<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                # 1. 簡單使用 可以直接結合`Toolbar`使用,也就是在添加的`item.xml`中直接使用,比如: ~~~ <?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <item android:id="@+id/bt2" android:title="@string/note_page_description" android:icon="@drawable/ic_baseline_search_24" app:actionViewClass="android.widget.SearchView" app:showAsAction="always" /> <item android:id="@+id/bt3" android:title="@string/note_page_setting" android:icon="@drawable/ic_baseline_settings_24" app:showAsAction="ifRoom"/> </menu> ~~~ 然后可以簡單設置一下顯示格式。 參考:https://blog.csdn.net/jaynm/article/details/107172544 ![](https://img.kancloud.cn/e0/bf/e0bff67276f12dcd24df00500ccd9331_1224x607.png) 使用 `SearchView` 時可使用如下常用方法。 - `setIconifiedByDefault(Boolean iconified)`:設置該搜索框默認是否自動縮小為圖標。 - `setSubmitButtonEnabled(Boolean enabled)`:設置是否顯示搜索按鈕。 - `setQueryHint(CharSequence hint)`:設置搜索框內默認顯示的提示文本。 - `setOnQueryTextListener(SearchView.OnQueryTextListener listener)`:為該搜索框設置事件監聽器。 比如: ~~~ // 添加Toolbar菜單欄按鈕 override fun onCreateOptionsMenu(menu: Menu?): Boolean { menuInflater.inflate(R.menu.toolbar_item, menu) // 找到搜索框 val item = menu?.findItem(R.id.bt2) search = item?.actionView as SearchView // 設置搜索框 search.let { it.isSubmitButtonEnabled = true it.queryHint = "請輸入關鍵字" it.imeOptions = EditorInfo.IME_ACTION_DONE it.maxWidth = 800 } return true } ~~~ 然后可以返回結果列表: 根據`setSuggestionsAdapter()`方法可以實現輸入搜索內容,自動提示的功能。`setSuggestionsAdapter(CursorAdapter adapter)`方法需要一個 `CursorAdapter` 參數,這里看到` Cursor`,很多人就應該清楚,`Cursor` 光標或者游標。正常情況下這里應該采用 `Cursor` 操作數據庫,可以實現查詢篩選功能。 # 2. 搜索提示功能 一般開發中遇到的需求是:輸入關鍵字就顯示搜索結果,所以需要監聽搜索框的文字輸入,一旦文字變化就查詢數據庫,更新搜索結果。這里為了模擬,創建一個數據庫。這里使用`Room`框架來構建,也就是三步: - 創建表對應的實體類; - 創建`Dao`層操作接口類; - 創建繼承自`RoomDatabase`的數據庫`Dao`層接口獲取類; 至于更多`Room`操作細節,可以查看我的看云的`Kotlin`筆記處。這里不再給出。當然,對應于這里我們需要模糊查詢,這里給出一個示例: ~~~ @Query("select * from MFNote where (title like '%' || :words || '%') or (content like '%' || :words || '%') or (first_submit like '%' || :words || '%') or (last_modify like '%' || :words || '%') or (label like '%' || :words || '%') or (category like '%' || :words || '%') LIMIT 10") fun getNodesByKeyWords(words: String): Cursor ~~~ 這里沒有指定具體類型`List<MFNote>`,因為我們這里需要一個`Cursor`對象。然后為查詢后顯示的`item`創建布局文件(`search_item_layout.xml`): ~~~ <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:orientation="vertical" android:layout_width="match_parent" android:background="@color/white" android:layout_height="match_parent" > <TextView android:id="@+id/search_item_tv" android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="18sp" android:text="主標題" android:textStyle="bold" android:padding="10dp" android:textColor="@color/black" android:gravity="center_vertical|start" > </TextView> <TextView android:id="@+id/search_item_subTitle" android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="12sp" android:text="副標題" android:paddingStart="10dp" android:paddingBottom="10dp" android:paddingEnd="10dp" android:maxEms="20" android:singleLine="true" android:ellipsize="end" android:textColor="@color/gray" android:gravity="center_vertical|start" tools:ignore="RtlSymmetry"> </TextView> </LinearLayout> ~~~ 然后找到這個`SearchView`,進行設置: ~~~ // 添加Toolbar菜單欄按鈕 override fun onCreateOptionsMenu(menu: Menu?): Boolean { menuInflater.inflate(R.menu.toolbar_item, menu) // 找到搜索框 val item = menu?.findItem(R.id.bt2) search = item?.actionView as SearchView // 設置搜索框 search.let { it.isSubmitButtonEnabled = true it.queryHint = "請輸入關鍵字" it.imeOptions = EditorInfo.IME_ACTION_DONE it.maxWidth = 800 } // 設置輸入監聽函數 search.setOnQueryTextListener(object : SearchView.OnQueryTextListener { override fun onQueryTextSubmit(query: String?): Boolean { return false } override fun onQueryTextChange(newText: String?): Boolean { if(mfDao == null){ mfDao = MFNoteDataBase.getInstance(this@MainActivity)?.mfDao() } val cursor = mfDao?.getNodesByKeyWords(newText?:"測") Log.e("TAG", "onQueryTextChange: ${newText}, cursor count : ${cursor?.count}" ) if(search.suggestionsAdapter == null){ val cursorAdapter = SimpleCursorAdapter(this@MainActivity, R.layout.search_item_layout, cursor, listOf<String>("title", "content").toTypedArray(), listOf<Int>(R.id.search_item_tv, R.id.search_item_subTitle).toIntArray() ) as CursorAdapter search.suggestionsAdapter = cursorAdapter } else{ search.suggestionsAdapter.changeCursor(cursor) } return false } }) return true } ~~~ 效果: ![](https://img.kancloud.cn/b6/32/b632a210925431a686c810ccf1b06f26_365x587.png) 但是有個弊端就是需要輸入兩個字符才會有數據提示。這里通過反射來實現: ~~~ // 通過反射設置只要有一個文字就觸發查詢 val clazz = search.javaClass val field = clazz.getDeclaredField("mSearchSrcTextView") field.isAccessible = true val searchAutoComplete = field.get(search) as AutoCompleteTextView searchAutoComplete.threshold = 1 ~~~ 效果: ![](https://img.kancloud.cn/62/d9/62d96ee7038050f161b3e04128cc3662_306x257.png) 當然,也可以直接不使用默認的這個結果顯示,自己寫一個`ListView`,然后進行監聽`SearchView`的數據變化,自己來渲染在`xml`中寫入的`ListView`即可。這里不采用這種方式,所以這里不再給出案例。 # 3. 搜索提示監聽 當然,上面的功能還沒完,我們還需要響應點擊事件。這里就需要查閱官方文檔:[創建搜索界面 ?|? Android 開發者 ?|? Android Developers](https://developer.android.com/guide/topics/search/search-dialog) ## 3.1 配置xml文件 首先需要的是一個名為可搜索配置的 `XML `文件。名為`searchable.xml`,并且必須保存在`res/xml/`項目目錄中。 > 注意:系統使用此文件來實例化`[SearchableInfo](https://developer.android.com/reference/android/app/SearchableInfo)`對象,但您無法在運行時自行創建此對象,您必須在 `XML` 中聲明可搜索配置。比如: ~~~ <?xml version="1.0" encoding="utf-8"?> <searchable xmlns:android="http://schemas.android.com/apk/res/android" android:hint="@string/search" android:label="@string/title"> </searchable> ~~~ ## 3.2 創建可搜索 Activity 因為這里我只是在`MainActivity`中有搜索框`SearchView`,所以這里我也只能配置在`MainActivity`來接受結果。比如: ~~~ <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> <intent-filter> <action android:name="android.intent.action.SEARCH" /> </intent-filter> <meta-data android:name="android.app.searchable" android:resource="@xml/searchable" /> </activity> ~~~ 1. 在[`<intent-filter>`](https://developer.android.com/guide/topics/manifest/intent-filter-element)元素中聲明要接受[`ACTION_SEARCH`](https://developer.android.com/reference/android/content/Intent#ACTION_SEARCH)`intent` 的 `Activity`。 2. 在[`<meta-data>`](https://developer.android.com/guide/topics/manifest/meta-data-element)元素中指定要使用的可搜索配置。 ## 3.3 配置關聯 需要為每個[`SearchView`](https://developer.android.com/reference/android/widget/SearchView)啟用輔助搜索。為此,您可以調用[`setSearchableInfo()`](https://developer.android.com/reference/android/widget/SearchView#setSearchableInfo(android.app.SearchableInfo))并向其傳遞表示可搜索配置的[`SearchableInfo`](https://developer.android.com/reference/android/app/SearchableInfo)對象。 ~~~ // 響應搜索列表點擊 val searchManager = getSystemService(Context.SEARCH_SERVICE) as SearchManager search.apply { setSearchableInfo(searchManager.getSearchableInfo(componentName)) } ~~~ ## 3.4 顯示搜索結果 在可搜索 `Activity` 中執行搜索涉及三個步驟: 1. [接收查詢](https://developer.android.com/guide/topics/search/search-dialog#ReceivingTheQuery) 2. [搜索數據](https://developer.android.com/guide/topics/search/search-dialog#SearchingYourData) 3. [顯示結果](https://developer.android.com/guide/topics/search/search-dialog#PresentingTheResults) 比如下面的代碼: ~~~ override fun onCreate(savedInstanceState: Bundle?) { ? ? ? ? super.onCreate(savedInstanceState) ? ? ? ? setContentView(R.layout.search) ? ? ? ? // Verify the action and get the query ? ? ? ? if (Intent.ACTION_SEARCH == intent.action) { ? ? ? ? ? ? intent.getStringExtra(SearchManager.QUERY)?.also { query -> ? ? ? ? ? ? ? ? doMySearch(query) ? ? ? ? ? ? } ? ? ? ? } ? ? } ~~~ 更多細節可以查閱官方文檔:[設置搜索界面 ?|? Android 開發者 ?|? Android Developers](https://developer.android.com/training/search/setup) 因為這里所有的控件都是在`MainActivity`中,所以這里需要代碼設置部分顯示和部分不顯示。而且我們需要設置這個`Activity`的啟動模式: ``` android:launchMode="singleTop" ``` 然后,在[`onNewIntent()`](https://developer.android.com/reference/android/app/Activity#onNewIntent(android.content.Intent))方法中處理[`ACTION_SEARCH`](https://developer.android.com/reference/android/content/Intent#ACTION_SEARCH)`intent`。 比如: ~~~ override fun onNewIntent(intent: Intent?) { super.onNewIntent(intent) processSearchData(intent) } fun processSearchData(intent: Intent?){ if(intent?.action == Intent.ACTION_SEARCH){ val stringExtra = intent.extras?.get(SearchManager.QUERY) Log.e("TAG", "processSearchData: ${ stringExtra }" ) } } ~~~ 但是呢,很不幸,結果如下: ![](https://img.kancloud.cn/78/36/783624883f1a5ce439218d3af6794fef_1025x174.png) 這里并沒有獲取到任何數據,所以這里需要再次查閱其源碼: ~~~ private Intent createIntentFromSuggestion(Cursor c, int actionKey, String actionMsg) { try { // use specific action if supplied, or default action if supplied, or fixed default String action = getColumnString(c, SearchManager.SUGGEST_COLUMN_INTENT_ACTION); if (action == null) { action = mSearchable.getSuggestIntentAction(); } if (action == null) { action = Intent.ACTION_SEARCH; } // use specific data if supplied, or default data if supplied String data = getColumnString(c, SearchManager.SUGGEST_COLUMN_INTENT_DATA); if (data == null) { data = mSearchable.getSuggestIntentData(); } // then, if an ID was provided, append it. if (data != null) { String id = getColumnString(c, SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID); if (id != null) { data = data + "/" + Uri.encode(id); } } Uri dataUri = (data == null) ? null : Uri.parse(data); String query = getColumnString(c, SearchManager.SUGGEST_COLUMN_QUERY); String extraData = getColumnString(c, SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA); return createIntent(action, dataUri, extraData, query, actionKey, actionMsg); } catch (RuntimeException e ) { int rowNum; try { // be really paranoid now rowNum = c.getPosition(); } catch (RuntimeException e2 ) { rowNum = -1; } Log.w(LOG_TAG, "Search suggestions cursor at row " + rowNum + " returned exception.", e); return null; } } ~~~ 以及: ~~~ private Intent createIntent(String action, Uri data, String extraData, String query, int actionKey, String actionMsg) { // Now build the Intent Intent intent = new Intent(action); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // We need CLEAR_TOP to avoid reusing an old task that has other activities // on top of the one we want. We don't want to do this in in-app search though, // as it can be destructive to the activity stack. if (data != null) { intent.setData(data); } intent.putExtra(SearchManager.USER_QUERY, mUserQuery); if (query != null) { intent.putExtra(SearchManager.QUERY, query); } if (extraData != null) { intent.putExtra(SearchManager.EXTRA_DATA_KEY, extraData); } if (mAppSearchData != null) { intent.putExtra(SearchManager.APP_DATA, mAppSearchData); } if (actionKey != KeyEvent.KEYCODE_UNKNOWN) { intent.putExtra(SearchManager.ACTION_KEY, actionKey); intent.putExtra(SearchManager.ACTION_MSG, actionMsg); } intent.setComponent(mSearchable.getSearchActivity()); return intent; } ~~~ 根據上面源碼可以很容易知道放置進去的鍵值對,故而這里可以多測試幾組: ~~~ fun processSearchData(intent: Intent?){ if(intent?.action == Intent.ACTION_SEARCH){ Log.e("TAG", "QUERY: ${ intent.extras?.get(SearchManager.QUERY) }" ) Log.e("TAG", "USER_QUERY: ${ intent.extras?.get(SearchManager.USER_QUERY) }" ) Log.e("TAG", "EXTRA_DATA_KEY: ${ intent.extras?.get(SearchManager.EXTRA_DATA_KEY) }" ) Log.e("TAG", "ACTION_KEY: ${ intent.extras?.get(SearchManager.ACTION_KEY) }" ) Log.e("TAG", "ACTION_MSG: ${ intent.extras?.get(SearchManager.ACTION_MSG) }" ) } } ~~~ 輸入: ![](https://img.kancloud.cn/6e/f3/6ef30e5361bfefb700418380fba6d7b7_567x359.png) 然后隨機點擊一個: ![](https://img.kancloud.cn/d3/5b/d35ba9448a3dfef4deb1ab5053605c35_1030x213.png) 可以看見此時有效的只有`USER_QUERY`。故而這里還需要看源碼,看看如何設置。可以看見: ~~~ // Cursor c String query = getColumnString(c, SearchManager.SUGGEST_COLUMN_QUERY); ~~~ 而這個方法來自: ~~~ import static android.widget.SuggestionsAdapter.getColumnString; ~~~ 其方法細節為: ~~~ public static String getColumnString(Cursor cursor, String columnName) { int col = cursor.getColumnIndex(columnName); return getStringOrNull(cursor, col); } ~~~ 也就是從`cursor`中獲取指定名字的列的數據。所以我們只需要確保查詢到的數據中有`SearchManager.SUGGEST_COLUMN_QUERY`這么一列。而這個值為: ~~~ public final static String SUGGEST_COLUMN_QUERY = "suggest_intent_query"; ~~~ 這里由于我使用的是`Room`所以這里我直接在`Entity`類中添加一個屬性: ~~~ @ColumnInfo(name = "suggest_intent_query") var query: Int = 0 ~~~ 然后重新生成數據庫即可。然后添加兩天數據,再次測試: ![](https://img.kancloud.cn/5a/3a/5a3afd553a5782a88cd21b5973e26002_514x349.png) 再次隨機點擊一條,查看控制臺打印信息: ![](https://img.kancloud.cn/69/d6/69d659a7cf7352a854e65ffa052e07e9_1024x187.png) 可以看到此時對應的`QUERY`字段就有值了。由于我們可能需要通過這個字段來查詢數據,進而顯示詳細的數據,所以這里需要其每個記錄的唯一,所以后面可能需要修改為`Long`,來存儲毫秒數。 # 3.5 重新修改邏輯 如果均在`MainActivity`顯示主要內容,以及顯示搜索結果,那么就需要設置很多的顯示和隱藏,比如: ~~~ // 進入顯示搜索結果的時候 fun enterSearchResultView(search_result_ll: LinearLayout){ search_result_ll.visibility = View.VISIBLE swiperefreshLayout.visibility = View.GONE bottom_tab.visibility = View.GONE floatingactionbutton.visibility = View.GONE } ~~~ 但是,感覺這樣太麻煩了,所以這里我預期將搜索結果顯示放置在另外一個`Activity`中。首先修改一下清單文件: ~~~ <activity android:name=".MainActivity" android:launchMode="singleTop"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".activitys.TestActivity"> <intent-filter> <action android:name="android.intent.action.SEARCH" /> </intent-filter> <meta-data android:name="android.app.searchable" android:resource="@xml/searchable" /> </activity> ~~~ 然后,需要關聯對應的`TestActivity`文件: ~~~ // 響應搜索列表點擊 val searchManager = getSystemService(Context.SEARCH_SERVICE) as SearchManager search.apply { setSearchableInfo(searchManager.getSearchableInfo(componentName)) } ~~~ 但是,`componentName`是在當前`Activity`的`this`中獲取到的,這里我無法直接獲取到`TestActivity`的`componentName`,所以直接手動創建一個對應的對象。 ~~~ // 響應搜索列表點擊 val searchManager = getSystemService(Context.SEARCH_SERVICE) as SearchManager search.apply { val search_componentName = ComponentName("com.weizu.myapplication.activitys", "com.weizu.myapplication.activitys.TestActivity") setSearchableInfo(searchManager.getSearchableInfo(search_componentName)) } ~~~ 但是這里失敗了: ![](https://img.kancloud.cn/fb/09/fb09c29316232c35648c6aeb10736bd7_1649x183.png) 這里也就懶得繼續看源碼來看如何解決了。這里就不修改了!!!直接修改邏輯為查詢到數據,就跳轉到一個新的`Activity`: ~~~ fun processSearchData(intent: Intent?){ if(intent?.action == Intent.ACTION_SEARCH){ // 用戶點擊的數據在數據庫表MFNote對應的suggest_intent_query的值 val suggest_intent_query = intent.getStringExtra(SearchManager.QUERY) Log.e("TAG", "QUERY: ${suggest_intent_query}") // 直接跳轉到顯示Activity startActivity(Intent().setClass(this, TestActivity::class.java)) } } ~~~ # 3.6 清除搜索框文本 ~~~ fun processSearchData(intent: Intent?){ if(intent?.action == Intent.ACTION_SEARCH){ // 用戶點擊的數據在數據庫表MFNote對應的suggest_intent_query的值 val suggest_intent_query = intent.getStringExtra(SearchManager.QUERY) // 直接跳轉到顯示Activity if(!TextUtils.isEmpty(suggest_intent_query)){ // 清除搜索框文本,關閉鍵盤,關閉搜索框 searchAutoComplete?.setText("") searchAutoComplete?.clearFocus() val clazz = search.javaClass val declaredMethod = clazz.getDeclaredMethod("onCloseClicked") declaredMethod.setAccessible(true); declaredMethod.invoke(search) val searchResultsIntent = Intent() searchResultsIntent.apply { setClass(this@MainActivity, TestActivity::class.java) putExtra("suggest_intent_query", suggest_intent_query) } startActivity(searchResultsIntent) } } } ~~~ 至于`searchAutoComplete`來自反射: ~~~ // 通過反射設置只要有一個文字就觸發查詢 val clazz = search.javaClass val field = clazz.getDeclaredField("mSearchSrcTextView") field.isAccessible = true if(searchAutoComplete == null){ searchAutoComplete = field.get(search) as AutoCompleteTextView } searchAutoComplete?.threshold = 1 ~~~ 結果就可以做到返回后關閉鍵盤,清空搜索框,關閉搜索框。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看