Android使用官方FlexboxLayout仿淘宝历史记录搜索效果

574 阅读1分钟

目前能正常实现需求,如果有其他需求兄弟们可以尝试自己实现,提供思路,勿喷!

1.先自定义一个可以设置最大多少行的FlexboxLayout

class LinesFlexboxLayout @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null
) : FlexboxLayout(context, attrs) {
    private var mMaxLines: Int = -1
    override fun getFlexLinesInternal(): MutableList<FlexLine> {
        return if (mMaxLines == -1) {
            super.getFlexLinesInternal()
        } else {
            val flexLines = super.getFlexLinesInternal();
            val size = flexLines.size
            if (mMaxLines in 1 until size) {
                flexLines.subList(mMaxLines, size).clear();
            }
            flexLines
        }


    }

    fun setCustomMaxLines(maxLines: Int) {
        this.mMaxLines = maxLines
        requestLayout()
    }

}

2.开始添加flexLayout的子view

binding.flexBoxLayout.setCustomMaxLines(-1)
lifecycleScope.launchWhenStarted {
    SearchRecordHelper.getDefault().getSearchRecordsFlow().collect {
        val list = it ?: emptyList()
        binding.flexBoxLayout.removeAllViews()
        list.take(15).forEach { record ->
            createBoxLayout(record)
        }
        viewModel.searchHistoryVisibility.set(list.isNotEmpty())
        binding.flexBoxLayout.post {
            try {
                //这里设定最大行数为3
                if (binding.flexBoxLayout.flexLinesInternal.size > 3) {
                   //获取第三行的FlexLine相关
                    binding.flexBoxLayout.flexLinesInternal.getOrNull(2)
                        ?.let { thirdLines ->
                            if (binding.flexBoxLayout.childCount <= 0) {
                                return@let
                            }
                            //获取到upView的宽度,upView就是展开更多记录的按钮view
                            val measuredWidth = SizeUtils.getMeasuredWidth(upView)
                            val surplusWidth =
                                ScreenUtils.getScreenWidth() - thirdLines.mainSize
                            binding.flexBoxLayout.setCustomMaxLines(3)
                            //如果剩余距离大于展开按钮的宽度
                            if (surplusWidth >= measuredWidth) {
                                //添加展开按钮到第三行的最后一个
                                binding.flexBoxLayout.addView(
                                    upView,
                                    thirdLines.firstIndex + thirdLines.itemCount
                                )
                                //隐藏第三行以外的view
                                removeOtherView(
                                    thirdLines.firstIndex + thirdLines.itemCount,
                                    binding.flexBoxLayout.childCount
                                )
                            } else {
                                //如果剩余距离小于展开按钮的宽度并且第三行的子view只有一个,修改其宽度确保能放下展开view
                                if (thirdLines.itemCount == 1) {
                                    val childAt =
                                        binding.flexBoxLayout.getChildAt(thirdLines.firstIndex)
                                    val updateWidth =
                                        ScreenUtils.getScreenWidth() - SizeUtils.dp2px(32f) - SizeUtils.getMeasuredWidth(
                                            upView
                                        )
                                    childAt.updateLayoutParams<ViewGroup.LayoutParams> {
                                        width = updateWidth
                                        height = ViewGroup.LayoutParams.WRAP_CONTENT
                                    }
                                    binding.flexBoxLayout.addView(
                                        upView, thirdLines.firstIndex + thirdLines.itemCount
                                  )
                                removeOtherView(
                                  thirdLines.firstIndex + thirdLines.itemCount,
                                  binding.flexBoxLayout.childCount)
                                } else {
                                 //如果剩余距离小于展开按钮的宽度并且第三行的子view有多个,隐藏最后一个,添加
                                    val childAt =
                                        binding.flexBoxLayout.getChildAt(thirdLines.firstIndex + thirdLines.itemCount - 1)
                                    if (childAt != null) {
                                        childAt.isVisible = false
                                    }
                                    binding.flexBoxLayout.addView(
                                        upView,
                                        thirdLines.firstIndex + thirdLines.itemCount - 1
                                    )
                                    removeOtherView(
                                        thirdLines.firstIndex + thirdLines.itemCount - 1,
                                        binding.flexBoxLayout.childCount
                                    )
                                }
                            }
                        }
                }
            } catch (e: Exception) {
                binding.flexBoxLayout.removeAllViews()
            }
        }
    }

}

3.隐藏最大行以外的view

private fun removeOtherView(startIndex: Int, childCount: Int) {
    for (index in startIndex + 1 until childCount) {
        val childAt = binding.flexBoxLayout.getChildAt(index)
        if (childAt != null) {
            childAt.isVisible = false
        }
    }
}