FlowLayout 继承于 ViewGroup ,可以快速帮您实现 Tablayout 以及 Label 标签,内含多种效果,帮您快速实现 APP UI 功能,让您专注代码架构,告别繁琐UI。
代码工程:实现一个可定制化的FlowLayout
如果你也想自己写一个,可以参考以下几篇文章
实现一个可定制化的TabFlowLayout(一) -- 测量与布局
实现一个可定制化的TabFlowLayout(二) -- 实现滚动和平滑过渡
实现一个可定制化的TabFlowLayout(三) -- 动态数据添加与常用接口封装
实现一个可定制化的TabFlowLayout(四) -- 与ViewPager 结合,实现炫酷效果
allprojects { repositories { ... maven { url 'https://jitpack.io' } } } 复制代码
implementation 'com.github.LillteZheng:FlowHelper:v1.16' 复制代码
首先,就是 TabFlowLayout 的效果,它的布局支持横竖两种方式,首先先看支持的效果:
结合ViewPager | 没有结合ViewPager |
---|---|
TabFlowLayout竖直,RecyclerView联动效果 |
---|
除了 TabFlowLayout,还有 LAbelFlowLayout 标签式布局,支持自动换行
LAbelFlowLayout 标签式布局 |
---|
可以看到 目前 TabFlowLayout 支持以下效果:
主要是 TabFlowLayout 和 LabelFlowLayout 这两个控件
首先是在 xml 中,填写 TabFlowLayout 控件,它支持横竖排列,默认横向,可以使用tab_orientation = "vertical" 更换成竖直排列,一个不带效果,支持横向的 TabFlowLayout 如下:
XML
<com.zhengsr.tablib.view.flow.TabFlowLayout android:id="@+id/resflow" android:layout_width="wrap_content" android:layout_marginTop="5dp" android:background="#6D8FB0" android:layout_height="wrap_content"/> 复制代码
比如要加矩形,三角形,可以使用 app:tab_type 这个属性,比如一个矩形:
<com.zhengsr.tablib.view.flow.TabFlowLayout android:id="@+id/rectflow" android:layout_width="wrap_content" android:layout_marginTop="5dp" app:tab_type="rect" app:tab_color="@color/colorPrimary" app:tab_height="3dp" app:tab_width="20dp" app:tab_margin_b="3dp" android:background="@color/black_ff_bg" app:tab_scale_factor="1.2" app:tab_item_autoScale="true" android:layout_height="wrap_content"/> 复制代码
这里解释一下关键几个自定参数
上面几个为基础属性,这里填写 tri 也可以同样设置。当 type 为 round 或者 res 时,width 和 height 则可以不填,因为要根据控件本书去适配大小。
其他说明,可以参看下面的自定义属性说明。
Java
那么,在 xml 写好了,接着,就是在 Activity 中,这样写:
private void rectFlow(){ TabFlowLayout flowLayout = findViewById(R.id.rectflow); //设置数据,这里以 setAdapter 的形式 flowLayout.setAdapter(new TabFlowAdapter<String>(R.layout.item_msg,mTitle) { @Override public void onItemSelectState(View view, boolean isSelected) { super.onItemSelectState(view, isSelected); //选中时,可以改变不同颜色,如果你的background 为 selector,可以不写这个 if (isSelected){ setTextColor(view,R.id.item_text,Color.WHITE); }else{ setTextColor(view,R.id.item_text,getResources().getColor(R.color.unselect)); } } @Override public void bindView(View view, String data, int position) { //绑定数据 setText(view,R.id.item_text,data) .setTextColor(view,R.id.item_text,getResources().getColor(R.color.unselect)); if (position == 0){ setVisible(view,R.id.item_msg,true); } } }); } 复制代码
可以看到,只需要设置 adapter 就行了,需要注意的是你要传入子控件的 layout,这样方便你自定义你的布局,比如一个TextView 和一个红点点。具体细节,可以参看这个:
实现一个可定制化的TabFlowLayout(三) -- 动态数据添加与常用接口封装
如果你需要使用颜色渐变的效果,TextView 换成 TabColorTextView 就可以了,比如:
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto"> <com.zhengsr.tablib.view.TabColorTextView android:id="@+id/item_text" android:layout_width="wrap_content" app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" tools:text="测试" android:paddingTop="6dp" android:paddingBottom="6dp" android:paddingStart="12dp" android:paddingEnd="12dp" android:textSize="14sp" app:colortext_default_color="@color/unselect" app:colortext_change_color="@color/colorAccent" android:gravity="center" android:layout_height="wrap_content"/> <TextView android:id="@+id/item_msg" android:layout_width="5dp" android:layout_height="5dp" android:gravity="center" android:textSize="8dp" android:background="@drawable/shape_red_radius" app:layout_constraintTop_toTopOf="parent" app:layout_constraintEnd_toEndOf="parent" android:layout_margin="5dp" android:visibility="gone" /> </android.support.constraint.ConstraintLayout> 复制代码
结合 ViewPager 非常简单,如下:
flowLayout.setViewPager(...) 即可. 复制代码
为了避免卡顿,当viewpager结合fragment时,可以有以下优化手段:
**如果您觉得viewpager切换太快,可以使用 ViewPagerHelperUtils.initSwitchTime(getContext(), viewPager, 600) 改变滚动速度 **
它有几个方法,参考这个解释就可以了。
/** * 配置viewpager * @param viewPager * @param textId view 中 textview 的id * @param selectedIndex 默认选中的item,初始值为0,也可以从第二页或者其他 位置 * @param unselectedColor 没有选中的颜色 TabColorTextView 中失效 * @param selectedColor 选中的颜色 TabColorTextView 中失效 */ public void setViewPager(ViewPager viewPager, int textId, int selectedIndex, int unselectedColor, int selectedColor) { } 复制代码
可能你不想在 xml 直接定死,那么可以直接使用 TabBean 去配置,比如使用 tab_type=res, 你的drawable 使用 shape 当移动背景的配置如下:
private void resFlow(){ final TabFlowLayout flowLayout = findViewById(R.id.resflow); flowLayout.setViewPager(mViewPager); /** * 配置自定义属性 */ TabBean bean = new TabBean(); bean.tabType = FlowConstants.RES; bean.tabItemRes = R.drawable.shape_round; //点击的动画执行时间 ms bean.tabClickAnimTime = 300; bean.tabMarginLeft = 5; bean.tabMarginTop = 12; bean.tabMarginRight = 5; bean.tabMarginBottom = 10; //设置进去即可 flowLayout.setTabBean(bean); flowLayout.setAdapter(new TabFlowAdapter<String>(R.layout.item_msg,mTitle) { @Override public void bindView(View view, String data, int position) { setText(view,R.id.item_text,data); } @Override public void onItemClick(View view, String data, int position) { super.onItemClick(view, data, position); mViewPager.setCurrentItem(position); } }); } 复制代码
如果上面没有你想要的怎么办?,那么项目也支持用户自定义,比如自定义一个白色圆点效果,只需要继承 BaseAction 即可:
/** * 绘制一个圆的指示器 */ class CircleAction extends BaseAction{ private static final String TAG = "CircleAction"; @Override public void config(TabFlowLayout parentView) { super.config(parentView); View child = parentView.getChildAt(0); if (child != null) { float l = parentView.getPaddingLeft() + child.getMeasuredWidth()/2; float t = parentView.getPaddingTop() + child.getMeasuredHeight() - mTabHeight/2 -mMarginBottom; float r = mTabWidth + l; float b = child.getMeasuredHeight() - mMarginBottom; mTabRect.set(l,t,r,b); } } @Override protected void valueChange(TabValue value) { super.valueChange(value); /** * value 子控件在滚动时的 left 和 right,可以理解为偏移量 * TabRect 为控件移动时的局域。 */ //由于自定义的,都是从left 开始算起的,所以这里还需要加上圆的半径 mTabRect.left = value.left + mTabWidth/2; } @Override public void draw(Canvas canvas) { canvas.drawCircle(mRect.left,mRect.top,mTabWidth/2,mPaint); } } 复制代码
通过重写 valueChange 拿到移动偏移量,然后通过 flowLayout.setAction(new CircleAction()) 即可。如果是竖直方向,拿到 value.top,value.bottom 再去写逻辑即可。
上面的效果,可以参考以下代码:
前面说到,只需要把 tab_orientation 设置成 vertical 即可,相应的 当 type 为 rect 或者 tri 时,还可以通过 tab_tab_action_orientaion 选择 left 还是right 的效果:
<com.zhengsr.tablib.view.flow.TabFlowLayout android:id="@+id/tabflow" android:layout_width="wrap_content" android:layout_height="0dp" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent" app:tab_type="rect" app:tab_color="@color/colorPrimary" app:tab_orientation="vertical" app:tab_width="2dp" app:tab_height="20dp" app:tab_action_orientaion="left" android:background="@color/page_gray_cccc" /> 复制代码
效果如下:
和 recyclerview 的联动效果,可以参考在这个:
LabelFlowLayout 竖向布局,支持自动换行,单选、多选、长按等功能.
它的状态变化,根据 view 的 selected 来,所以大家可以写 selector 当背景,或者在方法中自己设置
LabelFlowLayout 默认单选,在 xml 这样配置:
<com.zhengsr.tablib.view.flow.LabelFlowLayout android:id="@+id/singleflow" android:layout_width="match_parent" android:layout_height="wrap_content" /> 复制代码
FlowLayout 使用也使用 adapter 去配置数据:
LabelFlowLayout flowLayout = findViewById(R.id.singleflow); final LabelFlowAdapter adapter; flowLayout.setAdapter(adapter = new LabelFlowAdapter<String>(R.layout.item_textview,mTitle) { @Override public void bindView(View view, String data, int position) { setText(view,R.id.item_text,data); } @Override public void onItemSelectState(View view, boolean isSelected) { super.onItemSelectState(view, isSelected); TextView textView = view.findViewById(R.id.item_text); if (isSelected) { textView.setTextColor(Color.WHITE); } else { textView.setTextColor(Color.GRAY); } } }); 复制代码
其实只需要配置 flowLayout.setMaxCount(3); 就可以了,然后adapter 中重写:
@Override public void onReachMacCount(List<Integer> ids, int count) { super.onReachMacCount(ids, count); Toast.makeText(LabelActivity.this, "最多只能选中 "+count+" 个"+" 已选中坐标: "+ids, Toast.LENGTH_SHORT).show(); } 复制代码
如果您选默认选中其中一些item,可以使用 flowLayout.setSelects(2,3,5);
其实就是长按view,至于状态的变化,由自己去写:
private void canLongFlow(){ LabelFlowLayout flowLayout = findViewById(R.id.longflow); flowLayout.setAdapter(new LabelFlowAdapter<String>(R.layout.item_search_layout,mTitle2) { @Override public void bindView(View view, String data, int position) { setText(view,R.id.search_msg_tv,data) .addChildrenClick(view,R.id.search_delete_iv,position); } @Override public void onItemSelectState(View view, boolean isSelected) { super.onItemSelectState(view, isSelected); if (!isSelected){ view.setBackgroundResource(R.drawable.shape_search); setVisible(view,R.id.search_delete_iv,false); } } @Override public void onItemClick(View view, String data, int position) { super.onItemClick(view, data, position); Toast.makeText(LabelActivity.this, "点击了: "+data, Toast.LENGTH_SHORT).show(); } @Override public void onItemChildClick(View childView, int position) { super.onItemChildClick(childView, position); if (childView.getId() == R.id.search_delete_iv){ mTitle2.remove(position); notifyDataChanged(); } } @Override public boolean onItemLongClick(View view,int position) { /** * 置所有view 的 select 为 false */ resetStatus(); view.setBackgroundResource(R.drawable.shape_search_select); setVisible(view,R.id.search_delete_iv,true); return super.onItemLongClick(view,position); } }); } 复制代码
TabFlowLayout 和 LAbelFlowLayout 都是通过 setAdapter 的方式去加载数据的,除了支持 setText(..) ,setTextColor(..) ,setImageView 等,还支持 click 事件,具体的方法,可以参考下面的代码:
TabFlowLayout
名称 | 类型 | 说明 |
---|---|---|
tab_type | rect,tri,round,color,res | tab的类型,目前支持矩形,三角形、圆角、颜色渐变、资源res |
tab_color | color | 指示器的颜色,当类型为 rect、tri、roud是可以通过它定义 |
tab_width | dimension | 指示器的宽度,如果不写,则根据控件自身大小 |
tab_height | dimension | 指示器高度 |
tab_item_res | reference | 指示器的背景,比如shape,bitmap等,只对 res 起作用 |
tab_round_size | dimension | 圆角的大小,只对round起作用 |
tab_margin_l | dimension | 左偏移 |
tab_margin_t | dimension | 上偏移 |
tab_margin_r | dimension | 右偏移 |
tab_margin_b | dimension | 下偏移 |
tab_click_animTime | integer | 点击动画的时间,默认300ms |
tab_item_autoScale | boolean | 开启放大缩小的效果 |
tab_scale_factor | float | 放大倍数 |
tab_orientation | integer | vertical竖直防线,horizontal横向,默认横向 |
tab_action_orientaion | integer | left坐标,right右边,只支持 tri、rect 两种效果 |
tab_isAutoScroll | boolean | 是否支持自动滚动,默认为true |
TabColorTextView
名称 | 类型 | 说明 |
---|---|---|
colortext_default_color | color | 默认颜色 |
colortext_change_color | color | 需要渐变颜色 |
LabelFlowLayout
名称 | 类型 | 说明 |
---|---|---|
label_maxcount | integer | 最大选择个数 |
label_iaAutoScroll | boolean | 是否支持自动滚动 |