Android中SearchView的使用

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

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

開玩笑啊!!!

開個玩笑,同窗們準備好,立刻開車了。。。app

本文知識點

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

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

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

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

1. SearchView的介紹

SearchView是和Toolbar聯動,經過menu進行設置的搜索的控件(不知道我這麼歸納你能不能懂)。會在Toolbar的右側出現一個搜索的按鈕(系統自帶的,也能夠進行替換)。當你點擊搜索按鈕的時候,會出現相應的編輯框進行搜索。當你點擊叉號的時候,本次搜索取消,還原成搜索按鈕。google

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

2.1 基本的搜索功能實現

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

原諒個人配色

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

  • 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!

若是你感興趣,請關注個人二維碼

筆墨Android
相關文章
相關標籤/搜索