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

效果如下:
Camera3DView.gif
思路是利用camera對兩張圖片分別做旋轉(zhuǎn)處理,代碼如下
/**
 * 使用camera實現(xiàn)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;
    //旋轉(zhuǎn)方向
    private int orientation = VERTICAL;
    //旋轉(zhuǎn)軸,所有旋轉(zhuǎn)操作無外乎兩個玩意,一個是旋轉(zhuǎn)軸,一個是旋轉(zhuǎn)角度
    //VERTICAL時使用rotateY,HORIZONTAL時使用rotateX
    private float rotatePivotX, rotatePivotY;
    //旋轉(zhuǎn)角度
    private float degress;
    //最大旋轉(zhuǎn)角度
    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);
        }
    }

    /**
     * 旋轉(zhuǎn)一面后,調(diào)用重置索引
     */
    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;//循環(huán)切換
        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方向旋轉(zhuǎn)軸隨degress的變大不斷下移
            rotatePivotX = degress / maxDegress * viewWidth;
        } else {
            //y方向旋轉(zhuǎn)軸隨degress的變大不斷右移
            rotatePivotY = degress / maxDegress * viewHeight;
        }

        //刷新
        invalidate();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        //VERTICAL時使用rotateY,HORIZONTAL時使用rotateX
        if (orientation == VERTICAL) {
            //如果是前進,則畫當前圖,后退則畫上一張圖,注釋用的是前進情況
            matrix.reset();
            camera.save();
            //旋轉(zhuǎn)角度 0 - -maxDegress 
            camera.rotateX(-degress);
            camera.getMatrix(matrix);
            camera.restore();

            //繞著圖片top旋轉(zhuǎn)
            matrix.preTranslate(-viewWidth / 2f, 0);
            //旋轉(zhuǎn)軸向下平移,則圖片也向下平移
            matrix.postTranslate(viewWidth / 2f, rotatePivotY);
            //如果是前進,則畫當前圖,后退則畫上一張圖,因為后退時,這里畫的是動畫下方出來的圖片,而下方的圖片是前一張圖
            canvas.drawBitmap(getBitmapScale(bitmapResourceIds.get(isForward ? currentIndex : preIndex), viewWidth, viewHeight),
                    matrix, mPaint);

            //在處理下一張圖片
            matrix.reset();
            camera.save();
            //旋轉(zhuǎn)角度 maxDegress - 0
            camera.rotateX(maxDegress - degress);
            camera.getMatrix(matrix);
            camera.restore();

            //繞著圖片bottom旋轉(zhuǎn)
            matrix.preTranslate(-viewWidth / 2f, -viewHeight);
            //旋轉(zhuǎn)軸向下平移,則圖片也向下平移
            matrix.postTranslate(viewWidth / 2f, rotatePivotY);
            //如果是前進,則畫下一張圖,后退則畫當前圖,后退時,這邊代碼畫的是動畫上方的圖片,上方的圖片是當前圖片
            canvas.drawBitmap(getBitmapScale(bitmapResourceIds.get(isForward ? nextIndex : currentIndex), viewWidth, viewHeight),
                    matrix, mPaint);
        } else {
            //如果是前進,則畫當前圖,后退則畫上一張圖,注釋用的是前進情況
            matrix.reset();
            camera.save();
            //旋轉(zhuǎn)角度 0 - maxDegress 
            camera.rotateY(degress);
            camera.getMatrix(matrix);
            camera.restore();

            //繞著圖片left旋轉(zhuǎn)
            matrix.preTranslate(0, -viewHeight / 2);
            //旋轉(zhuǎn)軸向右平移,則圖片也向右平移
            matrix.postTranslate(rotatePivotX, viewHeight / 2);
            //如果是前進,則畫當前圖,后退則畫上一張圖,因為后退時,這里畫的是動畫右方出來的圖片,而右方的圖片是前一張圖
            canvas.drawBitmap(getBitmapScale(bitmapResourceIds.get(isForward ? currentIndex : preIndex), viewWidth, viewHeight),
                    matrix, mPaint);

            //在處理下一張圖片
            matrix.reset();
            camera.save();
            //旋轉(zhuǎn)角度 -maxDegress - 0
            camera.rotateY(-maxDegress + degress);
            camera.getMatrix(matrix);
            camera.restore();

            //繞著圖片right旋轉(zhuǎn)
            matrix.preTranslate(-viewWidth, -viewHeight / 2f);
            //旋轉(zhuǎn)軸向右平移,則圖片也向右平移
            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
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 小時候,我家的白菜窖就在倉庫的天井里,挖一個兩米深左右的長方形深坑,上面搭些不粗不細的木棍,木棍上面鋪上玉米秸,玉...
    秋風秋月閱讀 1,828評論 22 21
  • 今天小米請我去吃烤肉,這種事兒,我當然赴約了。 五花肉滋滋作響,我生怕肉被烤糊了,把全部心思都放在烤肉上。把肉一塊...
    肖幕閱讀 300評論 0 0
  • 物質(zhì)的組成、性質(zhì)及分類
    修飛機的Pilot閱讀 450評論 0 4
  • 文/安瑞娜 最近報名了一個婚禮主持培訓(xùn)班,除了基本的普通話標準以外,練聲發(fā)音繞口令都得不斷加強練習(xí),比如: ...
    安瑞娜閱讀 909評論 0 1
  • 只因在人群中多看了你一眼,再也無法忘卻你容顏。 男子不知何時聽到的歌曲,也不記得是什么歌名,不記得是誰唱的,甚至于...
    凱爾特平閱讀 854評論 0 4

友情鏈接更多精彩內(nèi)容