简单实现Android端搜索框示例详解

目录
  • 正文
  • 一、效果展示
  • 二、快速使用及属性介绍
    • 快速使用
    • 具体代码
  • 主要方法介绍
    • 1、搜索框监听
    • 2、搜索列表点击事件
    • 3、改变最近(历史)搜索item背景
    • 4、动态设置热门搜索热度
  • 属性介绍
    • SearchLayout(搜索框属性)
    • SearchList(搜索列表属性)
  • 三、具体代码实现

正文

今天带来一个非常实用的自定义搜索框,包含了搜索框、热门搜索列表、最近搜索列表等常见的功能,有类似的,大家可以直接复用,将会大大节约您的开发时间,有一点,很负责任的告诉大家,实现这个没什么技术含量,就是很简单的自定义组合View,本文除了使用介绍,我也会把具体的实现过程分享给大家。

今天的内容大概如下:

  • 1、效果展示
  • 2、快速使用及属性介绍
  • 3、具体代码实现
  • 4、开源地址及总结

一、效果展示

效果很常见,就是平常需求中的效果,上面是搜索框,下面是最近和热门搜索列表,为了方便大家在实际需求中使用,配置了很多属性,也进行了上下控件的拆分,也就是上边搜索框和下面的搜索列表的拆分,可以按需进行使用。

二、快速使用及属性介绍

快速使用

目前已经发布至远程Maven,大家可以进行远程依赖使用。

1、在你的根项目下的build.gradle文件下,引入maven。

allprojects {
    repositories {
        maven { url "https://gitee.com/AbnerAndroid/almighty/raw/master" }
    }
}

2、在你需要使用的Module中build.gradle文件下,引入依赖。

dependencies {
    implementation 'com.vip:search:1.0.0'
}

具体代码

1、xml中引入SearchLayout(搜索框)和SearchList(搜索列表),在实际开发中,根据需求可选择使用,二者是互不关联的。

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns: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:paddingLeft="10dp"
  android:paddingRight="10dp"
  tools:context=".MainActivity">
  <com.vip.search.SearchLayout
    android:id="@+id/search_layout"
    android:layout_width="match_parent"
    android:layout_height="40dp"
    android:layout_marginTop="10dp"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:search_bg="@drawable/shape_stroke_10" />
  <com.vip.search.SearchList
    android:id="@+id/search_list"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="10dp"
    app:is_hot_flex_box_or_grid="true"
    app:is_visibility_history_clear="true"
    app:layout_constraintTop_toBottomOf="@id/search_layout" />
</androidx.constraintlayout.widget.ConstraintLayout>

2、代码逻辑,以下是测试代码,如用到实际项目,请以实际项目获取控件为主。

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val searchLayout = findViewById<SearchLayout>(R.id.search_layout)
        val searchList = findViewById<SearchList>(R.id.search_list)
        searchLayout.setOnTextSearchListener({
            //搜索内容改变
        }, {
            //软键盘点击了搜索
            searchList.doSearchContent(it)
        })
        //设置用于测试的热门搜索列表
        searchList.setHotList(getHotList())
        //热门搜索条目点击事件
        searchList.setOnHotItemClickListener { s, i ->
            Toast.makeText(this, s, Toast.LENGTH_SHORT).show()
        }
        //历史搜索条目点击事件
        searchList.setOnHistoryItemClickListener { s, i ->
            Toast.makeText(this, s, Toast.LENGTH_SHORT).show()
        }
    }
    /**
* AUTHOR:AbnerMing
* INTRODUCE:模拟热门搜索列表
*/
    private val mTestHotList = arrayListOf(
        "二流小码农", "三流小可爱", "Android",
        "Kotlin", "iOS", "Java", "Python", "Php是世界上最好的语言"
    )
    private fun getHotList(): ArrayList<SearchBean> {
        return ArrayList<SearchBean>().apply {
            mTestHotList.forEachIndexed { index, s ->
                val bean = SearchBean()
                bean.content = s
                bean.isShowLeftIcon = true
                val drawable: Drawable? = if (index < 2) {
                    ContextCompat.getDrawable(this@MainActivity, R.drawable.shape_circle_select)
                } else if (index == 2) {
                    ContextCompat.getDrawable(this@MainActivity, R.drawable.shape_circle_ordinary)
                } else {
                    ContextCompat.getDrawable(this@MainActivity, R.drawable.shape_circle_normal)
                }
                drawable?.setBounds(0, 0, drawable.minimumWidth, drawable.minimumHeight)
                bean.leftIcon = drawable
                add(bean)
            }
        }
    }
}

主要方法介绍

1、搜索框监听

拿到searchLayout控件之后,调用setOnTextSearchListener方法即可,第一个方法是搜索内容发生变化会回调,第二个方法是,点击了软键盘的搜索按钮会回调,如果要在最近搜索里展示,直接调用doSearchContent方法即可。

 searchLayout.setOnTextSearchListener({
            //搜索内容改变
        }, {
            //软键盘点击了搜索
            searchList.doSearchContent(it)
})

2、搜索列表点击事件

热门搜索调用setOnHotItemClickListener方法,历史搜索也就是最近搜索调用setOnHistoryItemClickListener方法,都是两个参数,第一个是文本内容,第二个是索引,也就是点的是哪一个。

    	//热门搜索条目点击事件
        searchList.setOnHotItemClickListener { s, i ->
            Toast.makeText(this, s, Toast.LENGTH_SHORT).show()
        }
        //历史搜索条目点击事件
        searchList.setOnHistoryItemClickListener { s, i ->
            Toast.makeText(this, s, Toast.LENGTH_SHORT).show()
        }

3、改变最近(历史)搜索item背景

有的老铁说了,默认的背景我不喜欢,能否可以动态设置,必须能!

默认背景

设置背景,通过setHistoryItemBg方法。

 searchList.setHistoryItemBg(R.drawable.shape_solid_d43c3c_10)

效果展示

4、动态设置热门搜索热度

可能在很多需求中,需要展示几个热度,有的是按照颜色区分,如下图:

实现起来很简单,在设置热门列表(setHotList)的时候,针对传递的对象设置leftIcon即可。测试代码如下:

private fun getHotList(): ArrayList<SearchBean> {
        return ArrayList<SearchBean>().apply {
            mTestHotList.forEachIndexed { index, s ->
                val bean = SearchBean()
                bean.content = s
                bean.isShowLeftIcon = true
                val drawable: Drawable? = if (index < 2) {
                    ContextCompat.getDrawable(this@MainActivity, R.drawable.shape_circle_select)
                } else if (index == 2) {
                    ContextCompat.getDrawable(this@MainActivity, R.drawable.shape_circle_ordinary)
                } else {
                    ContextCompat.getDrawable(this@MainActivity, R.drawable.shape_circle_normal)
                }
                drawable?.setBounds(0, 0, drawable.minimumWidth, drawable.minimumHeight)
                bean.leftIcon = drawable
                add(bean)
            }
        }
    }

具体的哪个数据展示什么颜色,直接设置即可,想怎么展示就怎么展示。当然了除了展示不同的热度之外,还有一些其他的变量,isShowLeftIcon为是否展示文字左边的icon,textColor为当前文字的颜色,根据不同的颜色,我们也可以实现下面的效果。

除了常见的方法之外,还提供了很多的属性操作,具体的大家可以看下面,按需使用即可。

属性介绍

为了让功能灵活多变,也为了满足更多的需求样式,目前自定义了很多属性,大家可以按自己的需要进行设置,或者直接去GitHub中下载源码更改也可以。

SearchLayout(搜索框属性)

属性 类型 概述
search_icon reference 搜索图标,可直接从drawable或者mipmap中设置
search_icon_width dimension 搜索图标的宽
search_icon_height dimension 搜索图标的高
search_icon_left dimension 搜索图标距离左边的距离
search_icon_delete reference 搜索删除图标,右侧的删除
search_icon_delete_width dimension 搜索删除图标的宽
search_icon_delete_height dimension 搜索删除图标的高
search_icon_delete_right dimension 搜索删除图标距离右边的距离
search_hint string 搜索框占位字符
search_hint_color color 搜索框占位字符颜色
search_color color 搜索框文字颜色
search_size dimension 搜索框文字大小
search_text_cursor reference 搜索框光标
search_bg reference 整个搜索框背景

SearchList(搜索列表属性)

属性 类型 概述
is_hot_flex_box_or_grid boolean 热门搜索列表样式,是网格还是流式布局
is_hot_center boolean 热门搜索列表样式,内容是否居中
hot_grid_span_count integer 热门搜索列表样式,如果是网格布局,条目列数,默认2
hot_item_top_margin integer 热门搜索列表 item距离上边的距离
hot_item_color color 热门搜索列表 item 文字颜色
hot_item_size dimension 热门搜索列表 item 文字大小
hot_item_line integer 热门搜索列表 item 文字展示几行
hot_item_bg reference 热门搜索列表 item 背景
hot_item_margin_top reference 热门搜索列表 item 距离上边的距离
hot_padding_left dimension 热门搜索列表 内边距,左
hot_padding_top dimension 热门搜索列表 内边距,上
hot_padding_right dimension 热门搜索列表 内边距,右
hot_padding_bottom dimension 热门搜索列表 内边距,下
is_history_flex_box_or_grid boolean 历史搜索列表样式,是网格还是流式布局
history_flex_box_count integer 历史搜索列表,最多展示几个item,默认10
is_history_center boolean 历史搜索列表样式,内容是否居中
history_grid_span_count integer 历史搜索列表样式,如果是网格布局,条目列数,默认2
history_item_top_margin integer 历史搜索列表 item距离上边的距离
history_item_color color 历史搜索列表 item 文字颜色
history_item_size dimension 历史搜索列表 item 文字大小
history_item_margin_top dimension 历史搜索列表 item 距离上边的距离
is_visibility_history_clear boolean 历史搜索右边是否展示清除小按钮
history_clear_icon reference 历史搜索右边的清除小按钮
history_clear_text string 历史搜索右边的清除文字
history_clear_size dimension 历史搜索右边的清除文字大小
history_clear_color color 历史搜索右边的清除文字颜色
history_padding_left dimension 历史搜索列表 内边距,左
history_padding_top dimension 历史搜索列表 内边距,上
history_padding_right dimension 历史搜索列表 内边距,右
history_padding_bottom dimension 历史搜索列表 内边距,下

三、具体代码实现

关于这个组合View的实现方式,我是分为了两个View,大家在上边的使用中应该也看到了,一个是搜索框SearchLayout,一个是搜索框下面的搜索列表展示SearchList,开头就阐述了,没啥技术含量,简单的罗列下代码实现吧。

SearchLayout是一个组合View,中间是一个EditText,左右两边是一个ImageView,也就是搜索图标和删除图标,如下图:

SearchLayout本身没有啥要说的,无非就是把View组合到了一起,在开发的时候,既然要给别人使用,那么就要拓展出很多的动态属性或者方法出来,这是很重要的,所以,在封装的时候,自定义属性无比的重要,需要精确和认真,这一块没啥好说的,有一点需要注意,也就是EditText绑定软键盘搜索,除了设置属性android:imeOptions="actionSearch",也要设置,android:singleLine="true",方可生效。

SearchList其实也没啥好说的,也是一个组合View,使用的是上下两个RecyclerView来实现的,至于流失布局,采用的是google提供的flexbox,设置布局管理器即可。

recyclerView.layoutManager = FlexboxLayoutManager(mContext)

除了这个之外,可能需要阐述的也就是最近搜索的存储机制了,存储呢,Android中提供了很多的存储方式,比如数据库,SharedPreferences,SD卡,还有DataStore,MMKV等,无论哪一种吧,选择适合的即可,这个开源中,不想引入其他的三方了,直接使用的是SharedPreferences。

具体的实现方式,把搜索的内容,转成json串,以json串的形式进行存储,这里借助了原生的JSONArray和JSONObject。流程就是,触发搜索内容后,先从SharedPreferences取出之前存储的内容,放到JSONArray中,当前搜索内容如果存在JSONArray中,那边就要执行删除原来的,再把新的内容插入到第一个的位置,如果不存在JSONArray中,直接添加即可,随后再转成字符串存储即可。

当然了,一般在正常的需求开发中,最近搜索列表肯定不是无限展示的,都有固定的展示个数,比如10个,比如15个,所以,当超过指定的个数,也就是指定的阀门后,就要执行删除的操作。

    	val searchHistory = getSearchHistory()
        if (!TextUtils.isEmpty(it)) {
            val jsonArray: JSONArray = if (TextUtils.isEmpty(searchHistory)) {
                JSONArray()
            } else {
                JSONArray(searchHistory)
            }
            val json = JSONObject()
            json.put("content", it)
            //如果出现了一样的,删除后,加到第一个
            var isEqual = false
            var equalPosition = 0
            for (i in 0 until jsonArray.length()) {
                val item = jsonArray.getJSONObject(i)
                val content = item.getString("content")
                if (it == content) {
                    isEqual = true
                    equalPosition = i
                    break
                }
            }
            //有一样的
            if (isEqual) {
                jsonArray.remove(equalPosition)
            } else {
                //超过了指定的阀门之后,就不在扩充
                if (jsonArray.length() >= mHistoryListSize) {
                    jsonArray.remove(0)
                }
            }
            jsonArray.put(json)
            SearchSharedPreUtils.put(mContext!!, "search_history", jsonArray.toString())
        }
        getSearchHistory()?.let {
            eachSearchHistory(it)
        }
        //两个有一个不为空,展示
        if (!TextUtils.isEmpty(it) || !TextUtils.isEmpty(searchHistory)) {
            showOrHideHistoryLayout(View.VISIBLE)
        }

当然了,存储的逻辑,有很多的实现的方式,这里并不是最优的,只是提供了一种思路,大家可以按照自己的方式来操作。

开源地址:github.com/AbnerMing88…

搜索列表,无论是热门还是最近的搜索列表,均支持网格和流失布局形式展示,大家看属性相关介绍中即可。这个搜索框本身就是很简单的效果还有代码,大家直接看源码或文中介绍即可,就不多赘述了,更多关于Android端搜索框的资料请关注我们其它相关文章!

(0)

相关推荐

  • Android实现简单动态搜索功能

    目录 前言 一.addTextChangedListener 二.本文案例 1.介绍一下SearchView的一些方法 2.准备数据 3.初始化以及填充数据 4.在SearchView中用户输入字符时激发方法里写入简单逻辑 三.源码 前言 提到Android的动态搜索,大多应该会想到EditText的文本改变的监听器(addTextChangedListener),本文会简单介绍一下,但是本文介绍的是SearchView+Listview的实现. 效果图: 一.addTextChangedLis

  • Android本地实现搜索历史记录

    本文实例为大家分享了Android本地实现搜索历史记录的具体代码,供大家参考,具体内容如下 一.自定义搜索历史记录 本地实现搜索历史记录有很多种方法,下面不多说了,我们来用SQLite来实现此功能,直接上完整代码:点击下载源码 效果一: 效果二: 1.MainActivity主函数 package com.example.administrator.searchapplication; import android.support.v7.app.AppCompatActivity; import

  • Android实现搜索本地音乐的方法

    本文实例为大家分享了Android实现搜索本地音乐展示的具体代码,供大家参考,具体内容如下 首先是扫描本地所有的音频文件,然后全部装进集合当中,接下来就是用ListView展示在屏幕上,大概就是这几个步骤了,接下来细讲 创建一个容器 进行过数据解析的朋友都应该知道JavaBean吧,用来装载解析出来的数据,我们这里同样也要创建一个JavaBean,用来装载扫描到的音频文件,具体的代码是: /** * Created by user on 2016/6/24. * 放置音乐 */ public c

  • Android Studio全局搜索快捷键(Ctrl+Shift+F)失效问题及解决

    目录 Android Studio全局搜索快捷键(Ctrl+Shift+F)失效 焦点调整 输入法冲突 Mac下的Android Studio快捷键 Android Studio的快捷键 总结 Android Studio全局搜索快捷键(Ctrl+Shift+F)失效 焦点调整 可能你的焦点在下面的一排调试窗里,这种情况将焦点调到主界面即可 输入法冲突 可能在不同输入法下系统缓存区对输入的”Ctrl+Shift+F”的识别不同,这种情况下可以将输入法切换成系统默认的状态”Shift+Ctrl’或

  • Android的搜索框架实例详解

    基础知识 Android的搜索框架将代您管理的搜索对话框,您不需要自己去开发一个搜索框,不需要担心要把搜索框放什么位置,也不需要担心搜索框影响您当前的界面.所有的这些工作都由SearchManager类来为您处理(以下简称"搜索管理器"),它管理的Android搜索对话框的整个生命周期,并执行您的应用程序将发送的搜索请求,返回相应的搜索关键字. 当用户执行一个搜索,搜索管理器将使用一个专门的Intent把搜索查询的关键字传给您在配置文件中配置的处理搜索结果的Activity.从本质上讲

  • Android 列表选择框 Spinner详解及实例

    Android 列表选择框 Spinner详解及实例 Spinner 是 Android 的列表选择框,不过 spinner 并不需要显示下拉列表,而是相当于弹出一个菜单供用户选择. Spinner 属性: ● android:spinnerMode:列表显示的模式,有两个选择,为弹出列表(dialog)以及下拉列表(dropdown),如果不特别设置,为下拉列表. ● android:entries:使用<string-array.../>资源配置数据源. ● android:prompt:

  • Spi机制在Android开发的应用示例详解

    目录 Spi机制介绍 举个例子 ServiceLoader.load 在Android中的应用 总结 Spi机制介绍 SPI 全称是 Service Provider Interface,是一种将服务接口与服务实现分离以达到解耦.可以提升程序可扩展性的机制.嘿嘿,看到这个概念很多人肯定是一头雾水了,没事,我们直接就可以简单理解为是一种反射机制,即我们不需要知道具体的实现方,只要定义好接口,我们就能够在运行时找到一个实现接口的类,我们具体看一下官方定义. 举个例子 加入我是一个库设计者,我希望把一

  • kotlin android extensions 插件实现示例详解

    目录 前言 原理浅析 总体结构 源码分析 插件入口 配置编译器插件传参 编译器插件接收参数 注册各种Extension IrGenerationExtension ExpressionCodegenExtension StorageComponentContainerContributor ClassBuilderInterceptorExtension PackageFragmentProviderExtension 总结 前言 kotlin-android-extensions 插件是 Ko

  • Vue 服务端渲染SSR示例详解

    目录 手写Vue服务端渲染 一.开始vue-ssr之旅 二.采用模板渲染 三.ssr目录创建 四.通过webpack实现编译vue项目 app.js client-entry.js server-entry.js 五.配置客户端打包和服务端打包 六.配置运行脚本 七.服务端配置 七.通过json配置createBundleRenderer方法 八.集成VueRouter 配置入口文件 配置组件信息 防止刷新页面不存在 保证异步路由加载完成 十.集成vuex配置 在后端更新vuex 在浏览器运行时

  • 20行代码简单实现koa洋葱圈模型示例详解

    目录 引言 koa中间件的使用 洋葱圈模型 洋葱圈模型的实现,koa-compose 单次调用限制 koa-compose与流程引擎 总结 引言 koa想必很多人直接或间接的都用过,其源码不知道阅读本文的你有没有看过,相当精炼,本文想具体说说koa的中间件模型,一起看看koa-compose的源码,这也是koa系列的第一篇文章,后续会更新一下koa相关的其他知识点 koa中间件的使用 先让我们启动一个koa服务 // app.js const koa = require('koa'); cons

  • android中webview定位问题示例详解

    前言 现在很多App里都内置了Web网页(Hyprid App),比如说很多电商平台,淘宝.京东.聚划算等等 京东首页 那么这种该如何实现呢?其实这是Android里一个叫WebView的组件实现的. 最近在做安卓的网页开发.有一个页面需要用到定位,但是一直定位获取失败.很难过.网上教程也很多,但是无一例外全部失败.最后老夫花了3天时间,呕心沥血,终于研制出了解决方案. 三步走战略: 一.获取权限 android 6.0 以后,需要动态的获取位置或者存储权限,按照各自的爱好放置位置.我是应用开启

  • Android ActionBar搜索功能用法详解

    本文实例讲述了Android ActionBar搜索功能用法.分享给大家供大家参考,具体如下: 使用ActionBar SearchView时的注意点: 首先要吐槽一下Android的官方Guide文档 ,关于用法讲得不明确,可能是一直没更新的原因吧. 本来照着文档搞了一下,hint死活出不来,也无法跳转到搜索结果Activity. StackOverflow也有人提出了这个问题,答案说得很明白 - 参考链接. 正确用法 1. 在AndroidManifest.xml中为提供SearchView

  • Android多线程断点续传下载示例详解

    一.概述 在上一篇博文<Android多线程下载示例>中,我们讲解了如何实现Android的多线程下载功能,通过将整个文件分成多个数据块,开启多个线程,让每个线程分别下载一个相应的数据块来实现多线程下载的功能.多线程下载中,可以将下载这个耗时的操作放在子线程中执行,即不阻塞主线程,又符合Android开发的设计规范. 但是当下载的过程当中突然出现手机卡死,或者网络中断,手机电量不足关机的现象,这时,当手机可以正常使用后,如果重新下载文件,似乎不太符合大多数用户的心理期望,那如何实现当手机可以正

  • nodejs 实现简单的文件上传功能(示例详解)

    首先需要大家看一下目录结构,然后开始一点开始我们的小demo. 文件上传总计分为三种方式: 1.通过flash,activeX等第三方插件实现文件上传功能. 2.通过html的form标签实现文件上传功能,优点:浏览器兼容好. 3.通过xhr level2的异步请求,可以百度formData对象. 这里使用2做个练习. node插件请看下package.json文件 { "name": "upload", "version": "0.1

随机推荐