TabLayout自定义Tab实现不同的圆角效果
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了TabLayout自定义Tab实现不同的圆角效果相关的知识,希望对你有一定的参考价值。
参考技术A 开发过程中经常会遇到Tab左右或中间的圆角不一样,如下图所示:根据上图发现两个Tab圆角不同,且不对称,无法通过设置tabBackground属性来实现不同的圆角,解决方案是采用自定义TabView的方法。具体实现方案如下:
TabLayout属性设置:
tabPadding和padding全部设置为0,由自定义TabView来设置相应的padding,tabIndicatorHeight设置为0,tabSelectedTextColor设置选中Tab文字颜色,tabTextAppearance设置Tab未选中文字颜色。
左边Tab选中背景bg_tab_left_select.xml:
左边Tab未选中背景bg_tab_left_unselect.xml:
右边Tab选中背景bg_tab_right_select.xml:
右边Tab未选中背景bg_tab_right_unselect.xml:
左边Tab背景选择器tab_left_selector.xml:
右边Tab背景选择器tab_right_selector.xml:
左边TabView自定义布局文件:
右边TabView自定义布局文件:
注意:
自定义View的高度要保持与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",此处不再多做赘述,因为属性有点多,具体的根据想要实现的效果填充即可
本篇博客到此结束,感谢观看。
如有不对,请指正。
因为此效果是在项目中, 所以不太好传源码,见谅!
以上是关于TabLayout自定义Tab实现不同的圆角效果的主要内容,如果未能解决你的问题,请参考以下文章
自适应 Tab 宽度可以滑动文字逐渐变色的 TabLayout(仿今日头条顶部导航)
TabLayout +ViewPager 自定义Tab的UI