簡單實(shí)現(xiàn)Android端搜索框示例詳解
正文
今天帶來一個(gè)非常實(shí)用的自定義搜索框,包含了搜索框、熱門搜索列表、最近搜索列表等常見的功能,有類似的,大家可以直接復(fù)用,將會(huì)大大節(jié)約您的開發(fā)時(shí)間,有一點(diǎn),很負(fù)責(zé)任的告訴大家,實(shí)現(xiàn)這個(gè)沒什么技術(shù)含量,就是很簡單的自定義組合View,本文除了使用介紹,我也會(huì)把具體的實(shí)現(xiàn)過程分享給大家。
今天的內(nèi)容大概如下:
- 1、效果展示
- 2、快速使用及屬性介紹
- 3、具體代碼實(shí)現(xiàn)
- 4、開源地址及總結(jié)
一、效果展示
效果很常見,就是平常需求中的效果,上面是搜索框,下面是最近和熱門搜索列表,為了方便大家在實(shí)際需求中使用,配置了很多屬性,也進(jìn)行了上下控件的拆分,也就是上邊搜索框和下面的搜索列表的拆分,可以按需進(jìn)行使用。
二、快速使用及屬性介紹
快速使用
目前已經(jīng)發(fā)布至遠(yuǎn)程Maven,大家可以進(jìn)行遠(yuǎn)程依賴使用。
1、在你的根項(xiàng)目下的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(搜索列表),在實(shí)際開發(fā)中,根據(jù)需求可選擇使用,二者是互不關(guān)聯(lián)的。
<?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、代碼邏輯,以下是測(cè)試代碼,如用到實(shí)際項(xiàng)目,請(qǐng)以實(shí)際項(xiàng)目獲取控件為主。
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({ //搜索內(nèi)容改變 }, { //軟鍵盤點(diǎn)擊了搜索 searchList.doSearchContent(it) }) //設(shè)置用于測(cè)試的熱門搜索列表 searchList.setHotList(getHotList()) //熱門搜索條目點(diǎn)擊事件 searchList.setOnHotItemClickListener { s, i -> Toast.makeText(this, s, Toast.LENGTH_SHORT).show() } //歷史搜索條目點(diǎn)擊事件 searchList.setOnHistoryItemClickListener { s, i -> Toast.makeText(this, s, Toast.LENGTH_SHORT).show() } } /** * AUTHOR:AbnerMing * INTRODUCE:模擬熱門搜索列表 */ private val mTestHotList = arrayListOf( "二流小碼農(nóng)", "三流小可愛", "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、搜索框監(jiān)聽
拿到searchLayout控件之后,調(diào)用setOnTextSearchListener方法即可,第一個(gè)方法是搜索內(nèi)容發(fā)生變化會(huì)回調(diào),第二個(gè)方法是,點(diǎn)擊了軟鍵盤的搜索按鈕會(huì)回調(diào),如果要在最近搜索里展示,直接調(diào)用doSearchContent方法即可。
searchLayout.setOnTextSearchListener({ //搜索內(nèi)容改變 }, { //軟鍵盤點(diǎn)擊了搜索 searchList.doSearchContent(it) })
2、搜索列表點(diǎn)擊事件
熱門搜索調(diào)用setOnHotItemClickListener方法,歷史搜索也就是最近搜索調(diào)用setOnHistoryItemClickListener方法,都是兩個(gè)參數(shù),第一個(gè)是文本內(nèi)容,第二個(gè)是索引,也就是點(diǎn)的是哪一個(gè)。
//熱門搜索條目點(diǎn)擊事件 searchList.setOnHotItemClickListener { s, i -> Toast.makeText(this, s, Toast.LENGTH_SHORT).show() } //歷史搜索條目點(diǎn)擊事件 searchList.setOnHistoryItemClickListener { s, i -> Toast.makeText(this, s, Toast.LENGTH_SHORT).show() }
3、改變最近(歷史)搜索item背景
有的老鐵說了,默認(rèn)的背景我不喜歡,能否可以動(dòng)態(tài)設(shè)置,必須能!
默認(rèn)背景
設(shè)置背景,通過setHistoryItemBg方法。
searchList.setHistoryItemBg(R.drawable.shape_solid_d43c3c_10)
效果展示
4、動(dòng)態(tài)設(shè)置熱門搜索熱度
可能在很多需求中,需要展示幾個(gè)熱度,有的是按照顏色區(qū)分,如下圖:
實(shí)現(xiàn)起來很簡單,在設(shè)置熱門列表(setHotList)的時(shí)候,針對(duì)傳遞的對(duì)象設(shè)置leftIcon即可。測(cè)試代碼如下:
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) } } }
具體的哪個(gè)數(shù)據(jù)展示什么顏色,直接設(shè)置即可,想怎么展示就怎么展示。當(dāng)然了除了展示不同的熱度之外,還有一些其他的變量,isShowLeftIcon為是否展示文字左邊的icon,textColor為當(dāng)前文字的顏色,根據(jù)不同的顏色,我們也可以實(shí)現(xiàn)下面的效果。
除了常見的方法之外,還提供了很多的屬性操作,具體的大家可以看下面,按需使用即可。
屬性介紹
為了讓功能靈活多變,也為了滿足更多的需求樣式,目前自定義了很多屬性,大家可以按自己的需要進(jìn)行設(shè)置,或者直接去GitHub中下載源碼更改也可以。
SearchLayout(搜索框?qū)傩裕?/h3>
屬性 | 類型 | 概述 |
---|---|---|
search_icon | reference | 搜索圖標(biāo),可直接從drawable或者mipmap中設(shè)置 |
search_icon_width | dimension | 搜索圖標(biāo)的寬 |
search_icon_height | dimension | 搜索圖標(biāo)的高 |
search_icon_left | dimension | 搜索圖標(biāo)距離左邊的距離 |
search_icon_delete | reference | 搜索刪除圖標(biāo),右側(cè)的刪除 |
search_icon_delete_width | dimension | 搜索刪除圖標(biāo)的寬 |
search_icon_delete_height | dimension | 搜索刪除圖標(biāo)的高 |
search_icon_delete_right | dimension | 搜索刪除圖標(biāo)距離右邊的距離 |
search_hint | string | 搜索框占位字符 |
search_hint_color | color | 搜索框占位字符顏色 |
search_color | color | 搜索框文字顏色 |
search_size | dimension | 搜索框文字大小 |
search_text_cursor | reference | 搜索框光標(biāo) |
search_bg | reference | 整個(gè)搜索框背景 |
SearchList(搜索列表屬性)
屬性 | 類型 | 概述 |
---|---|---|
is_hot_flex_box_or_grid | boolean | 熱門搜索列表樣式,是網(wǎng)格還是流式布局 |
is_hot_center | boolean | 熱門搜索列表樣式,內(nèi)容是否居中 |
hot_grid_span_count | integer | 熱門搜索列表樣式,如果是網(wǎng)格布局,條目列數(shù),默認(rèn)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 | 熱門搜索列表 內(nèi)邊距,左 |
hot_padding_top | dimension | 熱門搜索列表 內(nèi)邊距,上 |
hot_padding_right | dimension | 熱門搜索列表 內(nèi)邊距,右 |
hot_padding_bottom | dimension | 熱門搜索列表 內(nèi)邊距,下 |
is_history_flex_box_or_grid | boolean | 歷史搜索列表樣式,是網(wǎng)格還是流式布局 |
history_flex_box_count | integer | 歷史搜索列表,最多展示幾個(gè)item,默認(rèn)10 |
is_history_center | boolean | 歷史搜索列表樣式,內(nèi)容是否居中 |
history_grid_span_count | integer | 歷史搜索列表樣式,如果是網(wǎng)格布局,條目列數(shù),默認(rèn)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 | 歷史搜索列表 內(nèi)邊距,左 |
history_padding_top | dimension | 歷史搜索列表 內(nèi)邊距,上 |
history_padding_right | dimension | 歷史搜索列表 內(nèi)邊距,右 |
history_padding_bottom | dimension | 歷史搜索列表 內(nèi)邊距,下 |
三、具體代碼實(shí)現(xiàn)
關(guān)于這個(gè)組合View的實(shí)現(xiàn)方式,我是分為了兩個(gè)View,大家在上邊的使用中應(yīng)該也看到了,一個(gè)是搜索框SearchLayout,一個(gè)是搜索框下面的搜索列表展示SearchList,開頭就闡述了,沒啥技術(shù)含量,簡單的羅列下代碼實(shí)現(xiàn)吧。
SearchLayout是一個(gè)組合View,中間是一個(gè)EditText,左右兩邊是一個(gè)ImageView,也就是搜索圖標(biāo)和刪除圖標(biāo),如下圖:
SearchLayout本身沒有啥要說的,無非就是把View組合到了一起,在開發(fā)的時(shí)候,既然要給別人使用,那么就要拓展出很多的動(dòng)態(tài)屬性或者方法出來,這是很重要的,所以,在封裝的時(shí)候,自定義屬性無比的重要,需要精確和認(rèn)真,這一塊沒啥好說的,有一點(diǎn)需要注意,也就是EditText綁定軟鍵盤搜索,除了設(shè)置屬性android:imeOptions="actionSearch",也要設(shè)置,android:singleLine="true",方可生效。
SearchList其實(shí)也沒啥好說的,也是一個(gè)組合View,使用的是上下兩個(gè)RecyclerView來實(shí)現(xiàn)的,至于流失布局,采用的是google提供的flexbox,設(shè)置布局管理器即可。
recyclerView.layoutManager = FlexboxLayoutManager(mContext)
除了這個(gè)之外,可能需要闡述的也就是最近搜索的存儲(chǔ)機(jī)制了,存儲(chǔ)呢,Android中提供了很多的存儲(chǔ)方式,比如數(shù)據(jù)庫,SharedPreferences,SD卡,還有DataStore,MMKV等,無論哪一種吧,選擇適合的即可,這個(gè)開源中,不想引入其他的三方了,直接使用的是SharedPreferences。
具體的實(shí)現(xiàn)方式,把搜索的內(nèi)容,轉(zhuǎn)成json串,以json串的形式進(jìn)行存儲(chǔ),這里借助了原生的JSONArray和JSONObject。流程就是,觸發(fā)搜索內(nèi)容后,先從SharedPreferences取出之前存儲(chǔ)的內(nèi)容,放到JSONArray中,當(dāng)前搜索內(nèi)容如果存在JSONArray中,那邊就要執(zhí)行刪除原來的,再把新的內(nèi)容插入到第一個(gè)的位置,如果不存在JSONArray中,直接添加即可,隨后再轉(zhuǎn)成字符串存儲(chǔ)即可。
當(dāng)然了,一般在正常的需求開發(fā)中,最近搜索列表肯定不是無限展示的,都有固定的展示個(gè)數(shù),比如10個(gè),比如15個(gè),所以,當(dāng)超過指定的個(gè)數(shù),也就是指定的閥門后,就要執(zhí)行刪除的操作。
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) //如果出現(xiàn)了一樣的,刪除后,加到第一個(gè) 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 { //超過了指定的閥門之后,就不在擴(kuò)充 if (jsonArray.length() >= mHistoryListSize) { jsonArray.remove(0) } } jsonArray.put(json) SearchSharedPreUtils.put(mContext!!, "search_history", jsonArray.toString()) } getSearchHistory()?.let { eachSearchHistory(it) } //兩個(gè)有一個(gè)不為空,展示 if (!TextUtils.isEmpty(it) || !TextUtils.isEmpty(searchHistory)) { showOrHideHistoryLayout(View.VISIBLE) }
當(dāng)然了,存儲(chǔ)的邏輯,有很多的實(shí)現(xiàn)的方式,這里并不是最優(yōu)的,只是提供了一種思路,大家可以按照自己的方式來操作。
搜索列表,無論是熱門還是最近的搜索列表,均支持網(wǎng)格和流失布局形式展示,大家看屬性相關(guān)介紹中即可。這個(gè)搜索框本身就是很簡單的效果還有代碼,大家直接看源碼或文中介紹即可,就不多贅述了,更多關(guān)于Android端搜索框的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
基于Android實(shí)現(xiàn)跳轉(zhuǎn)到WiFi開關(guān)設(shè)置頁的詳細(xì)步驟
在Android應(yīng)用開發(fā)中,有時(shí)候需要引導(dǎo)用戶到特定的系統(tǒng)設(shè)置頁面,例如Wi-Fi開關(guān)設(shè)置頁,可以通過隱式Intent來實(shí)現(xiàn)這一功能,以下是詳細(xì)的步驟以及相關(guān)的Kotlin代碼示例,需要的朋友可以參考下2024-09-09Android編程設(shè)計(jì)模式之模板方法模式詳解
這篇文章主要介紹了Android編程設(shè)計(jì)模式之模板方法模式,結(jié)合實(shí)例形式詳細(xì)分析了Android模板方法模式的概念、功能、使用場(chǎng)景、用法及相關(guān)操作注意事項(xiàng),需要的朋友可以參考下2017-12-12Android自定義view之圍棋動(dòng)畫效果的實(shí)現(xiàn)
這篇文章主要介紹了Android自定義view之圍棋動(dòng)畫效果的實(shí)現(xiàn),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12Android一個(gè)類實(shí)現(xiàn)錄音與播放實(shí)例
大家好,本篇文章主要講的是Android一個(gè)類實(shí)現(xiàn)錄音與播放實(shí)例,感興趣的同學(xué)趕快來看一看吧,對(duì)你有幫助的話記得收藏一下2022-02-02Android多線程+單線程+斷點(diǎn)續(xù)傳+進(jìn)度條顯示下載功能
這篇文章主要介紹了Android多線程+單線程+斷點(diǎn)續(xù)傳+進(jìn)度條顯示下載功能,需要的朋友可以參考下2017-06-06AndroidStudio升級(jí)4.1坑(無法啟動(dòng)、插件plugin不好用、代碼不高亮)
這篇文章主要介紹了AndroidStudio升級(jí)4.1坑(無法啟動(dòng)、插件plugin不好用、代碼不高亮),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10