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",此處不再多做贅述,因為屬性有點多,具體的根據想要實現的效果填充即可
本篇部落格到此結束,感謝觀看。
如有不對,請指正。
因為此效果是在專案中, 所以不太好傳原始碼,見諒!