安卓伪3D商品展示效果实现,模仿超真实,showFake3D

业务也不知道从哪儿找来了一个叫超真实的app,然后要模仿那种伪3D的商品效果展示。先看最后实现出来的效果。


业务给每个产品提供12张图,就是每30°提供一张,随着手指的滑动,不断切换图片,达到一种3D的展示效果。

已上传jitpack,可以直接导入

maven { url 'https://jitpack.io' }
implementation 'com.github.BaojunCZ:showFake3D:v1.1'

具体使用方法请看github项目地址

一共三个构造方法

完整构造

init(ArrayList pics, int moveOffset, int intertiaStart, int intertiaOffset, int intertiaEnd)

一参图片地址集合,图片是已从右往左为基准,二参是滑动整个宽度切换多少张图片,三四五参是惯性相关参数,分别是惯性开始速度,衰弱速度,结束速度

init(ArrayList pics, int moveOffset)
init(ArrayList pics)

具体实现

首先获取整个空间的宽段,然后进行分割我默认设置为15,也就是手指从最左侧滑动到最右侧,一共切换15张图片。

然后在onTouchEvent中处理图片切换。

 @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                leftScreen = false;
                start = event.getX();
                startTime = System.currentTimeMillis();
                break;
            case MotionEvent.ACTION_UP:
                float distance = event.getX() - start;
                distance = distance > 0 ? distance : -distance;
                long partTime = System.currentTimeMillis() - startTime;
                float v = distance / partTime;
                v = v > 0 ? v : -v;
                float StandardV = singleSpec / 60;
                Log.e(Tag, "distance=" + distance + ">>singleSpec=" + singleSpec + ">>v=" + v + ">>StandardV=" + StandardV);
                if (distance < singleSpec) {
                    leftScreen = false;
                } else if (v < StandardV) {
                    leftScreen = false;
                } else {
                    leftScreen = true;
                    Log.e(Tag, "ACTION_UP>>" + NowID);
                    intertia(NowID, intertiaStart);
                }
                break;
            case MotionEvent.ACTION_MOVE:
                int nowX = (int) event.getX();
                //计算移动距离
                float spec = nowX - start;
                int mo;
                String id;
                if (spec > 0) {
                    //从左向右滑
                    Log.e(Tag, "0  spec=" + spec + ">>singleSpec=" + singleSpec);
                    mo = (int) (spec / singleSpec);
                    if (mo > pics.size())
                        mo = mo - pics.size();
                    mo = pics.size() + 1 - mo;
                    positive = false;
                } else {
                    //从右向左滑
                    Log.e(Tag, "1  spec=" + spec + ">>singleSpec=" + singleSpec);
                    spec = 0 - spec;
                    mo = (int) (spec / singleSpec);
                    if (mo > pics.size())
                        mo = mo - pics.size();
                    positive = true;
                }
                if (mo != 0 && mo != 13) {
                    id = pics.get(mo - 1);
                    if (mo != NowID && !leftScreen) {
                        Log.e(Tag, "ACTION_MOVE>>" + NowID);
                        NowID = mo;
                        Uri uri = Uri.parse(id);
                        DraweeController controller = Fresco.newDraweeControllerBuilder()
                                .setUri(uri)
                                .setControllerListener(new BaseControllerListener())
                                .build();
                        iv.setController(controller);
                    }
                }
                break;
        }
        return true;
    }

计算手指移动距离,判断手指滑动的方向,从左到右和从右到左肯定是不同的,给的图是默认从右向左滑动的。

滑动超过12张图片的距离,就继续循环加载。

手指离开的时候需要设置一个惯性,本来一直考虑惯性衰减的问题,初速度是多少,加速度是多少,后来突然发现好像没必要这么复杂,惯性给一个固定的动画速度去衰减就行了。

启动惯性为了避免太假,所以要做两层判断,首先至少要滑动一个单位的距离,其次速度要大于60ms每张的速度才能触发惯性。

下面是惯性的代码

 //惯性
    private void intertia(int ID, final int time) {
        if (ID == 0)
            ID = pics.size();
        if (ID == pics.size() + 1)
            ID = 1;
        Log.e(Tag, "intertia>>ID=" + ID + ">>time=" + time + ">>leftScreen=" + leftScreen);
        if (leftScreen) {
            if (ID < pics.size() + 1) {
                Uri uri = Uri.parse(pics.get(ID - 1));
                final int finalID = ID;
                DraweeController controller = Fresco.newDraweeControllerBuilder()
                        .setUri(uri)
                        .setControllerListener(new BaseControllerListener() {

                            @Override
                            public void onSubmit(String id, Object callerContext) {
                                handler.postDelayed(new Runnable() {
                                    @Override
                                    public void run() {
                                        //惯性最后一定回到第一张图片
                                        if (time < intertiaEnd || finalID != 1) {
                                            if (positive)
                                                intertia(finalID + 1, time + intertiaOffset);
                                            else
                                                intertia(finalID - 1, time + intertiaOffset);
                                        }
                                    }
                                }, time);
                                Log.e(Tag, "onSubmit>>" + finalID);
                                super.onSubmit(id, callerContext);
                            }
                        })
                        .build();
                iv.setController(controller);
            }
        }
    }

很简单就是固定衰弱速度,到达设置的最慢速度就停止,同时为了好看一点,所以每次都让他回到第一张图再停止。

这样就基本完成了,可以看到我用的fresco来加载图片,其实最开始用的Glide,但是有个严重的问题,glide加载图片速度慢,导致图片切换一直在闪,所以就换了fresco,完美解决这个问题,Glide确实是轻量化,fresco太大但是功能更全面一点,加载速度很快,很流畅。但是第一次加载的时候也会闪,缓存结束后就ok了,很顺滑,所以在打开之后我先把图片全部加载一遍,作缓存。

//图片预加载图片,先将图片全部加载出来,解决滑动过程中白屏的问题
    private void setCache(final int ID) {
        if (ID < pics.size()) {
            Uri uri = Uri.parse(pics.get(ID));
            DraweeController controller = Fresco.newDraweeControllerBuilder()
                    .setUri(uri)
                    .setControllerListener(new BaseControllerListener() {
                        @Override
                        public void onFinalImageSet(String id, ImageInfo imageInfo, Animatable animatable) {
                            super.onFinalImageSet(id, imageInfo, animatable);
                            Log.e(Tag, "onFinalImageSet");
                            setCache(ID + 1);
                        }
                    })
                    .build();
            iv.setController(controller);
        } else {
            Uri uri = Uri.parse(pics.get(0));
            iv.setImageURI(uri);
            if (cacheListener != null)
                cacheListener.finish();
        }
    }
github 项目地址

你可能感兴趣的:(Android)