1. 程式人生 > >CoordinatorLayout+ViewPager+RecyclerView+自定義TabLayout佈局

CoordinatorLayout+ViewPager+RecyclerView+自定義TabLayout佈局

首先看看效果確定是不是你想要的:

如果效果是你想要的,那就接著往下看吧,我會一一介紹

(1)整體佈局:

佈局採用CoordinatorLayout+ViewPager+RecyclerView+自定義TabLayout實現,其中CoordinatorLayout為可上下滾動部分,ViewPager作為左右切換部分,tablayout作為標籤部分

先給出整體佈局的xml程式碼:

<android.support.design.widget.CoordinatorLayout
    android:layout_below="@+id/rel_home"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">
        <LinearLayout
            android:id="@+id/ll_banner"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="@dimen/dp12"
            android:layout_marginTop="@dimen/dp12"
            android:layout_marginRight="@dimen/dp12"
            app:layout_scrollFlags="scroll">

            <com.bigkoo.convenientbanner.ConvenientBanner
                android:id="@+id/convenient_banner"
                android:layout_width="match_parent"
                android:layout_height="@dimen/dp104"
                app:canLoop="true" />
        </LinearLayout>

        <android.support.design.widget.TabLayout
            android:id="@+id/tablayout"
            android:layout_width="match_parent"
            app:tabMaxWidth="@dimen/dp84"
            android:layout_height="@dimen/dp34"
            style="@style/aliwx_column_third_grade_with_click_style"
            app:tabPaddingEnd="0dp"
            app:tabPaddingStart="@dimen/dp0"
            android:layout_marginBottom="@dimen/dp12"
            android:layout_marginLeft="@dimen/dp12"
            android:layout_marginRight="@dimen/dp12"
            app:tabIndicatorHeight="0dp"
            android:layout_marginTop="@dimen/dp12"
            android:background="@drawable/iv_homefragment_label" />
        <!--</LinearLayout>-->
    </android.support.design.widget.AppBarLayout>
    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_marginLeft="@dimen/dp12"
        android:layout_marginRight="@dimen/dp12"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</android.support.design.widget.CoordinatorLayout>

佈局可見,CoordinatorLayout為滾動部分的整體佈局,甚至可看做行為可控制的ScrollView。

AppBarLayout作為懸浮視窗,什麼地方要懸浮就在此ViewGroup裡面寫佈局,而需要注意的是標紅部分app:layout_scrollFlags="scroll" 其中值有五種,具體差異可在這篇部落格中看到:https://www.jianshu.com/p/7caa5f4f49bd

此處的意思是其ChildView跟隨滾動事件移除螢幕外或移進。

app:layout_behavior="@string/appbar_scrolling_view_behavior"指定了ViewPager的滾動行為

當總體佈局寫成這樣就能基本實現框架了,接下來將各部分關聯起來

(2)ViewPager部分

viewpager這裡設計的是使用viewpager+fragment+recyclerview的方式是實現。

首先viewpager與tablayout繫結就很簡單的一句話:mTablayout.setupWithViewPager(mViewpager);

這樣的話。viewpager與tablayout的行為就實現了繫結,具體內容填充後面會介紹到

接著viewpager的部分,首先是viewpager的介面卡,此處使用FragmentPagerAdapter:

public class HomeViewPagerAdapter extends FragmentPagerAdapter {
    private List<HomeLabelsEntity.LabelsListBean> mLabelsListBeanList;
    private Context mContext;
    private List<ViewPagerFragment> mViewPagerFragments;
    FragmentManager fM;
    public HomeViewPagerAdapter(Context context,FragmentManager fm, List<HomeLabelsEntity.LabelsListBean> labelsListBeanList) {
        super(fm);
        fM = fm;
        mContext=context;
        mLabelsListBeanList=labelsListBeanList;
        mViewPagerFragments=new ArrayList<>();
    }

    @Override
    public Fragment getItem(int position) {
        ViewPagerFragment fragment = new ViewPagerFragment();
        Bundle bundle=new Bundle();
        bundle.putParcelable("data",mLabelsListBeanList.get(position));
        fragment.setArguments(bundle);
        return fragment;
    }
    public void notifData( List<HomeLabelsEntity.LabelsListBean> labelsListBeanList){
        mLabelsListBeanList=labelsListBeanList;
        notifyDataSetChanged();
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        ViewPagerFragment fragment = (ViewPagerFragment)super.instantiateItem(container,
                position);
        FragmentTransaction ft =fM.beginTransaction();
        String fragmentTag = fragment.getTag();
        ft.remove(fragment);
        fragment = new ViewPagerFragment();
        Bundle bundle=new Bundle();
        bundle.putParcelable("data",mLabelsListBeanList.get(position));
        fragment.setArguments(bundle);
        ft.add(container.getId(), fragment, fragmentTag);
        ft.attach(fragment);
        ft.commitAllowingStateLoss();
        return fragment;
    }



    @Override
    public int getCount() {
        return mLabelsListBeanList==null?0:mLabelsListBeanList.size();
    }

    @Override
    public int getItemPosition(Object object) {
        return POSITION_NONE;
    }
}

此處需要注意的就是兩個標紅方法的過載,getItem當Viewpager建立新介面的時候啟用,instantiateItem是當前介面渲染的時候使用,因為我寫的效果裡面需要切換城市,要重新整理Viewpager的狀態與資料,所以需要使用到instantiateItem,沒有這個需求的,getItem就能夠實現。此處使用的是傳參方式將資料傳遞到new出來的fragment。至於fragment部分就拿到資料,展示到recyclerview裡面,這裡就不做說明了。

(3)自定義tablayout

首先說明如果是純文字的tablayout只需要在viewpager的adapter中加上

  @Override
    public CharSequence getPageTitle(int position) {
        return tabStringList.get(position);
    }

tagStringList即為標籤文字集合

而如果採用自定義tablayout的話就需要在繫結之後進行佈局的渲染:

  //此處設定tablayout的內容
    for (int i = 0; i < mLabelsListBeanLists.size(); i++) {
        TabLayout.Tab tabAt = mHomePageChangeFragmentView.getTabLayout().getTabAt(i);
        View view= LayoutInflater.from(mContext).inflate(R.layout.item_recycler_home,null);
        if (i==mLabelsListBeanLists.size()-1){
            //最後一個不顯示箭頭
            view.findViewById(R.id.iv_cutline).setVisibility(View.GONE);
        }else{
            view.findViewById(R.id.iv_cutline).setVisibility(View.VISIBLE);
        }
        ((TextView)view.findViewById(R.id.tv_selected)).setText(mLabelsListBeanLists.get(i).getName());
        ((TextView)view.findViewById(R.id.tv_unselect)).setText(mLabelsListBeanLists.get(i).getName());
        if (i==0){
            //第一個預設設定被選中
            view.findViewById(R.id.llyout_selected).setVisibility(View.VISIBLE);
            view.findViewById(R.id.tv_unselect).setVisibility(View.INVISIBLE);
        }else{
            //其他設定為不選中狀態
            view.findViewById(R.id.llyout_selected).setVisibility(View.INVISIBLE);
            view.findViewById(R.id.tv_unselect).setVisibility(View.VISIBLE);
        }
        tabAt.setCustomView(view);
    }
    mHomePageChangeFragmentView.getTabLayout().addOnTabSelectedListener(this);
}

如程式碼所示,在tablayout繫結viewpager後,填充tablayout的佈局,並處理事件,處理事件採用監聽

@Override
public void onTabSelected(TabLayout.Tab tab) {
    if (tab!=null&&tab.getCustomView()!=null){
        tab.getCustomView().findViewById(R.id.llyout_selected).setVisibility(View.VISIBLE);
        tab.getCustomView().findViewById(R.id.tv_unselect).setVisibility(View.INVISIBLE);
    }
}

@Override
public void onTabUnselected(TabLayout.Tab tab) {
    if (tab!=null&&tab.getCustomView()!=null){
        tab.getCustomView().findViewById(R.id.llyout_selected).setVisibility(View.INVISIBLE);
        tab.getCustomView().findViewById(R.id.tv_unselect).setVisibility(View.VISIBLE);
    }
}

@Override
public void onTabReselected(TabLayout.Tab tab) {

}

而此處說一說自己踩的坑,首先tablayout的子佈局tabitem寬度,並不是根據你設定的寬度進行渲染的,它會在計算的時候進行重新計算,類似於LinearLayout子佈局中加android:layout_weight=""的效果,平分tablayout的寬度,想要自行設定寬度的話,在tablyout中設定屬性app:tabMaxWidth="@dimen/dp84"即可,然後tabitem自帶padding,所以發現自己佈局不對的話,設定其屬性

app:tabPaddingEnd="0dp"
app:tabPaddingStart="@dimen/dp0"

而想要設定沒有下劃線則設定,app:tabIndicatorHeight="0dp",此處不再多做贅述,因為屬性有點多,具體的根據想要實現的效果填充即可

本篇部落格到此結束,感謝觀看。

如有不對,請指正。

因為此效果是在專案中, 所以不太好傳原始碼,見諒!