美文网首页
Android超简单的3D旋转效果--图片轮播式

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

作者: ma漂泊者 | 来源:发表于2018-05-22 16:17 被阅读0次

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

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


    gif5新文件 (2).gif

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


    QQ截图20180522144843.png
    QQ截图20180522144653.png

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


    QQ截图20180522145233.png

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

    /**
     * Created by Peter on 2018/5/9.
     * 解压zip文件
     */
    
    public class ZipExtractorTask extends AsyncTask<Void, Integer, Long> {
        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<ZipEntry> entries;
            ZipFile zip = null;
            try {
                zip = new ZipFile(mInput);
                long uncompressedSize = getOriginalSize(zip);
                publishProgress(0, (int) uncompressedSize);
    
                entries = (Enumeration<ZipEntry>) 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<ZipEntry> entries = (Enumeration<ZipEntry>) 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<String> 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旋转效果--图片轮播式

          本文链接:https://www.haomeiwen.com/subject/ahahjftx.html