效果
效果分析
- 标签支持居左,居右,居中显示
- 标签支持设置最大显示行数
- 支持展开,折叠
分析思路
流布局标签,在日常应用中使用特别的广,使用场景及使用花样也很多,这里简单介绍其中的几点。
- 功能1: 标签展示的方式:左 中 右 三种
- 功能2: 标签支持折叠和展开,以及折叠时行数的控制
当我们需要做一种效果,或者需要自定义View的时候,本着 "不重复造轮子" 的方式来进行实现
像这种流布局最初大部分都是自定义ViewGrop来实现,自从google的flexbox发布,基本上都是用这个库来实现流布局效果。那么本文也是采用flexbox中的 FlexboxLayoutManager 来实现我们的效果,如果你对FlexboxLayoutManager有所了解的话,就知道是多么的方便。
流布局
recyclerView?.layoutManager = FlexboxLayoutManager(this)
为Recycleview设置为FlexboxLayoutManager的layoutManager就支持流布局展示了。
居左|居中|居右
//居左 setJustifyContent(JustifyContent.FLEX_START) //居中 setJustifyContent(JustifyContent.CENTER) //居右 setJustifyContent(JustifyContent.FLEX_END)
就是方便,现成的轮子就是爽啊!
固定最大显示行数
有的时候,我们会有固定行数的需求,当数据已经超出我们固定的行数时,只展示固定行数据,其他的裁掉,当点击展开的时候再显示所有数据。我们就带着这个需求去看下FlexboxLayoutManager有没有现成的方法。 诶,我找到了一个setMaxLine方法
@Override public void setMaxLine(int maxLine) { if (mMaxLine != maxLine) { mMaxLine = maxLine; requestLayout(); } }
字面上就是设置最大行的意思,马上试了一下:
setMaxLine(4)
效果出来是这样的
看来只能自己想办法了,本着 "有问题就谷歌,没谷歌看源码"的方式来搞他,一堆操作猛如虎。终于找到了
override fun getFlexLinesInternal(): MutableList<FlexLine> { val originList = super.getFlexLinesInternal() //数据 总行数 val totalLines = originList.size //总行数>设定行数,进行折叠 if (totalLines > mLineCount) { //对数据处理(清理从设定行到最大行的数据) originList.subList(mLineCount, totalLines).clear() //当前状态不是折叠状态时,再处理状态改变回调及状态更新,防止返回多次问题 if (mState != State.FOLD) { foldStateListener?.stateChange(State.FOLD) mState = State.FOLD } } //没有设置行数时,默认打开状态 if (mLineCount == NOT_SET) { //当前状态不是打开状态,进行打开操作,并回调状态改变 if (mState != State.OPEN) { foldStateListener?.stateChange(State.OPEN) mState = State.OPEN } } return originList }
根据判断当前行数是否大于设定的固定行数来进行数据裁剪来达到折叠的效果。代码比较的简单,全部贴出来
自定义 FlexboxLayoutManager
class MYFlexboxLayoutManager @JvmOverloads constructor(context: Context, var space: Int = 0) : FlexboxLayoutManager(context) { private var NOT_SET = Integer.MAX_VALUE private var mLineCount = NOT_SET private var mLinesCountTemp = NOT_SET private var mState = State.INIT var foldStateListener: OnFoldStateListener? = null enum class State { INIT, OPEN, FOLD, } /** * 设置显示最大行数 */ fun setMaxShowLine(lines: Int) { this.mLinesCountTemp = lines this.mLineCount = lines } /** * 切换展开/折叠 */ fun toggle() { if (mState == State.OPEN) { close() } else { open() } } /** * 展开 */ private fun open() { this.mLineCount = NOT_SET requestLayout() } /** * 折叠 */ private fun close() { this.mLineCount = mLinesCountTemp requestLayout() } override fun generateDefaultLayoutParams(): RecyclerView.LayoutParams { val generateDefaultLayoutParams = super.generateDefaultLayoutParams() generateDefaultLayoutParams.setMargins(space, space, space, space) return generateDefaultLayoutParams } override fun getFlexLinesInternal(): MutableList<FlexLine> { val originList = super.getFlexLinesInternal() //数据 总行数 val totalLines = originList.size //总行数>设定行数,进行折叠 if (totalLines > mLineCount) { //对数据处理(清理从设定行到最大行的数据) originList.subList(mLineCount, totalLines).clear() //当前状态不是折叠状态时,再处理状态改变回调及状态更新,防止返回多次问题 if (mState != State.FOLD) { foldStateListener?.stateChange(State.FOLD) mState = State.FOLD } } //没有设置行数时,默认打开状态 if (mLineCount == NOT_SET) { //当前状态不是打开状态,进行打开操作,并回调状态改变 if (mState != State.OPEN) { foldStateListener?.stateChange(State.OPEN) mState = State.OPEN } } return originList } interface OnFoldStateListener { fun stateChange(state: State) } }
欧克,就这么愉快的解决了。