1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        Android仿BiliBili 圖片3D切換效果

        共 5557字,需瀏覽 12分鐘

         ·

        2021-12-22 21:18

        ?作者?|??小白彡
        ?地址?|??https://www.jianshu.com/p/aa6770d29376

        最近刷B站看到一個(gè)比較有意思的圖片切換效果,在查看一個(gè)用戶發(fā)的圖片的時(shí)候是平滑過渡,如果下一張圖片是另一個(gè)用戶發(fā)的,則會(huì)觸發(fā)一個(gè)3D翻轉(zhuǎn)的效果,不止是圖片翻轉(zhuǎn),連帶里面的布局也會(huì)一起翻轉(zhuǎn)。


        話不多說、先上效果圖:




        先分析一下這個(gè)效果由哪幾部分組成:
        1.左右平移。
        2.上下翻轉(zhuǎn)。


        咦。。就這,就這

        真就這么簡單,先看第一個(gè)左右平移,這是一個(gè)很普通的ViewPage可以做到的效果,直接使用ViewPage就可以了,下面是使用ViewPage的代碼:

                ViewPager?vPage?=?findViewById(R.id.vpage);
        List mFragments = new ArrayList<>(); mFragments.add(R.mipmap.one); mFragments.add(R.mipmap.two); mFragments.add(R.mipmap.three); mFragments.add(R.mipmap.four); mFragments.add(R.mipmap.five);
        BliPageAdapter pageAdapter = new BliPageAdapter(this, mFragments); vPage.setAdapter(pageAdapter);


        這樣就可以實(shí)現(xiàn),左右平移的效果了(ViewPage的具體使用參考別的文章或官方文檔)


        那第二個(gè)翻轉(zhuǎn)該怎么實(shí)現(xiàn)呢,這才是最主要的,在效果圖中可以明顯看到3D的效果,那么肯定會(huì)用到Camera(非相機(jī))來做, 那么3D效果是作用在哪個(gè)控件上呢?如果作用到ViewPage上,那么看到的畫面就全部是傾斜的,如果作用到圖片上,那么只有】圖片傾斜,里面的內(nèi)容不會(huì)傾斜,所以判斷3D效果是作用在ViewPage的每一個(gè)子View上,這樣的話,看到的畫面是正的,但里面的內(nèi)容可傾斜可不傾斜,有了這個(gè)依據(jù),就可以開始實(shí)現(xiàn)了:


        1.給ViewPage設(shè)置PageTransformer用來監(jiān)聽滑動(dòng)的位置,因?yàn)?D效果會(huì)根據(jù)滑動(dòng)的位置來決定傾斜的角度。

         vPage.setPageTransformer(false, new BliPageTransformer());


        BliPageTransformer 實(shí)現(xiàn)了ViewPager.PageTransformer接口:

        public class BliPageTransformer implements ViewPager.PageTransformer {
        @Override public void transformPage(@NonNull View page, float position) {
        }}


        2.自定義自ViewPage子View,因?yàn)橐谧覸iew的dispatchDraw中對顯示的內(nèi)容做3D變換效果,我使用的是ConstraintLayout為最外層的容器,所以我自定義BliConstraintLayout繼承自ConstraintLayout, 重 ? ?寫dispatchDraw方法:

        public class BliConstraintLayout extends ConstraintLayout
           @Override    protected void dispatchDraw(Canvas canvas) {        //camera保存狀態(tài)        camera.save();        //camera設(shè)置繞Y軸旋轉(zhuǎn)角度        camera.rotateY(rotateY);        //將變換應(yīng)用到canvas上        camera.applyToCanvas(canvas);        camera.getMatrix(matrix);        if (!isLeftRotate){            //設(shè)置靠左進(jìn)行旋轉(zhuǎn)            matrix.preTranslate(- getWidth(), - getHeight() >> 1);            matrix.postTranslate(getWidth(), getHeight() >> 1);        } else {            //設(shè)置靠右進(jìn)行旋轉(zhuǎn)            matrix.preTranslate(0, - getHeight() >> 1);            matrix.postTranslate(0, getHeight() >> 1);        }        canvas.setMatrix(matrix);        //camera恢復(fù)狀態(tài)        camera.restore();        super.dispatchDraw(canvas);    }


        將ViewPage子View的xml文件外層容器替換成自定義的BliConstraintLayout

        核心代碼就在這里,Camera的用法可以參考其他博客或官方文檔,


        這里值得注意的是:


        1.camera需要保存和恢復(fù)狀態(tài),不然下一次繪制會(huì)拿到上一次改變過的狀態(tài)。


        2.使用matrix對變換矩陣進(jìn)行平移,因?yàn)槟J(rèn)變換都是針對坐標(biāo)點(diǎn)(0,0)的,而上面的3D效果,需要的是x軸 靠左和靠右, y軸居中.


        3.這些設(shè)置都要放在 super.dispatchDraw(canvas)之前,因?yàn)樵趕uper.dispatchDraw(canvas)調(diào)用后表示界面已經(jīng)開始繪制的,所以要在繪制之前給它設(shè)置成我們需要變換的樣子。


        在后頭看看BliPageTransformer中該怎么設(shè)置根據(jù)滑動(dòng)位置設(shè)置3D傾斜:

            @Override    public void transformPage(@NonNull View page, float position) {        BliConstraintLayout bliConstraintLayout = (BliConstraintLayout) page;        /**         * 傾斜度         */        int tiltDegree = 34;        float v = position * tiltDegree;        bliConstraintLayout.setRotateY(v);        if (position > 0){            bliConstraintLayout.setIsLeftRotate(true);        }else{            bliConstraintLayout.setIsLeftRotate(false);        }    }


        先看看方法里的參數(shù)
        1.page : 當(dāng)前子View
        2.position:先簡單了解一下position:position = -1 當(dāng)前顯示頁的上一頁。
        position = 0 ?當(dāng)前顯示頁。
        position = 1 當(dāng)前顯示頁的下一頁。


        那么在滑動(dòng)到下一頁的過程中position的變化就是:
        0 -> -1 ? : 對應(yīng)page為當(dāng)前顯示頁
        1 -> 0 ? ?:對應(yīng)page為當(dāng)前顯示頁的下一頁
        獲取到對應(yīng)View之后,再根據(jù)position計(jì)算對應(yīng)值:
        例如我設(shè)置的最大角度為34度, 那么在 1->0 的過程中,角度會(huì)由34 -> 0


        再判斷當(dāng)前View是當(dāng)前頁,還是下一頁,如果是當(dāng)前頁那么是相對布局的右邊傾斜,如果是當(dāng)前頁的下一頁那么應(yīng)該相對布局的左邊傾斜。


        再將計(jì)算出的值設(shè)置到我們自定義的BliConstraintLayout 中,重繪畫布。


        下面就可以運(yùn)行看看效果了:



        完美復(fù)刻,一鍵三連。


        下面貼一下關(guān)鍵點(diǎn)完整代碼:

        public class BliPageTransformer implements ViewPager.PageTransformer {
        @Override public void transformPage(@NonNull View page, float position) { BliConstraintLayout bliConstraintLayout = (BliConstraintLayout) page; /** * 傾斜度 */ int tiltDegree = 34; float v = position * tiltDegree; bliConstraintLayout.setRotateY(v); if (position > 0){ bliConstraintLayout.setIsLeftRotate(true); }else{ bliConstraintLayout.setIsLeftRotate(false); } }}

        public class BliConstraintLayout extends ConstraintLayout {
        private float rotateY = 0;
        private boolean isLeftRotate = true;
        private Matrix matrix = new Matrix();
        private Camera camera = new Camera();
        public BliConstraintLayout(@NonNull Context context) { super(context); }
        public BliConstraintLayout(@NonNull Context context, @Nullable AttributeSet attrs) { super(context, attrs); }
        public BliConstraintLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); }
        @Override protected void dispatchDraw(Canvas canvas) { //camera保存狀態(tài) camera.save(); //camera設(shè)置繞Y軸旋轉(zhuǎn)角度 camera.rotateY(rotateY); //將變換應(yīng)用到canvas上 camera.applyToCanvas(canvas); camera.getMatrix(matrix); if (!isLeftRotate){ //設(shè)置靠左進(jìn)行旋轉(zhuǎn) matrix.preTranslate(- getWidth(), - getHeight() >> 1); matrix.postTranslate(getWidth(), getHeight() >> 1); } else { //設(shè)置靠右進(jìn)行旋轉(zhuǎn) matrix.preTranslate(0, - getHeight() >> 1); matrix.postTranslate(0, getHeight() >> 1); } canvas.setMatrix(matrix); //camera恢復(fù)狀態(tài) camera.restore(); super.dispatchDraw(canvas); }
        public void setRotateY(float rotateY){ this.rotateY = rotateY; invalidate(); }
        public void setIsLeftRotate(boolean isLeft){ this.isLeftRotate = isLeft; }}


        想要源碼的童鞋【龍旋】公眾號(hào)后臺(tái)對話框回復(fù)關(guān)鍵字:3D切換,即可獲取下載鏈接。


        到這里就完成啦。

        瀏覽 94
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評論
        圖片
        表情
        推薦
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            亚洲视频在线播放 | 91蜜桃在线观看 | 暴躁老阿姨csgo图片高清 | 日韩视频久久 | 久久亚洲天堂网 | 免费欧美成人网站 | 草逼免费 | 亚洲一级A片毛毛aA片18 日韩无码中文字幕电影 | 里美尤利娅av一区二区 | 色欲九色 |