Android超简单的3D旋转效果--图片轮播式

Android超简单的3D旋转效果--图片轮播式

这段时间项目中要实现一个3D旋转的效果图,并要下载zip图包下载进行解压至手机本地,然后再显示出3D效果来,如图:


gif5新文件 (2).gif

a.首先是判断手机SD卡中是否有下载解压好的图片文件夹,当然文件夹名字可以是服务器返回过来命名的,也可以是自己写死,这个自己去设定吧,只要能判断文件夹是否存在就行,不存在就去下载资源包,存在的话就去手机中SD卡搜索图片。下载的话我用的是retrofit2,大牛已经封装好了的(原谅我懒 哈哈),看代码


Android超简单的3D旋转效果--图片轮播式_第1张图片
QQ截图20180522144843.png

Android超简单的3D旋转效果--图片轮播式_第2张图片
QQ截图20180522144653.png

b.下载完了就解压到手机里面


Android超简单的3D旋转效果--图片轮播式_第3张图片
QQ截图20180522145233.png

这是解压的代码,由于解压也是异步进行的,所以当解压完成后可发送广播通知至activity中更新显示图片

/**
 * Created by Peter on 2018/5/9.
 * 解压zip文件
 */

public class ZipExtractorTask extends AsyncTask {
    private final String TAG = "ZipExtractorTask";
    private final File mInput;
    private final File mOutput;
    //  private final ProgressDialog mDialog;
    private int mProgress = 0;
    private final Context mContext;
    private boolean mReplaceAll;
    //0解压展示产品类型,1解压DIY中戒托类型(用于发送不同的广播)
    private int type;
    WebView mWebView;

    public ZipExtractorTask(String in, String out, Context context, boolean replaceAll, int type){
        super();
        this.type = type;
        mInput = new File(in);
        mOutput = new File(out);
        if(!mOutput.exists()){
            if(!mOutput.mkdirs()){
                Log.e(TAG, "Failed to make directories:"+mOutput.getAbsolutePath());
            }
        }

        mContext = context;
        mReplaceAll = replaceAll;
    }
    @Override
    protected Long doInBackground(Void... params) {
        // TODO Auto-generated method stub
        return unzip();
    }

    @Override
    protected void onPostExecute(Long result) {
        // TODO Auto-generated method stub
        //super.onPostExecute(result);

        if(isCancelled())
            return;
        //这里表示解压完成  可以进行显示WebView 发送广播 并更新保存的 时间
        //更新产品展示的广播
        if (type == 0){
            Intent intent1 = new Intent("com.sl.unzip");
            LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent1);
        }
        //解压DIY中戒托zip后的广播
        if (type == 1){
            Intent intent1 = new Intent("com.sl.unzip.jt");
            LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent1);
        }
    }
    @Override
    protected void onPreExecute() {
        // TODO Auto-generated method stub
        //super.onPreExecute();
    }
    @Override
    protected void onProgressUpdate(Integer... values) {
        // TODO Auto-generated method stub
    }
    private long unzip(){
        long extractedSize = 0L;
        Enumeration entries;
        ZipFile zip = null;
        try {
            zip = new ZipFile(mInput);
            long uncompressedSize = getOriginalSize(zip);
            publishProgress(0, (int) uncompressedSize);

            entries = (Enumeration) zip.entries();
            while(entries.hasMoreElements()){
                ZipEntry entry = entries.nextElement();
                if(entry.isDirectory()){
                    continue;
                }
                File destination = new File(mOutput, entry.getName());
                if(!destination.getParentFile().exists()){
                    Log.e(TAG, "make="+destination.getParentFile().getAbsolutePath());
                    destination.getParentFile().mkdirs();
                }
                if(destination.exists()&&mContext!=null&&!mReplaceAll){

                }
                ProgressReportingOutputStream outStream = new ProgressReportingOutputStream(destination);
                extractedSize+=copy(zip.getInputStream(entry),outStream);
                outStream.close();
            }
        } catch (ZipException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }finally{
            try {
                zip.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

        return extractedSize;
    }

    private long getOriginalSize(ZipFile file){
        Enumeration entries = (Enumeration) file.entries();
        long originalSize = 0l;
        while(entries.hasMoreElements()){
            ZipEntry entry = entries.nextElement();
            if(entry.getSize()>=0){
                originalSize+=entry.getSize();
            }
        }
        return originalSize;
    }

    private int copy(InputStream input, OutputStream output){
        byte[] buffer = new byte[1024*8];
        BufferedInputStream in = new BufferedInputStream(input, 1024*8);
        BufferedOutputStream out  = new BufferedOutputStream(output, 1024*8);
        int count =0,n=0;
        try {
            while((n=in.read(buffer, 0, 1024*8))!=-1){
                out.write(buffer, 0, n);
                count+=n;
            }
            out.flush();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }finally{
            try {
                out.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            try {
                in.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        return count;
    }

    private final class ProgressReportingOutputStream extends FileOutputStream {

        public ProgressReportingOutputStream(File file)
                throws FileNotFoundException {
            super(file);
            // TODO Auto-generated constructor stub
        }
        @Override
        public void write(byte[] buffer, int byteOffset, int byteCount)
                throws IOException {
            // TODO Auto-generated method stub
            super.write(buffer, byteOffset, byteCount);
            mProgress += byteCount;
            publishProgress(mProgress);
        }

    }
}

c.在activity界面初始化时候创建广播接收器

 /*
        接收解压完成的广播,更新图片显示
         */
        LocalBroadcastManager broadcastManager = LocalBroadcastManager.getInstance(this);
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction("com.sl.unzip");
        BroadcastReceiver mItemViewListClickReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                mSVProgressHUD.dismiss();
                show3Dphoto();
            }
        };
        broadcastManager.registerReceiver(mItemViewListClickReceiver, intentFilter);

d.接收到了图片解压完成的消息就显示出来吧

//获取sd卡中的3D图片
    private void show3Dphoto() {
        try {
            //根据路径查找手机SD卡中该路径下的所有图片
            List list = Utils.getImagePathFromSD(Constants.PICTHER_PRODUCT_PATH + "tupian");
            if (list.size() != 0) {
                //对图片路径列表进行排序,升序
                Collections.sort(list, Collator.getInstance(java.util.Locale.CHINA));
                //图片总数
                maxNum = list.size();
                //SD卡本地要展示的图片路径数组
                srcs = list.toArray(new String[list.size()]);
                //从本地取图片(在cdcard中获取)
                bitmap = Utils.getLoacalBitmap(srcs[scrNum]);
                mImg_produce.setImageBitmap(bitmap);
                //开始计时自动旋转轮播图片
                startTipsTimer();
            } else {
                //如果搜索到的图片列表大小为0则重新下载资源
                onStartDownload("http://adel.ifs.waltzcn.com/upload/201805/10/V27275.zip", "tupian", RotatingActivity.this);
                Log.i("TAG","未找到3D图片");
            }
        } catch (Exception e) {
            e.printStackTrace();
            if (mSVProgressHUD != null) {
                if (mSVProgressHUD.isShowing()) {
                    mSVProgressHUD.dismiss();
                }
            }
            Log.i("TAG","搜索图片失败");
        }
    }

这段代码主要就是搜索下载后的图片位置,添加并按名字排序到list中。排序主要是让播放更有顺序,因为这是轮播图片,肯定得看起来要自然,比如有80张图片,分别命名为a01、a02...a80,那么就按这个顺序播放下去。

e.自动轮播旋转图片,我这里就用Handler实现,一个Message用来通知是否自动开始轮播,一个Message用于自动轮播图片,这个要注意区分开

  //handler中接受定时消息来更新展示的3D图片
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_WHIRLIGIG:
                    modifySrcR();
                    mHandler.sendEmptyMessageDelayed(MSG_WHIRLIGIG, 100);
                    break;
                case MSG_START_WHIRLIGIG:
                    mHandler.sendEmptyMessageDelayed(MSG_WHIRLIGIG, 100);
                    break;
            }

        }
    };

    private Runnable tipsShowRunable = new Runnable() {

        @Override
        public void run() {
            mHandler.obtainMessage(MSG_START_WHIRLIGIG).sendToTarget();
        }
    };

    //重置计时
    public void resetTipsTimer() {
        if (mHandler.hasMessages(MSG_WHIRLIGIG)) {
            mHandler.removeMessages(MSG_WHIRLIGIG);
        }
        mHandler.removeCallbacks(tipsShowRunable);
        mHandler.postDelayed(tipsShowRunable, 2000);
    }

    /**
     * <无操作时开始计时>
     * <功能详细描述>
     *
     * @see [类、类#方法、类#成员]
     */
    public void startTipsTimer() {
        if (mHandler.hasMessages(MSG_WHIRLIGIG)) {
            mHandler.removeMessages(MSG_WHIRLIGIG);
        }
        mHandler.postDelayed(tipsShowRunable, 2000);
    }

    /**
     * <结束当前计时,重置计时>
     * <功能详细描述>
     *
     * @see [类、类#方法、类#成员]
     */
    public void endTipsTimer() {
        if (mHandler.hasMessages(MSG_WHIRLIGIG)) {
            mHandler.removeMessages(MSG_WHIRLIGIG);
        }
        mHandler.removeCallbacks(tipsShowRunable);
    }

f.根据图片位置显示出来

// 向右滑动修改资源
    private void modifySrcR() {
        if (srcs == null) {
            return;
        }
        if (scrNum > maxNum) {
            scrNum = 1;
        }
        if (scrNum > 0) {
            bitmap = Utils.getLoacalBitmap(srcs[scrNum - 1]); //从本地取图片(在cdcard中获取)
            mImg_produce.setImageBitmap(bitmap);
            scrNum++;
        }

    }

// 向左滑动修改资源
    private void modifySrcL() {
        if (srcs == null) {
            return;
        }
        if (scrNum <= 0) {
            scrNum = maxNum;
        }
        if (scrNum <= maxNum) {
            bitmap = Utils.getLoacalBitmap(srcs[scrNum - 1]); //从本地取图片(在cdcard中获取)
            mImg_produce.setImageBitmap(bitmap);
            scrNum--;
        }
    }

g.最后把图片可触摸左右旋转的事件监听加上

//3D图布局触摸监听
        mLayout_produce_show.setOnTouchListener(new View.OnTouchListener() {

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                resetTipsTimer();
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        startX = (int) event.getX();
                        break;

                    case MotionEvent.ACTION_MOVE:
                        currentX = (int) event.getX();
                        // 判断手势滑动方向,并切换图片,旋转的灵敏度可在这里调
                        if (currentX - startX > 3) {
                            for (int i = 0; i < (currentX - startX) / 3; i++) {
                                modifySrcR();
                            }
                        } else if (currentX - startX < -3) {
                            for (int i = 0; i < (currentX - startX) / -3; i++) {
                                modifySrcL();
                            }
                        }
                        // 重置起始位置
                        startX = (int) event.getX();

                        break;

                }

                return true;
            }

        });

左右旋转的触摸主要是根据手指触摸的位置坐标来结算的。当手指按下去的时候,就停止自动旋转,重置计时发送Message。

Over!实现这个功能就到这里了,还有一些细节我可能也没写清楚或者写得不适当,项目源码更详细,请指教。

附上源码

https://github.com/peterMa1999/3DRotatingDome

你可能感兴趣的:(Android超简单的3D旋转效果--图片轮播式)