Android畫廊效果


1.概述

  

  最近項目中需要類似上圖這種可滾動、點擊選中居中的畫廊效果,於是萌生了一些想法.最開始想到的這種橫向滾動的效果可以用HorizontalScrollView來實現(需要考慮item復用);當然也可以使ViewPager,這需要解決一屏多顯和點擊事件的問題;再有,就是通過RecyclerView線性橫向布局來實現,但是需要處理滾動選中.暫時,就這三種方式了,無一例外,它們都需要選中后居中放大,更甚者,需要添加圖片的倒影效果.

2.ViewPager和RecyclerView實現

2.1 ViewPager實現方式

  淘來的ViewPager一屏多顯圖

原理就一個屬性android:clipChildren="false",該屬性的意思就是在子View進行繪制時不要去裁切它們的顯示范圍;在布局文件中

<RelativeLayout  
        android:layout_width="match_parent" 
        android:layout_height="160dp"
        android:clipChildren="false" 
        android:layout_centerInParent="true" 
        android:background="#aadc71ff" > 
    <android.support.v4.view.ViewPager 
        android:id="@+id/id_viewpager" 
        android:layout_width="match_parent"         
        android:layout_marginLeft="60dp"
        android:layout_marginRight="60dp" 
        android:clipChildren="false" 
        android:layout_height="120dp" 
        android:layout_gravity="center" />
</RelativeLayout>

給ViewPager及其控件都設置了android:clipChildren="false"

ViewPager的寬度是match_parent,左后個設置了60dp的邊距,就是為了顯示出左右部分的Page.

在Adapter中

 //設置Page間間距 mViewPager.setPageMargin(20);

以及

//設置緩存的頁面數量 mViewPager.setOffscreenPageLimit(3);

這樣,一屏多顯就搞定了;接下來就是設置滾動切換動畫了.思路不外乎:寫個類集成ViewPager.PageTransformer;重寫transformPage方法.上代碼:

public class ScaleAlphaPageTransformer implements ViewPager.PageTransformer{
    public static final float MAX_SCALE = 1.0f;
    public static final float MIN_SCALE = 0.6f;
    public static final float MAX_ALPHA = 1.0f;
    public static final float MIN_ALPHA = 0.5f;
    
    private boolean alpha = true;
    private boolean scale = true;

    @Override
    public void transformPage(View page, float position) {

        if (position < -1) {
            position = -1;
        } else if (position > 1) {
            position = 1;
        }

        float tempScale = position < 0 ? 1 + position : 1 - position;

        if(scale){
            float slope = (MAX_SCALE - MIN_SCALE) / 1;
            //一個公式
            float scaleValue = MIN_SCALE + tempScale * slope;
            page.setScaleX(scaleValue);
            page.setScaleY(scaleValue);
        }
        if(alpha){
            //模糊
            float alope = (MAX_ALPHA - MIN_ALPHA) / 1;
            float alphaValue = MIN_ALPHA + tempScale * alope;
            page.setAlpha(alphaValue);
        }
    }
    
    /***
     * 設置是否模糊和改變大小
     * @param alpha
     * @param scale
     */
    public void setType(boolean alpha, boolean scale){
        this.alpha = alpha;
        this.scale = scale;
    }
}

於是在Activity中,有

 ScaleAlphaPageTransformer mScaleAlphaPageTransformer = new ScaleAlphaPageTransformer();
        mScaleAlphaPageTransformer.setType(true, true);
        viewPager.setPageTransformer(true, mScaleAlphaPageTransformer);
        viewPager.setCurrentItem(0);
        viewPager.setOnPageChangeListener(new OnPageChangeListener() {

            @Override
            public void onPageSelected(int arg0) {
                Log.e("----------->選中", "" + arg0);
            }

            @Override
            public void onPageScrolled(int arg0, float arg1, int arg2) {
                if (vpLayout != null) {
                    vpLayout.invalidate();
                }

            }

            @Override
            public void onPageScrollStateChanged(int arg0) {
            }
        });

        vpLayout.setOnTouchListener(new OnTouchListener() {

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                v.performClick();
                return viewPager.dispatchTouchEvent(event);
            }
        });

這樣的話,切換縮放的動畫也解決了;

2.2 RecyclerView實現方式

  淘來的一張圖,效果不錯,要實現這種效果,需要搞定滑動結束后某個圖片居中和滾動縮放;分兩步走,

  ①滑動結束后停留在某張圖片居中

  Support RecyclerView 24.2.0中增加一個非常重要的類SnapHelper,他的作用是讓RecyclerView滑動視圖后使停止位置正好停在某頁的正中間。使用方式很簡單
重點在於new LinearSnapHelper().attachToRecyclerView(recyclerView);

LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, false); recyclerView.setLayoutManager(linearLayoutManager);
new LinearSnapHelper().attachToRecyclerView(recyclerView);

  這樣就解決了第一個問題.

  ②滑動縮放

  不難看出,RecyclerView的滑動縮放必須要監聽RecyclerView的滑動;

mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); // dx>0則表示右滑, dx<0表示左滑, dy<0表示上滑, dy>0表示下滑 mCurrentItemOffset += dx; computeCurrentItemPos(); onScrolledChangedCallback(); } });

mCurrentItemOffset為滑動總距離,Card每頁滑動的距離是固定的,根據這個可以計算出當前顯示的位置。縮放看onScrolledChangedCallback這個函數,有了滑動位置就能實時計算滑動某頁的百分比
float percent = (float) Math.max(Math.abs(offset) * 1.0 / mOnePageWidth, 0.0001);

得到百分比, 再獲取當前位置相鄰的視圖調用setScaleY函數實現縮放

/** * RecyclerView位移事件監聽, view大小隨位移事件變化 */ private void onScrolledChangedCallback() { int offset = mCurrentItemOffset - mCurrentItemPos * mOnePageWidth; float percent = (float) Math.max(Math.abs(offset) * 1.0 / mOnePageWidth, 0.0001); View leftView = null; View currentView; View rightView = null; if (mCurrentItemPos > 0) { leftView = mRecyclerView.getLayoutManager().findViewByPosition(mCurrentItemPos - 1); } currentView = mRecyclerView.getLayoutManager().findViewByPosition(mCurrentItemPos); if (mCurrentItemPos < mRecyclerView.getAdapter().getItemCount() - 1) { rightView = mRecyclerView.getLayoutManager().findViewByPosition(mCurrentItemPos + 1); } if (leftView != null) { // y = (1 - mScale)x + mScale leftView.setScaleY((1 - mScale) * percent + mScale); } if (currentView != null) { // y = (mScale - 1)x + 1 currentView.setScaleY((mScale - 1) * percent + 1); } if (rightView != null) { // y = (1 - mScale)x + mScale rightView.setScaleY((1 - mScale) * percent + mScale); } }//這樣縮放也搞定了.

3.小結  

  目前,個人比較傾向於第二種方式,item復用問題RecyclerView已經幫我們解決了,而且圖片的網絡加載是一個耗時的操作,利用RecyclerView可以很方便的完成,而ViewPager的方式點擊事件是不好實現的,尤其在一屏多顯的情景下,item條目復用也會有問題.實際使用可能還會有一些問題,先寫到這,后面發現了的話,再來補充.



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM