亲爱的同学们我又来了,搬好小板凳准备开车了。。。
不知道大家平时都用什么听音乐,我个人比较喜欢网易云音乐 (不是做广告,但是我这是干啥呢?),不过现在网易云音乐不能停周董的歌了,实在有些。。。那天突然想起最近研究的MaterialDesign,就想到的网易云音乐的标题栏是怎么实现的。后来我就各种百度,中于功夫不负有心人,总算是被我刨出来了!其实网易云音乐使用的就是标题上面说的SearchView,其实就是一个搜索的View。那么怎么实现的呢?请听下回分解!
开个玩笑,同学们准备好,马上开车了。。。
本文知识点
- SearchView的介绍
- 实现网易云音乐的搜索功能
- 基本的搜索功能实现
- 页面的美化问题
- 一些常见的问题
先简单说明一下,这里主要是讲解SearchView怎么实现网易云音乐的标题栏,但是都是以来Toolbar的,如果你对Toolbar和menu不是很了解的话!
请看我公众号的这两篇文章(强势输出一波)
-
MeterialDesign系列文章(一)Toolbar的使用
-
Android中menu的使用集锦
上面很详细的讲解了关于Toolbar和menu的使用方法和注意事项!!!
1. SearchView的介绍
SearchView是和Toolbar联动,通过menu进行设置的搜索的控件(不知道我这么概括你能不能懂)。会在Toolbar的右侧出现一个搜索的按钮(系统自带的,也可以进行替换)。当你点击搜索按钮的时候,会出现相应的编辑框进行搜索。当你点击叉号的时候,本次搜索取消,还原成搜索按钮。
2. 网易云音乐的搜索功能
2.1 基本的搜索功能实现
这里针对menu做了一些修改,所以可能和你出现的基本效果不太一样,但是我会把相应的内容贴出来,这样便于像我一样的懒癌患者,能很快的实现效果。毕竟开发项目紧的时候我是不会管是怎么实现的!!!先看一下基本功能的效果图
相信你看了之前的那两篇文章的话,很快就能写出下面这个标题栏的。
- menu文件的代码
"1.0" encoding="utf-8"?>
复制代码
- 布局文件的代码
"1.0" encoding="utf-8"?>
"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">
"@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="#ff0000"
app:popupTheme="@style/ToolbarTheme"
app:navigationIcon="@mipmap/back_icon">
"@+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" />
复制代码
- 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 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属性,这个属性可以自己设置的。
- "searchViewStyle">@style/SearchViewStyle
复制代码
这里的图片就看你发挥了。。。
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!
如果你感兴趣,请关注我的二维码