android仿网易云搜索,MaterialDesign之SearchView解锁 仿网易云音乐搜索

原标题:MaterialDesign之SearchView解锁 仿网易云音乐搜索

本文作者

本文由CSDN_LQR投稿

CSDN_LQR的博客地址:

http://www.jianshu.com/u/f9de259236a3

SearchView是v7包中的一个兼容性控件,它可以单独使用,也可以配合menu+toolbar一起使用。本文将使用第二种方式,对SearchView进行探索。最后将通过代码实战,实现 “仿网易云音乐本地音乐搜索” 效果,带你全面解锁SearchView的UI定制及查询功能的实现。

先扔个效果图:

c72fc95d7d6f3f73ee2cb873234f5aba.gif

1

常规使用

本文重点是SearchView,所以对Toolbar的使用及注意事项在本文中将不会有过多的体现,如需了解可自行百度或直接查看本Demo源码(源码在文末)。

(1)在menu的xml文件中配置

要跟menu一起使用,就必须在menu的xml文件中对其中的一个item进行actionViewClass属性配置,如:

f676b3f662766049509541c0cb64b8e6.png

这个item跟普通item的差别在于使用了app:actionViewClass属性(注意是app:开头的!!!),这里使用的是兼容性控件里的SearchView,所以取值"android.support.v7.widget.SearchView"。

其中title的设置不会生效(一般设置了title的item,长按后会有弹出提示文字),这里去掉也无所谓。

(2)在onCreateOptionsMenu()中得到SearchView

我们知道menu在创建时会回调Activity中的onCreateOptionsMenu(Menu menu)方法,通过该方法可以得到Menu对象,而SearchView是Menu中item的一个actionView,actionView可以通过MenuItemCompat获取,故,通过Menu对象可以得到SearchView。

0826995d065c1cb0f939abd9777484da.png

到这里就可以看到效果了:

a65940dc8d4888aa647b76a72fb94d01.gif

(3)对SearchView进行设置

默认展开搜索框

手淘的首页搜索框是默认展开的,使用SearchView可以做一样的效果。此外,SearchView有三种默认展开的设置,效果上有略微不同,请结合注释与图片仔细观察。

7c908fa8e9b914c63f1b079436f8f032.png

按顺序效果依次如下:

-setIconified(false)-

611924ddc827cb164d5e62dbec97d4b9.gif

-setIconifiedByDefault(false)-

18f159a2d86784ac5547241452b71035.gif

-onActionViewExpanded()-

SearchView的常规设置//设置最大宽度mSearchView.setMaxWidth(500);//设置是否显示搜索框展开时的提交按钮mSearchView.setSubmitButtonEnabled(true);//设置输入框提示语mSearchView.setQueryHint("hint");

比较容易,直接看下效果:

a37aefd5c84c51255f9e53f6f2b7aad6.gif

SearchView的事件监听

SearchView提供的事件监听还是比较丰富的,一般常用的有打开搜索框按钮的点击事件、清空或关闭搜索框按钮的点击事件、搜索框文字变化事件等。

fe97e9fca4cb73bb1e18509b4c234d15.png

这个也比较容易,直接看下效果:

d44857ff94f5311ce14915adb78d1150.gif

以上就是SearchView给开发者提供的常规方法调用和属性设置,但是这并不能满足我们的开发需求。

因为开发中大部分设计师根据不管MaterialDesign的设计规范,所以大多数情况下需要根据UI设计稿自定义SearchView的样式了,这相对比较复杂,下面将通过实战来学习SearchView的样式自定义,以此来满足我们的开发需求。

2

实战

仿网易云音乐本地音乐搜索,先看下效果,然后开始实战:

(1)设置Toolbar

1)创建该界面的布局activity_search_view2.xml 指定Toolbar的高度、NaviagtionIcon、标题、字体等

3725cc0a6be4f591058ec310f16c4429.png

其中style指向的Toolbar.MyStyle是设置标题与NavigationIcon的距离,titleTextAppearance指向的Toolbar.TitleText是设置标题文字大小。

在style.xml中创建Toolbar的自定义样式

c36cd77dfa3b33970fa378591b8000d5.png

如果不设置的话,效果不好,NavigationIcon和Toolbar的标题之前的间距看起来很大,下面看下设置前后的差别:

66183e9f97a93cd77f3b01abc9a0828a.png

a09d080009d0bba48314dc03120cc8e3.png

2)设置去除ActionBar的主题 在Style.xml中创建无ActionBar的主题,并设置主题背景色

b1ed2f05cf0bd1246cd9daab6bcccc68.png

不设置textColorSecondary的话,默认menu的item图标是黑色,下面看下设置前后的差别:

34d2b7b0432cb00b843ede157872dd45.png

1d69fcd273a5edab6aa93c298b149929.png

为Activity设置主题

380468e627ef2f2d8e07705ffa8774d8.png

3)在Activity中设置Toolbar的代码如下:

67756b88fa23cb5513bc4a94940818ef.png

(2)设置Menu

1)创建菜单布局search_view.xml

跟之前的代码相比,只是多加了几个item而已。

09a98ce75c6e92f4880b0db193fc63a0.png

2)在Activity中设置Menu的代码如下:

a173d9f2b2bae5982ef8df2860c4f96c.png

到这里,除了搜索框(SearchView)以外,整个布局的效果大体上都实现了:

3

定制SearchView样式

接下来要实现的样式自定义有:

17e2e5736a643c577bd7418dab3f6b44.png

重点来了,我们先来分析一下。SearchView本身不向外提供 “关闭搜索框” 和 “设置搜索框左边的搜索图标” 等方法,所以需要通过其他的方式来实现样式自定义。

考虑:

如果SearchView的布局结构是通过xml布局文件来实现的,那么可以通过SearchView.findViewById()的方式得到其中的部分或所有的控件;如果是通过代码动态添加的话,那么可以通过反射的方式得到我们需要的控件,进而对控件进行样式设置。

结论:

实现证明,SearchView的布局结构就是使用xml布局文件实现的,该xml文件名为abc_search_view.xml,且基本上每个控件都有id,这样就可以拿到需要的控件来实现样式自定义了。

(1)点击返回按钮,退出搜索框(若搜索框显示的话)

SearchView本身没有提供关闭搜索框的方法(反正我是没找到啊~~),不过SearchView中正好有一个onCloseClicked()方法是用来关闭搜索框,我们可以通过反射来调用该方法,先来理解下该方法都做了什么,onCloseClicked()的代码如下:

9b087a96619a46303fc59e66275046ed.png

这里要考虑到,当搜索框显示时,按下Toolbar的返回按钮关闭搜索框,否则就关闭当前界面。因为搜索框也有id,所以我们可以通过id可以得到搜索框控件,用来判断当前搜索框的显隐状态。

结合SearchView内部的onCloseClicked()方法,最后Toolbar返回按钮的点击事件代码可以这么写:

ccfa87d604b3945efcf207fbfbbbeb87.png

0683124bd444f4942216a3bfc860916a.gif

(2)隐藏搜索框左边的搜索图标

搜索框中左边的搜索图标不是一个控件,所以没办法通过id得到,但好在可以通过设置style的方式来修改SearchView所有的图标。

方法也很简单,只需创建一个style(这里取名Widget.SearchView)继承自Widget.AppCompat.SearchView,然后替换需要修改的属性即可。先看下Widget.AppCompat.SearchView的父级Base.Widget.AppCompat.SearchView吧:

bd8b4cd5f7d57ec4edf7d48aa77067ce.png

可以看到,这个父级style提供了SearchView中几乎所有的Icon属性,这意味着在图标定制上可以有很大拓展性。其中,layout是指定SearchView的布局,原始布局就是abc_search_view.xml,我们一般不会去动这个属性。

这里我们只需要去掉搜索框左边的图标(即:searchHintIcon),直接设置为@null就好了,如下修改style文件中的Widget.SearchView主题:

b5229165b88e2df1840c6e50cd01dec3.png

89da6975085eb67c1a4dbde76de03ba0.png

(3)设置搜索框的提示文字

修改提示文字内容

修改搜索框提示文字的方式有两种,一种就是修改SearchView的style,如上一步中,修改Widget.AppCompat.SearchView的defaultQueryHint属性;另一种方式是调用SearchView的setQueryHint()来修改。

这两种方式都可以,如果同时用这两种方式来设置搜索框的提示语,则最终的提示内容将以代码设置方式为主。

94610b895a81fa5bf964ea30210159de.png

058b2b3f18eb3e4610588f54d68a2271.png

修改提示文字样式

SearchView也没有提供任何直接修改搜索框提示文字样式的方法,但既然我们可以通过id得到搜索框控件,那设置提示文字的样式便不是什么问题了,代码如下:

5df0b3c1bd04f8683d02880339773a89.png

b487f4d40f9d60d8b7bc307d81256378.png

(4)根据搜索框中有无文字,来显隐搜索框右边的叉叉

这个有点像searchView.onActionViewExpanded()的效果,唯一的区别就是搜索框不能是默认展开的,这要怎么办呢?通过观察onActionViewExpanded()的源码,可以发现该方法中调用了setIconified(false)!!!

再联想到setIconified(false)本身就有让搜索框默认展开的效果,这是不是意味着,只要让onActionViewExpanded()的setIconified(false)改为setIconified(true)就好了呢?答案是是的。

而且不需要重写SearchView,因为onActionViewExpanded()和setIconified(true)是可以搭配使用的,只要依次调用这两个方法就可以实现这种效果了,代码如下:

bca1555e3dcb0013b8a54c14d86099e6.png

2350fe82d03059d60f4b3fedadaf85f8.gif

4

实现搜索提示功能

上面我们已经学习了SearchView的UI定制,下面将通过SearchView自身或结合ListView的方式(RecyclerView应该也一样吧,还没试过)直接学习SearchView搜索提示功能的实现,继续完善 “仿网易云音乐本地音乐搜索” 效果。

(1)弹出式搜索提示

SearchView本身的搜索框就是AutoCompleteTextView的一个子类,有图有真相。

a4a4bd288fd06427d12fc886e3dbd420.png

df98a9eede7680adb4898ee45a704940.png

AutoCompleteTextView是可以通过设置适配器来实现文本补全提示功能的,所以,SearchView中的搜索框一样也可以,不过SearchView提供了setSuggestionsAdapter()方法可以直接为搜索框设置适配器,需要注意的是,这个适配器必须跟数据库的Cursor对象一起使用,例如:

796384b44348d521870333b706cb3952.png

一般开发中遇到的需求是一边输入关键字一边显示搜索结果,所以需要监听搜索框的文字输入,一旦文字变化就查询数据库,更新搜索结果,所以代码可以这么写:

2e49a2ffd8e20e924099dc329c78bd6b.png

对于SimpleCursorAdapter的使用,不熟悉的自己百度学习吧,下面看效果:

2b106e7653264e0f78aa4e8c76c44814.gif

可以发现,当输入第一个文字"a"时,没有什么反应,当输入第二个文字"a"时,弹出了一个列表弹窗,这是由于AutoCompleteTextView本身默认触发查询动作的条件就是该控件中的文字至少要2个以上,如果我们想修改成只要有一个文字就触发查询的话,则可以这么做:

拿到SearchView中搜索框控件

调用setThreshold()设置触发查询的字数

直接上代码:

4e6bad02e29891618ede146ad2bc4e25.png

再看下效果:

34bad74cd35a07c25195c98f24f4cc47.gif

好了,弹出式搜索功能做完了,下面贴出条目布局item_layout.xml和queryData()方法的代码实现:

① item_layout.xml

24f2d75022a64a24e20af6ddcb21b2be.png

② queryData()

只是简单的创建一个数据库(music.db),库中有一张tb_music表,表中有_id和name两个字段,然后填充数据,查询数据,相对比较简单,这里就不做过多解释了。

4a3964b085124282dd71e249f8c5fbb9.png

(2)结合ListView实现搜索提示

虽然上面已经实现了搜索提示的功能,但网易云音乐本地搜索出来的结果并不是弹出式的,而是在SearchView下方以列表的方式呈现,要做到这样的效果,就必需让SearchView结合ListView一起使用。其实这并不难,因为AutoCompleteTextView设置的适配器跟ListView要设置的适配器是一样的,直接将上边的适配器设置给ListView即可。

f3a3b64a7a168be827a7ee931d596784.png

这样就完成了,虽然样式上是丑了点,但,那又怎样,呵呵~

b120d80aac26a226afe61f62b3d34fb6.gif

Demo链接

https://github.com/GitLqr/MaterialDesignDemo

如果你有想学习的文章直接留言,我会整理征稿。如果你有好的文章想和大家分享欢迎投稿,直接向我投递文章链接即可。返回搜狐,查看更多

责任编辑:

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
和导航栏的联动,你需要在布局文件中添加一个SearchView和NavigationView,然后在代码中实现它们的联动。具体实现可以参考以下代码: 布局文件: ``` <androidx.drawerlayout.widget.DrawerLayout android:id="@+id/drawer_layout" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <androidx.appcompat.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" android:elevation="4dp" android:theme="@style/ThemeOverlay.AppCompat.ActionBar" /> <androidx.appcompat.widget.SearchView android:id="@+id/search_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:iconifiedByDefault="false" android:queryHint="Search" /> <FrameLayout android:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout> <com.google.android.material.navigation.NavigationView android:id="@+id/navigation_view" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="start" app:headerLayout="@layout/nav_header" app:menu="@menu/nav_menu" /> </androidx.drawerlayout.widget.DrawerLayout> ``` 代码实现: ``` // 设置Toolbar Toolbar toolbar = findViewById(R.id.toolbar); setSupportActionBar(toolbar); // 设置SearchView SearchView searchView = findViewById(R.id.search_view); searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { @Override public boolean onQueryTextSubmit(String query) { // 处理搜索事件 return false; } @Override public boolean onQueryTextChange(String newText) { // 处理搜索框文本变化事件 return false; } }); // 设置NavigationView NavigationView navigationView = findViewById(R.id.navigation_view); navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() { @Override public boolean onNavigationItemSelected(@NonNull MenuItem item) { // 处理导航栏菜单点击事件 return false; } }); // 设置DrawerLayout DrawerLayout drawerLayout = findViewById(R.id.drawer_layout); ActionBarDrawerToggle toggle = new ActionBarDrawerToggle( this, drawerLayout, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close); drawerLayout.addDrawerListener(toggle); toggle.syncState(); ``` 这样就可以实现SearchView和NavigationView的联动了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值