122.Android 简单的历史搜索

news2024/12/26 21:35:24

 第一步 FlowLayout:

public class FlowLayout extends ViewGroup {
    private int mHorizontalSpacing = dp2px(16); //每个item横向间距
    private int mVerticalSpacing = dp2px(8); //每个item横向间距


    private List<List<View>> allLines = new ArrayList<>(); // 记录所有的行,一行一行的存储,用于layout
    List<Integer> lineHeights = new ArrayList<>(); // 记录每一行的行高,用于layout


    public FlowLayout(Context context) {
        super(context);
    }

    public FlowLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public FlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    private void clearMeasureParams() {
        allLines.clear();
        lineHeights.clear();
    }


    /*
     * 1、度量子view
     * 2、获取子view的宽、高、换行等
     * 3、向父类索要宽高,判断是哪种MeasureSpecMode,根据不同的mode给出不同的区域
     * 4、保存记录
     * */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        clearMeasureParams();

        List<View> lineViews = new ArrayList<>(); //保存一行中的所有的view
        int lineWidthUsed = 0; //记录这行已经使用了多宽的size
        int lineHeight = 0; // 一行的行高

        int selfWidth = MeasureSpec.getSize(widthMeasureSpec);  //父view给我的宽度
        int selfHeight = MeasureSpec.getSize(heightMeasureSpec); //父view给我的高度

        int flowLayoutNeedWidth = 0;  // measure过程中,FlowLayout要求的父ViewGroup的宽
        int flowLayoutNeedHeight = 0; // measure过程中,FlowLayout要求的父ViewGroup的高

        int paddingLeft = getPaddingLeft();
        int paddingRight = getPaddingRight();
        int paddingTop = getPaddingTop();
        int paddingBottom = getPaddingBottom();
        // 获取子view数
        int childCount = getChildCount();
        for (int i = 0; i < childCount; i++) {
            // 获取子view
            View childView = getChildAt(i);
            // 获取子view的layoutParams,通过layoutParams可得到子view的宽高具体值或者MATCH_PARENT还是WRAP_CONTENT
            LayoutParams childLP = childView.getLayoutParams();
            if (childView.getVisibility() != View.GONE) {
                //将layoutParams转变成为 measureSpec  即设置子view的measureSpec
                /*
                 * widthMeasureSpec表示父view给予FlowLayout的宽度
                 * paddingLeft + paddingRight表示父view所设置的左右padding值
                 * childLP.width  表示 子view的宽度
                 * */
                int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec, paddingLeft + paddingRight, childLP.width);
                int childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec, paddingTop + paddingBottom, childLP.height);
                // 通过子view的measureSpec度量子view
                childView.measure(childWidthMeasureSpec, childHeightMeasureSpec);

                //获取子view的度量宽高
                int childMeasureWidth = childView.getMeasuredWidth();
                int childMeasureHeight = childView.getMeasuredHeight();

                //换行
                if(lineWidthUsed + mHorizontalSpacing + childMeasureWidth > selfWidth ){
                    //一旦换行,我们就可以判断当前行需要的宽和高,所以此时要记录下来
                    allLines.add(lineViews);
                    lineHeights.add(lineHeight);
                    //判断flowLayout到底需要多宽、多高
                    flowLayoutNeedWidth = Math.max(flowLayoutNeedWidth, lineWidthUsed);
                    flowLayoutNeedHeight = flowLayoutNeedHeight + lineHeight + mVerticalSpacing;

                    // 换行后初始化
                    // 此处不能用clear,用clear则allLines里面的item所指向的就是同一个内存地址了
                    lineViews = new ArrayList<>();
                    lineWidthUsed = 0;
                    lineHeight = 0;
                }

                //每行的设置
                lineViews.add(childView);
                lineWidthUsed = lineWidthUsed + mHorizontalSpacing + childMeasureWidth;
                lineHeight = Math.max(lineHeight, childMeasureHeight);

                //最后一行数据(因为最后一行的时候到不了换行的那句代码,所以不会显示,因此要单独判断)
                if(i == childCount -1){
                    allLines.add(lineViews);
                    lineHeights.add(lineHeight);
                    //判断flowLayout到底需要多宽、多高
                    flowLayoutNeedWidth = Math.max(flowLayoutNeedWidth, lineWidthUsed);
                    flowLayoutNeedHeight = flowLayoutNeedHeight + lineHeight + mVerticalSpacing;
                }

            }
        }

        //根据子View的度量结果,来重新度量自己ViewGroup
        // 作为一个ViewGroup,它自己也是一个View,它的大小也需要根据它的父view给它提供的宽高来度量
        //首先获取到父view的MeasureSpec的mode
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);

        // 如果父view的MeasureSpec的mode是EXACTLY表示宽度是确切的,则selfWidth为最终宽度,否则为
        int flowLayoutWidth = (widthMode == MeasureSpec.EXACTLY) ? selfWidth : flowLayoutNeedWidth;
        int flowLayoutHeight = (heightMode == MeasureSpec.EXACTLY) ? selfHeight : flowLayoutNeedHeight;

        // 保存记录
        setMeasuredDimension(flowLayoutWidth, flowLayoutHeight);

    }

    // 布局(每一行每一行的布局)
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        // 获取行数 最大显示3行
        int lineCount = Math.min(allLines.size(), 3);
        // 获取flowLayout所设置的pandding值,布局从左上角开始
        int curL = getPaddingLeft();
        int curT = getPaddingTop();
        for (int i = 0; i < lineCount; i++) {
            // 获取到每一行的所有view
            List<View> lineViews = allLines.get(i);

            for (int j = 0; j < lineViews.size(); j++){
                //获取单个view
                View view = lineViews.get(j);
                //设置view的视图坐标系,
                int left = curL;
                int top = curT;
                int right = left + view.getMeasuredWidth();
                int bottom = top + view.getMeasuredHeight();
                // view添加到布局
                view.layout(left,top,right,bottom);

                // 计算下一个view的宽度的开始位置
                curL = right + mHorizontalSpacing;
            }

            // 计算下一行view的高度的开始位置
            curT = curT + lineHeights.get(i) + mVerticalSpacing;
            // 宽度位置初始化
            curL = getPaddingLeft();
        }

    }

    public List<List<View>> getAllLines() {
        return allLines;
    }

    public static int dp2px(int dp) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, Resources.getSystem().getDisplayMetrics());
    }
}

第二步 xml布局:

<com.knowledge.platform.view.FlowLayout
    android:id="@+id/mSearchHistoryFlowLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

第三步 动态设置内容:

mSearchHistoryFlowLayout.removeAllViews();
List<String> historyText = UserInfo.getInstance().getHistoryText();
//集合反转
Collections.reverse(historyText);
for (String text : historyText) {
    TextView textView = new TextView(this);
    textView.setText(text);
    textView.setBackgroundResource(R.drawable.selector_dialog_bg_2);
    textView.setPadding(20, 20, 20, 20);
    textView.setGravity(Gravity.CENTER);
    textView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            mSearchmSearchHistoryLin.setVisibility(View.GONE);
            mSearchTabLin.setVisibility(View.VISIBLE);
            mSearchEdit.setText(textView.getText().toString());
            //选中文本最后一位
            Editable editable = mSearchEdit.getText();
            Selection.setSelection(editable, editable.length());
        }
    });
    mSearchHistoryFlowLayout.addView(textView);
}

第四步 保存、获取历史搜索内容数据,MmkvUtil是保存本地数据工具类:

/**
 * 获取保存的搜索历史
 *
 * @return
 */
public List<String> getHistoryText() {
    String historyText = MmkvUtil.getInstance().decodeString("historyText");
    if (TextUtils.isEmpty(historyText)) {
        return new ArrayList<>();
    }

    List<String> list = new ArrayList<>();
    JSONArray jsonArray = GsonUtil.getInstance().getJSONArray(historyText);
    for (int i = 0; i < jsonArray.length(); i++) {
        String string = jsonArray.optString(i);
        list.remove(string);
        list.add(string);
    }
    return list;
}

/**
 * 保存搜索历史
 *
 * @param historyText
 */
public void setHistoryText(List<String> historyText) {
    if (historyText.size() == 0) {
        MmkvUtil.getInstance().encode("historyText", "");
        return;
    }
    //使用JSONArray保存一些特殊字符
    JsonArray jsonArray = GsonUtil.getInstance().newJsonArray();

    //只保存100条数据
    int start = 0;
    if (historyText.size() > 100) {
        start = historyText.size() - 100;
    }
    for (int i = start; i < historyText.size(); i++) {
        jsonArray.add(historyText.get(i));
    }
    MmkvUtil.getInstance().encode("historyText", jsonArray.toString());
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1221453.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

PyCharm中常用插件推荐

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️ &#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…

Jmeter进行压力测试不为人知的秘密

jmeter是apache公司基于java开发的一款开源压力测试工具&#xff0c;体积小&#xff0c;功能全&#xff0c;使用方便&#xff0c;是一个比较轻量级的测试工具&#xff0c;使用起来非常简单。因为jmeter是java开发的&#xff0c;所以运行的时候必须先要安装jdk才可以。jmeter是免…

37 关于 undo 日志

前言 undo 和 redo 是在 mysql 中 事务, 或者 异常恢复 的场景下面 经常会看到的两个概念 这里 来看一下 undo, undo 主要是用于 事务回滚 的场景下面 测试表结构如下 CREATE TABLE tz_test (id int(11) unsigned NOT NULL AUTO_INCREMENT,field1 varchar(128) DEFAULT NUL…

python基础教程之有序字典

嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 有序字典和通常字典类似&#xff0c;只是它可以记录元素插入其中的顺序&#xff0c;而一般字典是会以任意的顺序迭代的。 普通字典&#xff1a; d1{} d1[a]A d1[b]B d1[c]C d1[d]D #此时的d1 {a:A,b:B,c:C,d:D} for k,v …

本地jar导入maven

一、通过dependency引入 1.1. jar包放置&#xff0c;建造lib目录 1.2. pom.xml文件 <dependency><groupId>zip4j</groupId><artifactId>zip4j</artifactId><version>1.3.2</version><!--system&#xff0c;类似provided&#x…

【Linux】第十八站:进程等待

文章目录 一、进程等待的必要性1.进程等待是什么2.进程等待的必要性3.为什么要进程等待呢&#xff1f; 二、进程等待的方法1.问题2.wait3.waitpid4.status的原理5.等待失败6.与status有关的两个宏7.options 一、进程等待的必要性 1.进程等待是什么 通过系统调用wait/waitpid&a…

压缩感知学习

对稀疏和稀疏矩阵的认识 采样率80Mhz 采样间隔12.5ns,样本数量为800个 一帧时长800*12.5ns 10us 频域间隔 1/10us 0.1Mhz 第一个点的频率是0 第21个点的频率是2Mhz 在只考虑正半轴&#xff0c;也即400个点的情况下&#xff0c;分别让不同的频点取1 &#xff0c;然后对其进…

MySQL优化的底层逻辑

文章目录 前言索引的底层结构数据与索引的关系聚簇索引的数据存储普通索引的数据存储 索引的命中逻辑怎么理解索引失效总结 前言 去年刚开始写博客的时候写了一篇《MySQL性能调优参考》&#xff0c;文章中提到优化的几个技巧&#xff0c;比如数据类型的使用、范式和反范式的合…

安装部署Esxi7.0并创建虚拟机

1. Esxi介绍 ESXI虚拟平台是VMware出品的一个强大平台&#xff0c;它可以直接安装在物理机上&#xff0c;从而充分利用物理奖性能&#xff0c;虚拟多个系统出来。ESXI是一个带WEB管理后台的软件&#xff0c;非常适合安装在服务器上&#xff0c;然后直接通过网页进行远程管理。…

测试开发环境下centos7.9下安装docker的minio

按照以下方法进行 1、安装docker&#xff0c;要是生产等还是要按照docker-ce yum install docker 2、启动docker service docker start 3、 查看docker信息 docker info 4、加到启动里 systemctl enable docker.service 5、开始docker pull minio/minio 但报错&#x…

TP-LINK联洲面试题

文章目录 1.说一下微服务架构?2.微服务优缺点3.负载均衡的实现算法4.Redis集群部署方式?5.MySQL主从复制?5.1 配置流程5.2 优缺点分析6.口头手撕快排7.队列实现栈和栈实现队列7.1 队列实现栈7.2 栈实现队列8.进程有几种状态?9.Spring Boot Actuator?10.外键、主键和索引?…

ImportError: cannot import name ‘url_quote‘ from...

&#x1f468;&#x1f3fb;‍&#x1f4bb; 热爱摄影的程序员 &#x1f468;&#x1f3fb;‍&#x1f3a8; 喜欢编码的设计师 &#x1f9d5;&#x1f3fb; 擅长设计的剪辑师 &#x1f9d1;&#x1f3fb;‍&#x1f3eb; 一位高冷无情的编码爱好者 大家好&#xff0c;我是全栈工…

Netty传输object并解决粘包拆包问题

⭐️ 前言 大家好&#xff0c;笔者之前写过一篇文章&#xff0c;《Netty中粘包拆包问题解决探讨》&#xff0c;就Netty粘包拆包问题及其解决方案进行了探讨&#xff0c;本文算是这篇博客的延续。探讨netty传输object的问题。 本文将netty结合java序列化来传输object并解决粘包…

C语言——求1/1-1/2+1/3-......+1/99-1/100的值

#include<stdio.h> int main() {int i 1;double sum 0;int flage 1;for(i 1;i < 100; i){sumflage*1.0/i;flage -flage; //正负号}printf("%lf\n",sum);return 0; }

2024年山东省职业院校技能大赛中职组“网络安全”赛项竞赛试题-B

2024年山东省职业院校技能大赛中职组 “网络安全”赛项竞赛试题-B 一、竞赛时间 总计&#xff1a;360分钟 二、竞赛阶段 竞赛阶段 任务阶段 竞赛任务 竞赛时间 分值 A、B模块 A-1 登录安全加固 180分钟 200分 A-2 本地安全策略设置 A-3 流量完整性保护 A-4 …

二十一、数组(1)

本章概要 数组特性 用于显示数组的实用程序 一等对象返回数组 简单来看&#xff0c;数组需要你去创建和初始化&#xff0c;你可以通过下标对数组元素进行访问&#xff0c;数组的大小不会改变。大多数时候你只需要知道这些&#xff0c;但有时候你必须在数组上进行更复杂的操作…

Ubuntu18.04安装Moveit框架

简介 Moveit是一个由一系列移动操作的功能包组成的集成化开发平台,提供友好的GUI,是目前ROS社区中使用度排名前三的功能包,Moveit包含以下三大核心功能,并集成了大量的优秀算法接口: 运动学:KDL,Trac-IK,IKFast...路径规划:OMPL,CHMOP,SBPL..碰撞检测:FCL,PCD... 一、更新功…

前段-用面向对象的方式开发一个水管小鸟的游戏

首先准备好各类空文件 index.js css html 和图片 图片是下面这些&#xff0c;如果没有的可在这里下载 2 开发开始 好了&#xff0c;基础准备工作完毕&#xff0c;开发开始&#xff0c; 首先&#xff0c;先把天空&#xff0c;大地&#xff0c;小鸟的盒子准备好&#xff0c;并…

基于探路者算法优化概率神经网络PNN的分类预测 - 附代码

基于探路者算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于探路者算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于探路者优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;针对PNN神经网络…

main函数的数组参数是干嘛用的

今天在看项目代码的时候&#xff0c;突然看到项目中用到了main函数的参数args&#xff0c;在这之前我还没怎么注意过这个参数&#xff0c;一时间居然不知道这个参数是干嘛的&#xff01; 虽然也写过一些java和scala&#xff0c;但是确实没遇到过会用这个参数的情况。 网上就查…