1. 程式人生 > >安卓手把手教你實現RecycleView橫向和ViewPage的級聯滑動

安卓手把手教你實現RecycleView橫向和ViewPage的級聯滑動

之前做過一個horizontalScrollView+viewpage的級聯滑動,總結如下:

  1. 既然我們有了recycleView為何不用?
  2. recycleview可以在horizontalScrollView的基礎上增加多行,實現更多變更多定製化的效果。

我們都知道recycleview有三種效果:

  1. inearLayoutManager 線形管理器,支援橫向、縱向。
  2. GridLayoutManager 網格佈局管理器
  3. StaggeredGridLayoutManager 瀑布流式佈局管理器
  • 監聽recycleview的item點選事件
  • 監聽Viewpage的變化
  • recycleview實現橫向的gridview
  • 根據螢幕的寬度固定每個item的寬度
  • 滑動viewpage,recycleview跟著滑動到對應item
  • 點選recycleview的對應item,Viewpage跟著滑動到對應頁

    開始之前我們看一下效果:
    這裡寫圖片描述

看一下activity的佈局:

<com.example.recycleviewtest.PercentLinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
      xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <android.support.v4.view.ViewPager android:id="@+id/viewPager" android:layout_width="match_parent" android:layout_height="200dp"/> <com.example.recycleviewtest
.PercentLinearLayout android:id="@+id/linearLayout" android:layout_width="500dp" android:layout_height="200dp" app:layout_heightPercent="30%h" app:layout_widthPercent="100%w"> <android.support.v7.widget.RecyclerView android:id="@+id/id_recyclerview" android:divider="#ffff0000" android:layout_width="match_parent" android:layout_height="match_parent"/> </com.example.recycleviewtest.PercentLinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" > <ImageView android:id="@+id/imageview" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/ic_launcher" android:onClick="imageclick"/> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/ic_launcher" android:tint="#ffcdd2"/> </LinearLayout> </com.example.recycleviewtest.PercentLinearLayout>

這兒用到了百分比佈局,花2分鐘看我上一篇文章就秒懂。

看一下oncreate的程式碼

protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        imageView=(ImageView)findViewById(R.id.imageview);
        viewPager = (ViewPager) findViewById(R.id.viewPager);
        initData();
        mRecyclerView = (RecyclerView) findViewById(R.id.id_recyclerview);
      // 採用瀑布流並設定4行水平滾動
        StaggeredGridLayoutManager mStaggeredLayoutManager= new StaggeredGridLayoutManager(4,
                StaggeredGridLayoutManager.HORIZONTAL);
     mRecyclerView.setLayoutManager(mStaggeredLayoutManager);
        mRecyclerView.setAdapter(mAdapter = new HomeAdapter(MainActivity.this,mDatas));
        mRecyclerView.addItemDecoration(new DividerGridItemDecoration(this));//每一列新增分割線
        getDispaly(mRecyclerView);//獲取螢幕尺寸,目的是為了等分螢幕寬度


mmAdapter = new MyPagerAdapter(getSupportFragmentManager());
        viewPager.setAdapter(mmAdapter);
        viewPager.setOnPageChangeListener(new OnPageChangeListener() {
            @Override
            public void onPageSelected(int arg0) {      
                mRecyclerView.smoothScrollToPosition(arg0*4+3);
            }
            /** 此方法在滑動ViewPager的時候一直被呼叫,頁面在滑動過程中不停觸發該方法:position”按照api的解釋是“目前顯示在螢幕上的第一個頁面,只要positionOffset不為0,那麼他後面的頁面同樣是可見的
       第一頁~第二頁
       position = 0
       positionOffset  0.0 ~ 1.0
       第二頁~第一頁 
       position = 0
       positionOffset  1.0 ~ 0.0
       通過上面的結果,由於position的值在切換第一頁和第二頁的時候沒有變化,就可以同過position+1得到右邊的view,通過position拿到左邊的view 不論是滑動還是靜止,他表示的都是螢幕左邊的頁
       positionOffset           移量的百分比
       positionOffsetPixels     偏移量的數值*/
            @Override
            public void onPageScrolled(int position, float offest, int offestPixes) {
            }
     /**當頁面的滑動狀態改變時該方法會被觸發,頁面的滑動狀態有3個:0表示什麼都不做,1表示開始滑動,2表示結束滑動*/              
            @Override
            public void onPageScrollStateChanged(int arg0) {
            }
        });



        mAdapter.setOnItemClickerListener(new OnItemClickerListener() {

            @Override
            public void OnItemClicker(View view, int position) {
                // TODO Auto-generated method stub
                //只能去點選第一行的item,即4的倍數
                if(position%4==0){
                     viewPager.setCurrentItem(position/4, true);        //item從0-31,對應著viewpage的0-7頁,所以說一列item對應一頁
                    Toast.makeText(MainActivity.this, "你點選了"+position, Toast.LENGTH_SHORT).show();
                }
                else{return;}
            }
        });
    }
  • viewPager.setCurrentItem(position/4, true); 改變viewpage顯示頁面。
  • 計算偏移量這兒我用了一個小的投機取巧的方式( mRecyclerView.smoothScrollToPosition(arg0*4+3),我沒有使用計算得出的偏移量來設定滾動,而是根據這個方法的特性顯示出下一列的最後一個數字(本應該是第一個),這樣下一列就完全顯示出來從而達到可操控的滾動

  • 注:特性是指scrolltoposition這個方法會把你想要移動的item放到你能看見的地方,但是它不會管放到哪個位置,能讓你看見就行,一般在末尾。

:下面我舉例子解釋一下:
這裡寫圖片描述
比如我滑到了第六頁,準備顯示第六行,也即為數字為20的item,因為ScrollToPosition這個方法只會把20顯示出來,但是不管位置,所以它顯示出來的效果是這樣的:20跑到了19的下面,本應該是在17的右邊的。
這裡寫圖片描述

OK,那麼我的方法就是把23顯示到目前20的位置,這樣20就被頂到17的位置了,在視覺上就實現了列的左平移。

  • 第二:smoothScrollToPosition是從ScrollToPosition方法切換過來的,(如果不採用smoothScrollToPosition這個方法的話)不平滑滾動的話會出現兩個問題:
    一是檢視無法滾動到最左邊,二是當手動去滾動至最左邊的時候item的位置出現錯亂(雖然會自動恢復,但是有明顯的視覺延遲)見下圖樣式:這裡寫圖片描述
    可以看見,檢視亂了,但是鬆手的話它會自動恢復。

資料就是36個數字

    protected void initData()
    {
        mDatas = new ArrayList<String>();
        for (int i = 0; i < 36; i++)
        {
            mDatas.add("" +  i);
        }
    }
  • OK,我們再看一下recycleview的Adapter中bindviewholder的程式碼:
public void onBindViewHolder(final MyViewHolder holder, int position)
    {
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
                (int)(Constant.displayWidth*0.2), 
                (int)(Constant.recycleviewHeight*0.25));
        holder.itemView.setLayoutParams(params);
        holder.tv.setText(mDatas.get(position));
        if(onItemClickerListener!=null){
        //提供給activity的點選回撥
              holder.itemView.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    // TODO Auto-generated method stub
                    int p=holder.getLayoutPosition();
                    onItemClickerListener.OnItemClicker(holder.itemView, p);
                }
            });
        }
    }

Constant.displayWidth*0.2即為螢幕寬度的1/5,依據螢幕寬度每行5個item。

現在我們梳理一下文章都有哪些內容:
第一:從佈局中我們看出有一個viewpage和一個瀑布流的recycleview。
第二:設定為可滾動的recycleview。並限定每行5個item。
第三:在viewpage的onPageSelected方法裡面計算recycleview的滑動距離。
第四:在recycleview的item點選事件裡面設定viewpage的切換。
基本和我們前面確定的內容一致,寫到這兒只是讓大家瞭解一下基本思路就行了,知道聯動該怎麼去實現,對應什麼方法,歡迎多多交流。下面給出原始碼(eclipse版本的):
csdn下載地址:http://download.csdn.net/detail/u012534831/9539449
git地址:https://github.com/qht1003077897/recycleview-viewpage—-Scroll.git