Android中SearchView的使用

weixin_33809981發表於2018-04-23

親愛的同學們我又來了,搬好小板凳準備開車了。。。

不知道大家平時都用什麼聽音樂,我個人比較喜歡網易雲音樂 (不是做廣告,但是我這是幹啥呢?),不過現在網易雲音樂不能停周董的歌了,實在有些。。。那天突然想起最近研究的MaterialDesign,就想到的網易雲音樂的標題欄是怎麼實現的。後來我就各種百度,中於功夫不負有心人,總算是被我刨出來了!其實網易雲音樂使用的就是標題上面說的SearchView,其實就是一個搜尋的View。那麼怎麼實現的呢?請聽下回分解!

開個玩笑,同學們準備好,馬上開車了。。。

本文知識點

  • SearchView的介紹
  • 實現網易雲音樂的搜尋功能
    • 基本的搜尋功能實現
    • 頁面的美化問題
    • 一些常見的問題

先簡單說明一下,這裡主要是講解SearchView怎麼實現網易雲音樂的標題欄,但是都是以來Toolbar的,如果你對Toolbar和menu不是很瞭解的話!

請看我公眾號的這兩篇文章(強勢輸出一波)

上面很詳細的講解了關於Toolbar和menu的使用方法和注意事項!!!

1. SearchView的介紹

SearchView是和Toolbar聯動,通過menu進行設定的搜尋的控制元件(不知道我這麼概括你能不能懂)。會在Toolbar的右側出現一個搜尋的按鈕(系統自帶的,也可以進行替換)。當你點選搜尋按鈕的時候,會出現相應的編輯框進行搜尋。當你點選叉號的時候,本次搜尋取消,還原成搜尋按鈕。

2. 網易雲音樂的搜尋功能

2.1 基本的搜尋功能實現

這裡針對menu做了一些修改,所以可能和你出現的基本效果不太一樣,但是我會把相應的內容貼出來,這樣便於像我一樣的懶癌患者,能很快的實現效果。畢竟開發專案緊的時候我是不會管是怎麼實現的!!!先看一下基本功能的效果圖

相信你看了之前的那兩篇文章的話,很快就能寫出下面這個標題欄的。

  • menu檔案的程式碼
<?xml version="1.0" encoding="utf-8"?>
<!--仿網易雲音樂的menu實現-->
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <item
        android:id="@+id/search"
        android:icon="@drawable/ic_search_black_24dp"
        android:title="搜尋"
        app:actionViewClass="android.support.v7.widget.SearchView"
        app:showAsAction="always" />

    <item
        android:id="@+id/other"
        android:title="其他內容"
        app:showAsAction="never" />
</menu>
複製程式碼
  • 佈局檔案的程式碼
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:orientation="vertical"
    tools:context="com.jinlong.newmaterialdesign.toolbar.YunActivity">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="#ff0000"
        app:popupTheme="@style/ToolbarTheme"
        app:navigationIcon="@mipmap/back_icon">

        <TextView
            android:id="@+id/tv_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:text="雲Toolbar的實現"
            android:textColor="@android:color/white"
            android:textSize="18sp" />
    </android.support.v7.widget.Toolbar>

</LinearLayout>
複製程式碼
  • Activity中的程式碼
public class YunActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_yun);

        initToolbar();
    }

    private void initToolbar() {
        Toolbar toolbar = findViewById(R.id.toolbar);
        toolbar.setTitle("");
        setSupportActionBar(toolbar);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater menuInflater = getMenuInflater();
        menuInflater.inflate(R.menu.menu_yun,menu);
        return super.onCreateOptionsMenu(menu);
    }
}
複製程式碼

上面程式碼跑一下,緊接著就可以看見上面的內容了!

2.1.1 搜尋按鈕的初始化和監聽問題

  • 初始化SearchView

    因為在初始化SearcheView,需要對相應的menu進行操作,所以一般都會在onCreateOptionsMenu(Menu menu)中進行獲取。具體程式碼如下:

        //獲取SearchView物件
        MenuItem searchItem = menu.findItem(R.id.search);
        mSearchView = (SearchView) searchItem.getActionView();
複製程式碼

這裡注意一點,就是在初始化SearchView的時候,也可以使用MenuItemCompat.getActionView(searchItem);進行獲取的,只不過是過時了。。。所以見到了不要說不知道就行

  • 相應的監聽setOnQueryTextListener(OnQueryTextListener listener)
setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String query) {
                //在文字改變的時候回撥,query是改變之後的文字
                return false;
            }

            @Override
            public boolean onQueryTextChange(String newText) {
                //文字提交的時候哦回撥,newText是最後提交搜尋的文字
                return false;
            }
        });
複製程式碼

上面的內容可以實現簡單的搜尋了?其實我個人覺得這一個監聽還不夠?為什麼這麼說呢?因為你想要控制Fragment的切換,沒有相應的時間點,或者說是沒找到時機進行Fragment的切換問題,當時我想了好久,後來看見原始碼的時候,我才發現,其實這種時機google工程是早就替我們想好了,其實我覺得我們能想到的,google工程師會替我們實現的!

  • setOnSearchClickListener(OnClickListener listener) 在點選Search那個圖示的時候回撥的方法。
  • setOnCloseListener(OnCloseListener listener) 在點選搜尋後那個叉號的時候回撥的方法。

這樣就存在相應的時間點了,你在進來的時候開啟一個事物,放進去一個Fragment(這裡如果你想加動畫效果的話,你可以使用ViewPager,然後通過設定顯示那個的方法進行切換.其實事物也是可以設定動畫的,看你怎麼選擇吧)。當你點選關閉的時候。再將之前的Fragment替換掉就可以了。這裡為了大家能更好的理解,我還是用程式碼實現一下吧!先看下效果(虛擬機器錄得有點渣!)

  • 其實xml中沒有什麼變化,就不貼了!
  • Activity中的程式碼是最主要的,程式碼如下:
public class YunActivity extends AppCompatActivity {

    private static final String TAG = YunActivity.class.getSimpleName();
    private SearchView mSearchView;
    private ViewPager mVpContent;
    private SearchFragment mSearchFragment;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_yun);

        Log.e(TAG, "onCreate: ");

        initToolbar();
        initViewPager();
    }


    private void initToolbar() {
        Toolbar toolbar = findViewById(R.id.toolbar);
        toolbar.setTitle("");
        setSupportActionBar(toolbar);
    }

    private void initViewPager() {
        mVpContent = findViewById(R.id.vp_content);

        List<Fragment> list = new ArrayList<>();
        DefaultFragment defaultFragment = new DefaultFragment();
        list.add(defaultFragment);
        mSearchFragment = new SearchFragment();
        list.add(mSearchFragment);

        MainVPAdapter adapter = new MainVPAdapter(getSupportFragmentManager(), list);

        mVpContent.setAdapter(adapter);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        Log.e(TAG, "onCreateOptionsMenu: ");
        MenuInflater menuInflater = getMenuInflater();
        menuInflater.inflate(R.menu.menu_yun, menu);

        //獲取SearchView物件
        MenuItem searchItem = menu.findItem(R.id.search);
        mSearchView = (SearchView) searchItem.getActionView();

        //設定相應的監聽,文字變化的監聽
        mSearchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String query) {
                //在文字改變的時候回撥,query是改變之後的文字
                mSearchFragment.setSearchStr(query);
                return false;
            }

            @Override
            public boolean onQueryTextChange(String newText) {
                //文字提交的時候哦回撥,newText是最後提交搜尋的文字
                return false;
            }
        });

        mSearchView.setOnSearchClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //開始搜尋的時候,設定顯示搜尋頁面
                mVpContent.setCurrentItem(1);
            }
        });


        mSearchView.setOnCloseListener(new SearchView.OnCloseListener() {
            @Override
            public boolean onClose() {
                //關閉搜尋按鈕的時候,設定顯示預設頁面
                mVpContent.setCurrentItem(0);
                return false;
            }
        });

        return super.onCreateOptionsMenu(menu);
    }
}
複製程式碼

這裡最主要的就是那幾個監聽,只要你理解了那幾個監聽的話基本上就沒有問題了。

  • Fragment中的程式碼:
public class SearchFragment extends Fragment {


    private TextView mTvSearch;

    public SearchFragment() {
        // Required empty public constructor
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        // Inflate the layout for this fragment

        View rootView = inflater.inflate(R.layout.fragment_search, container, false);

        mTvSearch = rootView.findViewById(R.id.tv_search);
        return rootView;
    }
    
    /**
     * 搜尋的內容
     */
    public void setSearchStr(String query) {
        if (!TextUtils.isEmpty(query))
            mTvSearch.setText("搜尋的內容是" + query);
    }
}
複製程式碼

這樣就能實現相應的效果了。怎麼樣?不錯吧!!!

2.2 介面的美化問題

2.2.1 預設的提示文字

上面的圖是沒有提示文字時候顯示的樣子,怎麼新增提示文字呢?

searchView.setQueryHint("相應的提示內容");
複製程式碼

通過上面的程式碼就可以新增搜尋的提示文字了。

2.2.2 搜尋按鈕不消失

這個搜尋按鈕是在輸入框的內部,當你設定內容的時候,搜尋按鈕會消失。這個我感覺我描述的不太正確,管他呢?你們理解就好。。。

  • setIconifiedByDefault(boolean iconified) 這個Api主要是控制搜尋按鈕是否在輸入框內部的,true代表在內部顯示,false代表在外部顯示

2.2.3 搜尋按鈕取消關閉圖示的問題

有的產品經理總會有奇葩的需求,想要去掉那個搜尋後面的叉號。說不人性。。。只能默默的改了。。。其實我的內心是崩潰的。。。

  • onActionViewExpanded() 設定關閉圖示不顯示的Api

雖然你能關閉這個圖示,但是這樣就存在一個問題了,之前寫好的關閉切換Fragment的操作在這裡就會失效了。怎麼解決呢?想了半天,只有處理返回事件了,要不我根本就沒有辦法知道使用者真麼時候搜尋完成啊?那就只有什麼時候執行返回操作什麼時候算他結束了唄!

        toolbar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mSearchAutoComplete.isShown()) {
                    try {
                        mSearchAutoComplete.setText("");//清除文字
                        //利用反射呼叫收起SearchView的onCloseClicked()方法
                        Method method = mSearchView.getClass().getDeclaredMethod("onCloseClicked");
                        method.setAccessible(true);
                        method.invoke(mSearchView);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                } else {
                    finish();
                }
            }
        });
複製程式碼

加上這段程式碼的話,通過反射拿到SearchView的onDloseClicked(),呼叫一下就可以了

2.2.4 搜尋欄的預設展開問題

產品又說了,進到這個頁面,預設應該是顯示搜尋對話方塊的,使用者少操作一步,使用者體驗好,當時我就說了。那使用者就要那樣呢?產品說那樣的奇葩使用者不用管。。。(當時的我啊!滿腦袋黑線)

  • setIconified(boolean iconify) 設定搜尋輸入框是否是展開的,這裡注意啊!false代表展開,true代表關閉狀態

2.2.5 修改搜尋圖示或者去掉圖示

老根產品過不去也不行吧!這裡自己看了看搜尋圖示覺得小了,想更改一下!怎麼辦呢?

就是在頁面的Activity的主題中,新增相應的searchViewStyle屬性,這個屬性可以自己設定的。

    <!--SearchView的主題設定-->
    <item name="searchViewStyle">@style/SearchViewStyle</item>
        
    <!--SearchView的主題設定-->
    <style name="SearchViewStyle" parent="Widget.AppCompat.SearchView">
        <!--修改圖示的圖片-->
        <item name="searchIcon">@mipmap/ic_directions_bike_white_24dp</item>
        <!--去掉圖示-->
        <!--<item name="searchHintIcon">@null</item>-->
    </style>        
複製程式碼

這裡的圖片就看你發揮了。。。

2.2.6 修改文字顏色

當你覺得輸入框的文字或者提示的文字是黑色比較難看的時候,那麼你可以像下面這樣修改

        //修改searchView的文字顏色
        SearchView.SearchAutoComplete mSearchAutoComplete = mSearchView.findViewById(R.id.search_src_text);
        //設定輸入框內提示文字樣式
        mSearchAutoComplete.setHintTextColor(getResources().getColor(android.R.color.white));//設定提示文字顏色
        mSearchAutoComplete.setTextColor(getResources().getColor(android.R.color.white));//設定內容文字顏色
複製程式碼

不知道還有沒有什麼其他的了,我感覺有了這些對付你們產品經理就已經足夠了,不行桌子上放把刀、要不放個二維碼啥的就可以了。。。

希望我的文章對你有幫助!希望我們共同進步。。。see you!

如果你感興趣,請關注我的二維碼

相關文章