前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android--利用camera打造3D效果

Android--利用camera打造3D效果

作者头像
aruba
发布2020-07-02 15:30:59
9310
发布2020-07-02 15:30:59
举报
文章被收录于专栏:android技术android技术
效果如下:

Camera3DView.gif

思路是利用camera对两张图片分别做旋转处理,代码如下
代码语言:javascript
复制
/**
 * 使用camera实现3d效果的自定义控件
 */
public class Camera3DView extends View {
    //存放bitmap资源文件id的集合
    private List<Integer> bitmapResourceIds;
    //用于3d变换
    private Camera camera;
    //用于变换的矩阵
    private Matrix matrix;
    //view的宽高
    private float viewWidth, viewHeight;
    //是否绘制完毕
    private boolean isDrawFinished = false;
    public static final int VERTICAL = LinearLayout.VERTICAL;
    public static final int HORIZONTAL = LinearLayout.HORIZONTAL;
    //旋转方向
    private int orientation = VERTICAL;
    //旋转轴,所有旋转操作无外乎两个玩意,一个是旋转轴,一个是旋转角度
    //VERTICAL时使用rotateY,HORIZONTAL时使用rotateX
    private float rotatePivotX, rotatePivotY;
    //旋转角度
    private float degress;
    //最大旋转角度
    private float maxDegress = 90;
    //当前图片索引
    private int currentIndex;
    //下个显示图片索引
    private int nextIndex;
    //上个显示图片索引
    private int preIndex;
    private Paint mPaint;
    //是否前进
    private boolean isForward = true;
    private ValueAnimator valueAnimator;
    private boolean isAnimatiorRunning;

    public Camera3DView(Context context) {
        this(context, null);
    }

    public Camera3DView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public Camera3DView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        bitmapResourceIds = new ArrayList<>();
        camera = new Camera();
        matrix = new Matrix();
        mPaint = new Paint();

        isDrawFinished = false;
    }

    /**
     * 添加图片
     *
     * @param resId
     */
    public void addResId(int resId) {
        bitmapResourceIds.add(resId);
        if (isDrawFinished) {
            invalidate();
        }
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        viewWidth = w;
        viewHeight = h;
        isDrawFinished = true;
        initBitmaps();
        resetIndex();
    }

    private void initBitmaps() {
        for (int i = 0; i < bitmapResourceIds.size(); i++) {
            int resID = bitmapResourceIds.get(i);
            getBitmapScale(resID, viewWidth, viewHeight);
        }
    }

    /**
     * 旋转一面后,调用重置索引
     */
    public void resetIndex() {
        int listSize = bitmapResourceIds.size();
        if (isForward) {//前进或者向下
            currentIndex++;
            if (currentIndex > listSize - 1) {
                currentIndex = 0;
            }
        } else {
            currentIndex--;
            if (currentIndex < 0)
                currentIndex = listSize - 1;
        }

        nextIndex = currentIndex + 1;
        preIndex = currentIndex - 1;
        if (nextIndex > listSize - 1)
            nextIndex = 0;//循环切换
        if (preIndex < 0)
            preIndex = listSize - 1;

        this.degress = 0;

        rotatePivotX = 0;
        rotatePivotY = 0;

        isForward = true;

        invalidate();
    }

    public void setDegress(int degress) {
        this.degress = degress;

        //VERTICAL时使用rotateY,HORIZONTAL时使用rotateX
        if (orientation == HORIZONTAL) {
            //x方向旋转轴随degress的变大不断下移
            rotatePivotX = degress / maxDegress * viewWidth;
        } else {
            //y方向旋转轴随degress的变大不断右移
            rotatePivotY = degress / maxDegress * viewHeight;
        }

        //刷新
        invalidate();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        //VERTICAL时使用rotateY,HORIZONTAL时使用rotateX
        if (orientation == VERTICAL) {
            //如果是前进,则画当前图,后退则画上一张图,注释用的是前进情况
            matrix.reset();
            camera.save();
            //旋转角度 0 - -maxDegress 
            camera.rotateX(-degress);
            camera.getMatrix(matrix);
            camera.restore();

            //绕着图片top旋转
            matrix.preTranslate(-viewWidth / 2f, 0);
            //旋转轴向下平移,则图片也向下平移
            matrix.postTranslate(viewWidth / 2f, rotatePivotY);
            //如果是前进,则画当前图,后退则画上一张图,因为后退时,这里画的是动画下方出来的图片,而下方的图片是前一张图
            canvas.drawBitmap(getBitmapScale(bitmapResourceIds.get(isForward ? currentIndex : preIndex), viewWidth, viewHeight),
                    matrix, mPaint);

            //在处理下一张图片
            matrix.reset();
            camera.save();
            //旋转角度 maxDegress - 0
            camera.rotateX(maxDegress - degress);
            camera.getMatrix(matrix);
            camera.restore();

            //绕着图片bottom旋转
            matrix.preTranslate(-viewWidth / 2f, -viewHeight);
            //旋转轴向下平移,则图片也向下平移
            matrix.postTranslate(viewWidth / 2f, rotatePivotY);
            //如果是前进,则画下一张图,后退则画当前图,后退时,这边代码画的是动画上方的图片,上方的图片是当前图片
            canvas.drawBitmap(getBitmapScale(bitmapResourceIds.get(isForward ? nextIndex : currentIndex), viewWidth, viewHeight),
                    matrix, mPaint);
        } else {
            //如果是前进,则画当前图,后退则画上一张图,注释用的是前进情况
            matrix.reset();
            camera.save();
            //旋转角度 0 - maxDegress 
            camera.rotateY(degress);
            camera.getMatrix(matrix);
            camera.restore();

            //绕着图片left旋转
            matrix.preTranslate(0, -viewHeight / 2);
            //旋转轴向右平移,则图片也向右平移
            matrix.postTranslate(rotatePivotX, viewHeight / 2);
            //如果是前进,则画当前图,后退则画上一张图,因为后退时,这里画的是动画右方出来的图片,而右方的图片是前一张图
            canvas.drawBitmap(getBitmapScale(bitmapResourceIds.get(isForward ? currentIndex : preIndex), viewWidth, viewHeight),
                    matrix, mPaint);

            //在处理下一张图片
            matrix.reset();
            camera.save();
            //旋转角度 -maxDegress - 0
            camera.rotateY(-maxDegress + degress);
            camera.getMatrix(matrix);
            camera.restore();

            //绕着图片right旋转
            matrix.preTranslate(-viewWidth, -viewHeight / 2f);
            //旋转轴向右平移,则图片也向右平移
            matrix.postTranslate(rotatePivotX, viewHeight / 2f);
            //如果是前进,则画下一张图,后退则画当前图,后退时,这边代码画的是动画左方的图片,左方的图片是当前图片
            canvas.drawBitmap(getBitmapScale(bitmapResourceIds.get(isForward ? nextIndex : currentIndex), viewWidth, viewHeight),
                    matrix, mPaint);
        }

    }

    /**
     * 获取缩放图片
     *
     * @param resId
     * @param width
     * @param height
     * @return
     */
    private Bitmap getBitmapScale(int resId, float width, float height) {
        if (ImageCache.getInstance().getBitmapFromMemCache(String.valueOf(resId)) != null) {
            return ImageCache.getInstance().getBitmapFromMemCache(String.valueOf(resId));
        }
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), resId);

        Bitmap bitmapDst = Bitmap.createScaledBitmap(bitmap, (int) width, (int) height, false);
        bitmap.recycle();

        ImageCache.getInstance().addBitmapToMemoryCache(String.valueOf(resId)
                , bitmapDst);
        return bitmapDst;
    }

    public void next() {
        createAnimator();

        if (!isAnimatiorRunning) {
            isForward = true;
            isAnimatiorRunning = true;
            valueAnimator.start();
        }
    }

    public void pre() {
        createAnimator();

        if (!isAnimatiorRunning) {
            isForward = false;
            isAnimatiorRunning = true;
            valueAnimator.reverse();
        }
    }

    private void createAnimator() {
        if (valueAnimator == null) {
            valueAnimator = ValueAnimator.ofFloat(0, 1f);
            valueAnimator.setDuration(500);
            valueAnimator.setInterpolator(new LinearInterpolator());
            valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    degress = maxDegress * animation.getAnimatedFraction();
                    setDegress((int) degress);
                }
            });
            valueAnimator.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    resetIndex();
                    isAnimatiorRunning = false;
                }
            });
        }
    }

    public void setOrientation(int orientation) {
        this.orientation = orientation;
    }
}
项目地址:https://gitee.com/aruba/CameraApplication.git
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 效果如下:
  • 思路是利用camera对两张图片分别做旋转处理,代码如下
  • 项目地址:https://gitee.com/aruba/CameraApplication.git
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档