<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          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)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

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

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚洲视频观看免费 | 国产成人在线免费自拍 | 一区二区三区精品视频在线观看 | 日韩性做爰免费A片AA片 | 激情婷婷丁香五月天 |