1. 项目需求:

如下,如果没有向下箭头(显示/隐藏剩余搜索词条)的话,采用flexbox-layout+Recycleview+FlexboxLayoutManager 可以实现流式布局。

加了这个箭头,做起来有点复杂,体现在:
1 怎么知道搜索词条总的数量超过2行了?
2 箭头应该在哪个位置出现?
原有的FlexboxLayoutManager 并没有提供类似的方法或是监听告知。可能需要用到自定义view来做特殊处理

2. 代码实现:

方案:采用FlowLayout,这里借鉴了FlowLayout,
思路:判断当前词条是否已经超过了2行,如果超过了2行,就获取到第2行最后一个view的索引值,然后在词条库中将此索引值对应的词条更改为特殊标记。当flowlayout获取到这个特殊标记时候,做相应的处理。
FlowLayout修改如下:
关键是:

 //OnLayout中:if(lineCount==1){//第二行数据,并且有超过限定行数的时候lastGoneView = child;lastGoneView.setTag(i);//将此view的索引值放入tag中Log.d("HXY","CountIndex="+i);}
1. FlowLayout
public class FlowLayout extends ViewGroup {private static final String TAG = "FlowLayout";private static final int LEFT = -1;private OnTagClickListener mOnTagClickListener;private int limitLineCount; //默认显示3行 断词条显示3行,长词条显示2行private boolean isLimit; //是否有行限制private boolean isOverFlow; //是否溢出2行private View lastGoneView;//被隐藏的最后一个viewpublic View getLastGoneView() {return lastGoneView;}protected List<List<View>> mAllViews = new ArrayList<List<View>>();protected List<Integer> mLineHeight = new ArrayList<Integer>();protected List<Integer> mLineWidth = new ArrayList<Integer>();private List<View> lineViews = new ArrayList<>();public boolean isOverFlow() {return isOverFlow;}private void setOverFlow(boolean overFlow) {isOverFlow = overFlow;}public boolean isLimit() {return isLimit;}public void setLimit(boolean limit) {if (!limit) {setOverFlow(false);}isLimit = limit;requestLayout();}public FlowLayout(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);limitLineCount = 2;isLimit = true;}public FlowLayout(Context context, AttributeSet attrs) {this(context, attrs, 0);}public FlowLayout(Context context) {this(context, null);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);int modeWidth = MeasureSpec.getMode(widthMeasureSpec);int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);int modeHeight = MeasureSpec.getMode(heightMeasureSpec);// wrap_contentint width = 0;int height = 0;int lineWidth = 0;int lineHeight = 0;//在每一次换行之后记录,是否超过了行数int lineCount = 0;//记录当前的行数int cCount = getChildCount();for (int i = 0; i < cCount; i++) {View child = getChildAt(i);if (child.getVisibility() == View.GONE) {if (i == cCount - 1) {if (isLimit) {if (lineCount == limitLineCount) {setOverFlow(true);break;} else {setOverFlow(false);}}width = Math.max(lineWidth, width);height += lineHeight;lineCount++;}continue;}measureChild(child, widthMeasureSpec, heightMeasureSpec);MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();int childWidth = child.getMeasuredWidth() + lp.leftMargin+ lp.rightMargin;int childHeight = child.getMeasuredHeight() + lp.topMargin+ lp.bottomMargin;if (lineWidth + childWidth > sizeWidth - getPaddingLeft() - getPaddingRight()) {if (isLimit) {if (lineCount == limitLineCount) {setOverFlow(true);break;} else {setOverFlow(false);}}width = Math.max(width, lineWidth);lineWidth = childWidth;height += lineHeight;lineHeight = childHeight;lineCount++;} else {lineWidth += childWidth;lineHeight = Math.max(lineHeight, childHeight);}if (i == cCount - 1) {if (isLimit) {if (lineCount == limitLineCount) {setOverFlow(true);break;} else {setOverFlow(false);}}width = Math.max(lineWidth, width);height += lineHeight;lineCount++;}}setMeasuredDimension(modeWidth == MeasureSpec.EXACTLY ? sizeWidth : width + getPaddingLeft() + getPaddingRight(),modeHeight == MeasureSpec.EXACTLY ? sizeHeight : height + getPaddingTop() + getPaddingBottom()//);}@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {mAllViews.clear();mLineHeight.clear();mLineWidth.clear();lineViews.clear();int width = getWidth();int lineWidth = 0;int lineHeight = 0;//如果超过规定的行数则不进行绘制int lineCount = 0;//记录当前的行数int cCount = getChildCount();//count数量for (int i = 0; i < cCount; i++) {View child = getChildAt(i);if (child.getVisibility() == View.GONE) continue;MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();int childWidth = child.getMeasuredWidth();int childHeight = child.getMeasuredHeight();if (childWidth + lineWidth + lp.leftMargin + lp.rightMargin > width - getPaddingLeft() - getPaddingRight()) {if (isLimit) {if (lineCount == limitLineCount) {Log.d("HXY","onLayout = 达到限制行数");break;}}mLineHeight.add(lineHeight);mAllViews.add(lineViews);mLineWidth.add(lineWidth);lineWidth = 0;lineHeight = childHeight + lp.topMargin + lp.bottomMargin;lineViews = new ArrayList<View>();lineCount++;}Log.d("HXY","lineCount ="+lineCount);if(lineCount==1){//第二行数据,并且有超过限定行数的时候lastGoneView = child;lastGoneView.setTag(i);Log.d("HXY","CountIndex="+i);}lineWidth += childWidth + lp.leftMargin + lp.rightMargin;lineHeight = Math.max(lineHeight, childHeight + lp.topMargin+ lp.bottomMargin);lineViews.add(child);}mLineHeight.add(lineHeight);mLineWidth.add(lineWidth);mAllViews.add(lineViews);int left = getPaddingLeft();int top = getPaddingTop();int lineNum = mAllViews.size();if(lineNum<=2){//说明没有超过2行,则不存在lastGoneViewlastGoneView=null;}for (int i = 0; i < lineNum; i++) {lineViews = mAllViews.get(i);lineHeight = mLineHeight.get(i);left = getPaddingLeft();for (int j = 0; j < lineViews.size(); j++) {View child = lineViews.get(j);if (child.getVisibility() == View.GONE) {continue;}MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();int lc = left + lp.leftMargin;int tc = top + lp.topMargin;int rc = lc + child.getMeasuredWidth();int bc = tc + child.getMeasuredHeight();child.layout(lc, tc, rc, bc);child.setOnClickListener(new View.OnClickListener(){@Overridepublic void onClick(View v) {if(mOnTagClickListener!=null){mOnTagClickListener.onTagClick(child);}}});left += child.getMeasuredWidth() + lp.leftMargin+ lp.rightMargin;}top += lineHeight;}}@Overridepublic LayoutParams generateLayoutParams(AttributeSet attrs) {return new MarginLayoutParams(getContext(), attrs);}@Overrideprotected LayoutParams generateDefaultLayoutParams() {return new MarginLayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);}@Overrideprotected LayoutParams generateLayoutParams(LayoutParams p) {return new MarginLayoutParams(p);}//点击事件的监听public void setOnTagClickListener(OnTagClickListener onTagClickListener) {mOnTagClickListener = onTagClickListener;}public interface OnTagClickListener {void onTagClick(View view);}}
2. Activity中应用如下:
  private var datas = mutableListOf<String>("小狗汪汪汪", "黑胡椒AAAAAAAA", "韩剧同款", "钢琴曲","测试数据啊啊啊","多一条")override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_flex1)setFlowLayoutNormal()ivClear.setOnClickListener {flowLayout.visibility = View.GONEdatas.clear()}//最后一个被隐藏的view,post 是因为lastGoneView是在onLayout中获取的,避免拿不到flowLayout.post {var children1 = flowLayout.lastGoneView//查找到隐藏的viewif (children1 != null) {val tag = children1.tag as IntLog.d("HXY","tag index=${tag}")datas.add(tag,"箭头")//将隐藏的view对应的值替换掉datas.forEach {Log.d("HXY","data:${it}")}setFlowLayoutArrow()//设置成箭头模式flowLayout.post {var chi = flowLayout[tag]chi.setOnClickListener {datas.removeAt(tag)//恢复成正常模式flowLayout.isLimit = falsesetFlowLayoutNormal()}}}}flowLayout.setOnTagClickListener {if(it is TextView){var text = it.textLog.d("HXY","点击 text ${text}")}}}private fun setFlowLayoutNormal() {flowLayout.removeAllViews()for (i in datas.indices) {var tv = TextView(this)tv.height = 28.dptv.gravity = Gravity.CENTERval name = datas[i]tv.text = nametv.setPadding(16.dp, 4.dp, 16.dp, 4.dp)tv.setBackgroundResource(R.drawable.bg_16_ff445e)flowLayout.addView(tv)var layoutParams = tv.layoutParams as ViewGroup.MarginLayoutParamslayoutParams.setMargins(8.dp)tv.layoutParams = layoutParams}}private fun setFlowLayoutArrow() {flowLayout.removeAllViews()for (i in datas.indices) {var tv = TextView(this)tv.height = 28.dptv.gravity = Gravity.CENTERval iv = ImageView(this)iv.setImageResource(R.drawable.icon_com_arrow_down_2)iv.setBackgroundResource(R.drawable.bg_16_ff445e)iv.isClickable = trueval name = datas[i]if (name == "箭头") {iv.setPadding(6.dp)flowLayout.addView(iv)var layoutParams = iv.layoutParams as ViewGroup.MarginLayoutParamslayoutParams.height = 28.dplayoutParams.width = ViewGroup.LayoutParams.WRAP_CONTENTlayoutParams.setMargins(8.dp)iv.layoutParams = layoutParamsbreak} else {tv.text = nametv.setPadding(16.dp, 4.dp, 16.dp, 4.dp)tv.setBackgroundResource(R.drawable.bg_16_ff445e)flowLayout.addView(tv)var layoutParams = tv.layoutParams as ViewGroup.MarginLayoutParamslayoutParams.setMargins(8.dp)tv.layoutParams = layoutParams}}}}

布局代码:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:background="#f0f0f0"android:padding="8dp"tools:context=".FlexActivity1"><TextViewandroid:id="@+id/tvHistory"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="历史搜索"android:textSize="17sp"android:textColor="#3c3c3c"android:textStyle="bold"android:layout_marginLeft="8dp"android:layout_marginRight="8dp"app:layout_constraintTop_toTopOf="parent"app:layout_constraintLeft_toLeftOf="parent"/><ImageViewandroid:id="@+id/ivClear"android:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@drawable/icon_com_trash_line"app:layout_constraintTop_toTopOf="@id/tvHistory"app:layout_constraintBottom_toBottomOf="@id/tvHistory"android:layout_marginRight="8dp"app:layout_constraintRight_toRightOf="parent"/><com.example.myyouapp.flow.FlowLayoutandroid:id="@+id/flowLayout"android:layout_width="match_parent"android:layout_height="wrap_content"app:layout_constraintTop_toBottomOf="@id/tvHistory"android:layout_marginTop="12dp"></com.example.myyouapp.flow.FlowLayout></androidx.constraintlayout.widget.ConstraintLayout>
3. 运行效果:
  1. 词汇( “小狗汪汪汪”, “黑胡椒AAAAAAAA”, “韩剧同款”, “钢琴曲”,“测试数据啊啊啊”,“多一条”)超过2 行:
  2. 词汇( “小狗汪汪汪”, “黑胡椒AAAAAAAA”, “韩剧同款”, “钢琴曲”,“测试数据啊啊啊”,“多一条”)超过2行点击箭头展开
  3. 词汇( “小狗汪汪汪”, “黑胡椒AAAAAAAA”, “韩剧同款”, “钢琴曲”,“测试数据啊啊啊”)只有2行

    以上就是改造Flowlayout 所做的历史搜索流式布局样式效果。

仿唯品会/京东/淘宝搜索流式布局的隐藏与展示相关推荐

  1. 移动端开发——京东首页制作(流式布局)

    移动端开发--京东首页制作(流式布局) 项目准备 初始化基本文件夹 创建index.html 设置视口 引入基本公共样式 引入自己的css样 <!DOCTYPE html> <htm ...

  2. 手写一个淘宝、京东的搜索流式布局FlowLayout

    目录 一些叨叨 继承ViewGrop 实现自定义控件 重写构造器 提供对外接口 测量 摆放 使用方法 完整代码 一些叨叨 市面上所有的app只要有搜索功能,几乎都离不开流式布局,像淘宝.京东.小红书等 ...

  3. 京东移动端首页-流式布局

    京东移动端首页 采用流式布局(百分比布局) 采用流式布局(百分比布局) 主要源码: <!DOCTYPE html> <html lang="en">< ...

  4. 京东首页案例(流式布局)

    我是表哥Harker,表妹我来咯~ 上篇说过,现在主流的移动端开发是单独制作移动端页面,响应式虽然有但是很麻烦,但是我们学肯定都要学到,那么这篇开始我们先讲解单独制作的几个布局. 这篇讲解流式布局(其 ...

  5. 实在智能RPA助你揭开淘宝搜索权重引流规则

    摘要:实在智能为电商运营提供RPA自动化解决方案,淘宝搜索框下拉框关联词获取机器人.生意参谋平台自动化下载报表机器人--实在智能RPA助力电商人提升运营效率! 说到电商,就避不开店铺运营,而店铺整体的 ...

  6. 升级JSONB列式存储,Hologres助力淘宝搜索2022双11降本增效!

    作者:陆晨炜(花名遣云)阿里巴巴智能引擎事业部数据开发 前言: 2022年的双11,阿里淘宝搜推集群承载上千万每秒的的流量峰值,消费者的每一次浏览.点击都通过搜推集群进行流转,与往年双11不同的是,降 ...

  7. 菜鸟窝-仿京东淘宝项目学习笔记(二)ToolBar的基本使用

    本篇知识点均来自于菜鸟窝-仿京东淘宝实战项目视频中 今天继续仿京东淘宝项目的学习,第二天,学习ToolBar的基本使用,本篇记录视频中一些重要的笔记 笔记一:ToolBar的一些重要属性 xml st ...

  8. 微信小程序仿京东淘宝商品排序

    微信小程序仿京东淘宝商品排序 效果图如下所示 仿京东微信小程序视频请加QQ:1010753897 下载地址:https://download.csdn.net/download/qq_43764578 ...

  9. Javascript小案例(一):仿淘宝搜索框用户输入事件的实现

    淘宝是我们经常用的一个网上购物平台,打开淘宝网首页,找到淘宝首页的搜索框,如下如所示: (截图日期:2017年6月18日) 大家可以看到,当页面一打开,搜索框中就可以看到灰色字体"少女高跟鞋 ...

最新文章

  1. 当代艺术遇上虚拟现实:幻境视界打造基业VR美术馆
  2. c# 线程,同步,锁
  3. mysql实际项目中使用多长时间_存储过程在实际项目中用的多吗?
  4. let 和const
  5. 深度优先搜索----poj 1321棋盘问题
  6. linux gcc编译C程序 分享
  7. 11 月全球 Web 服务器调查报告:nginx 表现最佳
  8. linux中的rootfs/initrd/ramfs/initramfs
  9. Mobileye单目测距
  10. python预测模型类型,多变量时间序列的预测和建模指南(附Python代码)
  11. JSP内置对象及其常用方法
  12. 企业级POS收银系统源码(客户端+后台)
  13. 【TK精灵】一款界面友好的桌面程序(exe)进程守护管理软件
  14. 如何快速辨别工业级POE交换机和普通交换机的不同?
  15. 秀米的对话框格子可以变大吗_秀米怎么制作微信滑动照片呢?方法/步骤
  16. 【Python自动化任务】让运维更简单的7种定时任务实现方式,总有一种适合你的场景
  17. html a标签发微信,a标签的特殊和文本的样式
  18. Access 一些内部函数(Access 帮助里) .
  19. 杭州计算机学校2017分数,2017各大学最低投档分数线
  20. diffdock:将扩散模型用于分子对接

热门文章

  1. python职位应聘_我去面试Python岗位了
  2. 【Android笔记 二】Location获取地理位置信息(上)
  3. 【开源项目学习】源码剖析,学习仿网易云音乐app代码
  4. 三容水箱液位控制系统_基于MATLAB三容水箱液位控制系统
  5. 【信号分析与处理】Matlab运算带有冲激函数的积分
  6. 社区型商场/购物中心会员管理方案
  7. 《非暴力沟通》读书感悟
  8. SqueezeNet网络讲解
  9. 基于SpringBoot+Python多语言银行卡识别系统
  10. 金融信息安全实训——利用常见的网络命令获取网络信息