親愛的同學們我又來了,搬好小板凳準備開車了。。。
不知道大家平時都用什麼聽音樂,我個人比較喜歡網易雲音樂 (不是做廣告,但是我這是幹啥呢?),不過現在網易雲音樂不能停周董的歌了,實在有些。。。那天突然想起最近研究的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!
如果你感興趣,請關注我的二維碼