MaterialDesign学习篇(五),使用SearchView的正确姿势

介绍

大多APP都具有搜索功能,但是大部分都是在标题栏中放置搜索的图标或者是不可输入的EditText,当点击的时候,开启另外一个界面进行搜索,但是网易云音乐在搜索本地音乐的时候,点击搜索按钮,就会出现输入框,点击返回时,又会再次收起,以前认为需要自己根据状态做布局的改变,最后发现原来有一个很方便好用的控件,叫做SearchView,现在开始学习下如何使用SearchView。

网易云音乐的效果如下:

使用SearchView

SearchView需要和Toolbar一起使用,如果不熟悉Toolbar的使用,可以查看我写过的介绍Toolbar的文章:

MaterialDesign学习篇(二),Toolbar、DrawerLayout的使用

创建带SearchView的menu

在res->menu文件夹中我们新建一个叫做menu_search_view.xml的文件,文件的内容为:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto">

    <!--右侧搜索操作条目-->
    <item
        android:id="@+id/action_search"
        android:title="@string/menu_search"
        app:actionViewClass="android.support.v7.widget.SearchView"
        app:showAsAction="always"/>

    <!--右侧设置条目,收起-->
    <item
        android:id="@+id/action_setting"
        android:title="@string/menu_setting"
        app:showAsAction="never" />

</menu>

其中第一个是搜索的条目,我们指定了它的actionViewClass="android.support.v7.widget.SearchView",这就表明它是一个SearchView,和其他的菜单条目不同,下面会给大家演示它的不同之处。

布局文件中使用Toolbar

<?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"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
>

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:background="@color/netease_red"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:title="我的音乐"
        app:titleTextColor="@android:color/white"
        />

</LinearLayout>

Activity中展示Toolbar和Menu

找到Toolbar对象,调用setSupportActionBar()方法,重写onCreateOptionsMenu()方法展示右侧菜单项

public class SearchViewActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_search_view);

        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_search_view, menu);

        //找到searchView
        MenuItem searchItem = menu.findItem(R.id.action_search);
        SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchItem);

        return super.onCreateOptionsMenu(menu);
    }
}

效果如图:

可以看到,右侧放置有搜索的图标和竖立的三点水(更多),搜索的图标并没有指定,是系统自带的,由于指定了actionViewClass属性为android.support.v7.widget.SearchView,所以该菜单项具有搜索的功能,点击后会展现出搜索框,如果输入框中有内容,当点击搜索框右侧的关闭时,会清除文本框中的内容,如果输入框中没有内容,点击关闭图标时,它会收起来,变成原来的搜索图标。

更改默认图标的颜色

上图中图标的颜色是黑色的,看起来是不是有些不堪入目,是不是很想改变它的颜色,改变菜单项图标的颜色不难,只需要在Activity的主题中,指定Toolbar菜单项图标的颜色:

<style name="SeachViewActivityTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="colorPrimary">@color/netease_red</item>
    <item name="colorPrimaryDark">@color/netease_red</item>
    <item name="colorAccent">@color/netease_red</item>
    <!--toolbar菜单项图标的颜色-->
    <item name="android:textColorSecondary">@android:color/white</item>
</style>

只需要设置android:textColorSecondary,指定Toolbar中菜单项图标的颜色,我们现在把它指定为white,效果如下:

是不是觉得好看多了,顿时觉得界面清新了许多。

设置SearchView的展开样式

一、让SearchView一开始就处于展开状态:

代码:

searchView.setIconified(false);//一开始处于展开状态

可以看到SearchView一开始处于展开的状态,而且关闭的图标也显示出来,当输入框中有内容的时候,点击关闭的图标是清除内容,当输入框中没有内容的时候,点击关闭图标是收起张开状态。

二、设置SearchView无法收起

代码:

searchView.setIconified(false);//设置searchView处于展开状态
searchView.onActionViewExpanded();// 当展开无输入内容的时候,没有关闭的图标

可以看到SearchView一开始处于展开的状态,但是关闭的图标一开始没有显示出来,所以无法收起展开状态,当输入框中有内容的时候,点击关闭的图标是清除内容。

三、设置搜索小图标的位置在框外

代码:

searchView.setIconified(false);//设置searchView处于展开状态
searchView.onActionViewExpanded();// 当展开无输入内容的时候,没有关闭的图标
searchView.setIconifiedByDefault(false);//默认为true在框内,设置false则在框外

可以看到,第三张图的效果和第二张图的差不多,只不过搜索的小图标是在输入框外而不是输入框内。

SearchView的监听

内容变化以及点击提交的监听

代码:

    searchView.setSubmitButtonEnabled(true);//显示提交按钮
    searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
        @Override
        public boolean onQueryTextSubmit(String query) {
            //提交按钮的点击事件
            Toast.makeText(SearchViewActivity.this, query, Toast.LENGTH_SHORT).show();
            return true;
        }

        @Override
        public boolean onQueryTextChange(String newText) {
            //当输入框内容改变的时候回调
            Log.i(TAG,"内容: " + newText);
            return true;
        }
    });

log截图:

上图中可以看到,输入框的右侧有一个">"图标,即提交按钮,按钮的点击事件在onQueryTextSubmit()方法中回调处理,这里我只是简单弹出搜索框中的内容,当输入框中的内容变化时,会在onQueryTextChange()方法中回调,这里我将变化的内容打印在控制台。

设置无内容时的提示文字

searchView.setQueryHint("输入歌曲名查找");//设置默认无内容时的文字提示

修改搜索图标

想要修改默认的搜索图标,需要在Activity的主题中修改,像刚才修改默认图标的颜色一样,需要在style.xml中对应Activity的主题中进行修改:

<style name="SeachViewActivityTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="colorPrimary">@color/netease_red</item>
    <item name="colorPrimaryDark">@color/netease_red</item>
    <item name="colorAccent">@color/netease_red</item>
    <!--toolbar菜单项图标的颜色-->
    <item name="android:textColorSecondary">@android:color/white</item>
    <!--修改searchView样式-->
    <item name="searchViewStyle">@style/SearchViewStyle</item>
</style>

<style name="SearchViewStyle" parent="Widget.AppCompat.SearchView">
    <item name="searchIcon">@mipmap/ic_search</item>
</style>

可以看到搜索图标变成自己指定的图标了,无论是展开还是收起状态,图标都改变了.

修改输入框文字提示的颜色和内容文字的颜色

 mSearchAutoComplete = (SearchView.SearchAutoComplete) mSearchView.findViewById(R.id.search_src_text);

 //设置输入框提示文字样式
 mSearchAutoComplete.setHintTextColor(getResources().getColor(android.R.color.white));//设置提示文字颜色
 mSearchAutoComplete.setTextColor(getResources().getColor(android.R.color.white));//设置内容文字颜色

可以看到,提示文字的颜色和内容文字的颜色都变成白色了。

去除搜索框中的图标

<style name="SeachViewActivityTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="colorPrimary">@color/netease_red</item>
    <item name="colorPrimaryDark">@color/netease_red</item>
    <item name="colorAccent">@color/netease_red</item>
    <!--toolbar菜单项图标的颜色-->
    <item name="android:textColorSecondary">@android:color/white</item>
    <!--修改searchView样式-->
    <item name="searchViewStyle">@style/SearchViewStyle</item>
</style>

<style name="SearchViewStyle" parent="Widget.AppCompat.SearchView">
    <item name="searchIcon">@mipmap/ic_search</item>
    <item name="searchHintIcon">@null</item>
</style>

指定SearchView样式中的searchHintIcon为null,即可去除搜索框中的图标,如图:

关联navigationIcon的点击

这里我们尝试做成跟网易云音乐一样,当搜索框处于展开的时候,点击返回键是收起SearchView,当SearchView处于收起时,点击是关闭当前Activity。

修改布局文件中的Toolbar,指定navigationIcon:

<android.support.v7.widget.Toolbar
    android:id="@+id/toolbar"
    android:background="@color/netease_red"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:title="本地音乐"
    app:titleTextColor="@android:color/white"
    app:navigationIcon="@mipmap/back"
    />

Activity中,设置navigationIcon的点击事件:

 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();
            }
        }
    });

设置navigationIcon的点击事件时,我们判断当前SearchView是否处于显示状态,通过调用SearchAutoComplete的isShown()方法,如果处于显示状态,则清除输入框中的内容,接着通过反射调用SearchView的onCloseClicked()方法,收起SearchView;如果SearchView处于收起状态,点击则是关闭当前Activity.现在是不是觉得很接近网易云音乐的搜索本地音乐的样子了。

修改navigationIcon和SearchView之间的距离

上图中navigationIcon和SearchView之间的距离过大,我们对其进行修改,需要在style.xml定义Toolbar的样式:

<!--NavigationIcon和标题之间的距离-->
<style name="ToolbarStyle" parent="Base.Widget.AppCompat.Toolbar">
    <item name="contentInsetStart">0dp</item>
    <item name="contentInsetStartWithNavigation">0dp</item>
</style>

在布局文件中,引用Toolbar的样式:

<android.support.v7.widget.Toolbar
    android:id="@+id/toolbar"
    style="@style/ToolbarStyle"
    android:background="@color/netease_red"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:title="本地音乐"
    app:titleTextColor="@android:color/white"
    app:navigationIcon="@mipmap/back"
    />

Toolbar的样式中,我们修改了navigationIcon和title之间的距离,将其修改为0,现在看起来navigationIcon和SearchView之间的距离是不是变小了,好看些了。

模仿网易云音乐搜索本地音乐功能

先看下效果:

修改布局文件,即Toolbar + ListView:

<?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"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
>

<android.support.v7.widget.Toolbar
    android:id="@+id/toolbar"
    style="@style/ToolbarStyle"
    android:background="@color/netease_red"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:title="本地音乐"
    app:titleTextColor="@android:color/white"
    app:navigationIcon="@mipmap/back"
    />

<ListView
    android:id="@+id/lv_music"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    />

</LinearLayout>

当搜索内容变化的时候,调用模糊查看本地音乐的功能:

mSearchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
        @Override
        public boolean onQueryTextSubmit(String query) {
            //提交按钮的点击事件
            Toast.makeText(SearchViewActivity.this, query, Toast.LENGTH_SHORT).show();
            return true;
        }

        @Override
        public boolean onQueryTextChange(String newText) {
            //当输入框内容改变的时候回调
            // Log.i(TAG,"内容: " + newText);
            quertMusic(newText);
            return true;
        }
    });

 /**
 * 模糊查找音乐
 * @param key
 */
private void quertMusic(String key) {
    String[] musics = new String[]{};
    if (!TextUtils.isEmpty(key)){
        musics = FileUtils.queryMusic(this, key);
    }
    ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, musics);
    mLvMusic.setAdapter(adapter);
}

FileUtils中,查找本地音乐数据库的queryMusic()方法:

/**
 * 根据歌名查看音乐
 * @param context 上下文
 * @param key 关键字
 * @return
 */
public static String[] queryMusic(Context context, String key) {
    ArrayList<String> nameList = new ArrayList<>();
    Cursor c = null;
    try {
        c = context.getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null,
                MediaStore.Audio.Media.DISPLAY_NAME + " LIKE '%" + key + "%'",
                null,
                MediaStore.Audio.Media.DEFAULT_SORT_ORDER);

        while (c.moveToNext()) {
            String path = c.getString(c.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA));// 路径

            if (!FileUtils.isExists(path)) {
                continue;
            }

            String name = c.getString(c.getColumnIndexOrThrow(MediaStore.Audio.Media.DISPLAY_NAME)); // 歌曲名
            nameList.add(name);
        }

    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if (c != null) {
            c.close();
        }
    }
    if (nameList.isEmpty()){
        return new String[]{};
    }
    return (String[])nameList.toArray(new String[nameList.size()]);
}

利用ContentResolver查找本地音乐数据库,这里只是简单查询出歌曲名,然后将歌曲的集合转换成数组,需要注意的是,如果是Android6.0以上,需要动态申请读取SD卡的权限:

 @Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
    setContentView(R.layout.activity_search_view);

    initView();
    initToolbar();
    requestPermission();
}

private void requestPermission() {
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){
        //如果还没有读取SD卡的权限,申请
        ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},REQ_PERMISSION);
    }
}

这里在初始化完毕的时候进行权限的判断和申请。

好的,到这里SearchView的相关用法已经介绍完毕了,需要源码的可以查看:

https://github.com/chaychan/MaterialDesignExercise

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容

  • 内容 抽屉菜单 ListView WebView SwitchButton 按钮 点赞按钮 进度条 TabLayo...
    小狼W阅读 1,611评论 0 10
  • 用两张图告诉你,为什么你的 App 会卡顿? - Android - 掘金 Cover 有什么料? 从这篇文章中你...
    hw1212阅读 12,691评论 2 59
  • 内容抽屉菜单ListViewWebViewSwitchButton按钮点赞按钮进度条TabLayout图标下拉刷新...
    皇小弟阅读 46,706评论 22 664
  • 热烈里透露出真诚,我记住了过去的这一份友谊。也是在深秋,黄昏轻风,树梢雨珠,把酒初聚。...
    冰夫阅读 52评论 0 0
  • 为什么都不能好好吃一顿饭呢?吃饭的时候感觉他都在有情绪,唉,看不透一些人,就好像是你跟他熟悉了和刚认识他的时候是两...
    我叫大芳阅读 178评论 0 0