SearchView 学习_0

来源:互联网 发布:iphone随机抽奖软件 编辑:程序博客网 时间:2024/06/02 03:51

1. 基本原理:SearchView是android中一个搜索框组件,它不是一个单独的view,而是一个LinearLayout布局,包括表示Search图标和清除图标等其它图标的imageView、具有下拉建议列表的AutoCompleteTextView等,有时候我们需要对SearchView做一些特定的修改,而SearchView本身却又没有提供相关的接口,这时需要对SearchView进行自顶向下的深度遍历,提取它的每一个子孙view,如果只要对特定类型的view进行修改,只需根据view的类型来提取(viewinstanceof XXXView),若要提取特定的某一个view,则需要知道该view的id号,可以从SearchView源代码找到。

search_view.xml:
<LinearLayout    xmlns:android="http://schemas.android.com/apk/res/android"    android:id="@+id/search_bar"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="horizontal"    >    <!-- This is actually used for the badge icon *or* the badge label (or neither) -->    <TextView        android:id="@+id/search_badge"        android:layout_width="wrap_content"        android:layout_height="match_parent"        android:gravity="center_vertical"        android:layout_marginBottom="2dip"        android:drawablePadding="0dip"        android:textAppearance="?android:attr/textAppearanceMedium"        android:textColor="?android:attr/textColorPrimary"        android:visibility="gone"    />    <ImageView        android:id="@+id/search_button"        style="?android:attr/actionButtonStyle"        android:layout_width="wrap_content"        android:layout_height="match_parent"        android:layout_gravity="center_vertical"        android:src="?android:attr/searchViewSearchIcon"        android:contentDescription="@string/searchview_description_search"    />    <LinearLayout        android:id="@+id/search_edit_frame"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_weight="1"        android:layout_gravity="center_vertical"        android:layout_marginTop="4dip"        android:layout_marginBottom="4dip"        android:layout_marginLeft="8dip"        android:layout_marginRight="8dip"        android:orientation="horizontal">        <ImageView            android:id="@+id/search_mag_icon"            android:layout_width="@dimen/dropdownitem_icon_width"            android:layout_height="wrap_content"            android:scaleType="centerInside"            android:layout_marginLeft="@dimen/dropdownitem_text_padding_left"            android:layout_gravity="center_vertical"            android:src="?android:attr/searchViewSearchIcon"            android:visibility="gone"        />        <!-- Inner layout contains the app icon, button(s) and EditText -->        <LinearLayout            android:id="@+id/search_plate"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_weight="1"            android:layout_gravity="center_vertical"            android:orientation="horizontal"            android:background="?android:attr/searchViewTextField">            <view class="android.widget.SearchView$SearchAutoComplete"                android:id="@+id/search_src_text"                android:layout_height="36dip"                android:layout_width="0dp"                android:layout_weight="1"                android:minWidth="@dimen/search_view_text_min_width"                android:layout_gravity="bottom"                android:paddingLeft="@dimen/dropdownitem_text_padding_left"                android:paddingRight="@dimen/dropdownitem_text_padding_right"                android:singleLine="true"                android:ellipsize="end"                android:background="@null"                android:inputType="text|textAutoComplete|textNoSuggestions"                android:imeOptions="actionSearch"                android:dropDownHeight="wrap_content"                android:dropDownAnchor="@id/search_edit_frame"                android:dropDownVerticalOffset="0dip"                android:dropDownHorizontalOffset="0dip"                android:contentDescription="@string/searchview_description_query"            />            <ImageView                android:id="@+id/search_close_btn"                android:layout_width="wrap_content"                android:layout_height="match_parent"                android:paddingLeft="8dip"                android:paddingRight="8dip"                android:layout_gravity="center_vertical"                android:background="?android:attr/selectableItemBackground"                android:src="?android:attr/searchViewCloseIcon"                android:focusable="true"                android:contentDescription="@string/searchview_description_clear"            />        </LinearLayout>        <LinearLayout            android:id="@+id/submit_area"            android:orientation="horizontal"            android:layout_width="wrap_content"            android:layout_height="match_parent"            android:background="?android:attr/searchViewTextFieldRight">                <ImageView                android:id="@+id/search_go_btn"                android:layout_width="wrap_content"                android:layout_height="match_parent"                android:layout_gravity="center_vertical"                android:paddingLeft="16dip"                android:paddingRight="16dip"                android:background="?android:attr/selectableItemBackground"                android:src="?android:attr/searchViewGoIcon"                android:visibility="gone"                android:focusable="true"                android:contentDescription="@string/searchview_description_submit"            />            <ImageView                android:id="@+id/search_voice_btn"                android:layout_width="wrap_content"                android:layout_height="match_parent"                android:layout_gravity="center_vertical"                android:paddingLeft="16dip"                android:paddingRight="16dip"                android:src="?android:attr/searchViewVoiceIcon"                android:background="?android:attr/selectableItemBackground"                android:visibility="gone"                android:focusable="true"                android:contentDescription="@string/searchview_description_voice"            />        </LinearLayout>    </LinearLayout></LinearLayout>
<h2>2. 我的使用格式:</h2><div>     根据我自己百度的资料,searchview有两种使用方式:1:放置到actionBar的位置。2:直接放置到布局中。自己跑了两个程序,感觉searchview放哪里都一样。</div><div>     <strong>下面以放置到布局为例:</strong></div><div>      程序功能:实现一个SD卡的浏览器功能。listview中的数据就是当前目录下所有文件的(图标+文件名)。在搜索框输入搜索文本,listview内的数据刷新,只显示含义搜索文本的条目。(程序有点小bug,部分功能没实现,但能够说明searchview的大多数的基本用法)</div><div>       下面的代码copy到程序就可跑(文件名字有需要自己改动的地方:布局代码文件的文件名和主程序的文件名,图片资源需你自己更换一下)</div><div>           布局代码:<pre style="font-size: 9pt; color: rgb(169, 183, 198); font-family: 宋体; background-color: rgb(43, 43, 43);"><span style="color: rgb(152, 118, 170); "><em>activity_sdpathbrowse1.xml</em></span><span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(240, 240, 240);">              </span>
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical">    <RelativeLayout        android:layout_width="match_parent"        android:layout_height="45dp"        android:background="#000000">        <ImageView            android:id="@+id/iv_back"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_centerVertical="true"            android:padding="10dp"            android:src="@mipmap/back" />        <TextView            android:id="@+id/tv_path"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_centerVertical="true"            android:layout_toRightOf="@+id/iv_back"            android:text="555555555555555555"            android:textColor="#ffffff" />    </RelativeLayout>    <LinearLayout        android:layout_width="fill_parent"        android:layout_height="60dp"        android:background="#f2f2f2f2"        android:orientation="vertical">        <SearchView            android:id="@+id/sv_"            android:layout_width="match_parent"            android:layout_height="match_parent"            android:layout_margin="8dp"            android:background="@drawable/shape_bg_search"            android:imeOptions="actionSearch"            android:inputType="text"            android:queryHint="请输入您要查找的内容"            tools:ignore="NewApi" />    </LinearLayout>    <ListView        android:id="@+id/lv_list"        android:layout_width="match_parent"        android:layout_height="wrap_content"></ListView></LinearLayout>
主程序代码:

package com.SDPathBrowse;import java.io.File;import java.io.IOException;import java.lang.reflect.Field;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;import android.annotation.SuppressLint;import android.app.Activity;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.os.Bundle;import android.os.Environment;import android.text.TextUtils;import android.util.Log;import android.view.View;import android.view.View.OnClickListener;import android.view.ViewGroup;import android.widget.AdapterView;import android.widget.AdapterView.OnItemClickListener;import android.widget.BaseAdapter;import android.widget.Filter;import android.widget.Filterable;import android.widget.ImageView;import android.widget.LinearLayout;import android.widget.ListView;import android.widget.RelativeLayout;import android.widget.SearchView;import android.widget.TextView;import android.widget.Toast;import android.view.LayoutInflater;import android.view.inputmethod.InputMethodManager;import engineering.R;/** * @version 1.0 */@SuppressLint("NewApi")public class SDPathBrowse1 extends Activity implements SearchView.OnQueryTextListener {    //显示本路径下所有的文件夹和文件.    ListView listView;    //标题头,显示当前路径.    TextView textView;    // 记录当前的父文件夹    File currentParent;    // 记录当前路径下的所有文件的文件数组    File[] currentFiles;    //返回图标    ImageView parent;    SearchView sv_;    //listItems存储listview要加载的数据,根据serachView的输入,listView加载部分数据或全部数据.    List<Map<String, Object>> listItems;    //tmplistItems是listItem全部数据的拷贝。    List<Map<String, Object>> tmplistItems;    MyAdapter myAdapter;    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_sdpathbrowse1);        initView();        initData();        initListener();    }    public void initView() {        // 获取列出全部文件的ListView        listView = (ListView) findViewById(R.id.lv_list);        listView.setTextFilterEnabled(true);        //标题头,显示当前路径.        textView = (TextView) findViewById(R.id.tv_path);        // 返回上一级目录的 图标        parent = (ImageView) findViewById(R.id.iv_back);        sv_ = (SearchView) findViewById(R.id.sv_);        //searchView输入后 右面有搜索按钮.false则没有.        sv_.setSubmitButtonEnabled(false);        //搜索图标是否在输入框中        sv_.setIconifiedByDefault(true);        // 创建一个List集合,List集合的元素是Map        listItems = new ArrayList<Map<String, Object>>();        tmplistItems = new ArrayList<Map<String, Object>>();        //用到的数据集合(listItems)在本类中是全局变量,adapter类写到了同一个文件中。若不在同一个文件中,adapter的构造函数需传递数据集合,用于本文件的逻辑就需要改变。        myAdapter = new MyAdapter(this);        listView.setAdapter(myAdapter);    }    public void initData() {        // 获取系统的SD卡的目录,两段代码都可。        //File root = new File("/mnt/sdcard/");        File root = Environment.getExternalStorageDirectory();        Log.i("lyw", root.toString());//storage/emulated/0        // 如果 SD卡存在        if (root.exists()) {            currentParent = root;            //获取当前文件夹下的所有文件和文件夹            currentFiles = root.listFiles();            trimCurrentFiles(currentFiles);        }    }    @SuppressLint("NewApi")    public void initListener() {        // 为ListView的列表项的单击事件绑定监听器        listView.setOnItemClickListener(new OnItemClickListener() {            @Override            public void onItemClick(AdapterView<?> parent, View view,                                    int position, long id) {                // 用户单击了文件,直接返回,不做任何处理                if (currentFiles[position].isFile()) {                    //此处可做对文件的各种操作,如对MP3的播放,图片的预览(预览界面可滑动),文本的打开等。                    return;                }                // 获取用户点击的文件夹下的所有文件                File[] tmp = currentFiles[position].listFiles();                if (tmp == null || tmp.length == 0) {                    Toast.makeText(SDPathBrowse1.this                            , "当前路径不可访问或该路径下没有文件",                            Toast.LENGTH_SHORT).show();                } else {                    // 获取用户单击的列表项对应的文件夹,设为当前的父文件夹                    currentParent = currentFiles[position];                    // 保存当前的父文件夹内的全部文件和文件夹(即将临时tmp赋值给currentFiles).                    currentFiles = tmp;                    trimCurrentFiles(currentFiles);                }            }        });        parent.setOnClickListener(new OnClickListener() {            @Override            public void onClick(View source) {                try {                    String currentPath = currentParent.getCanonicalPath();                    Log.i("lyw", currentPath);                    if (!currentParent.getCanonicalPath()//返回规范路径名                            .equals("/")) {                        // 获取上一级目录                        currentParent = currentParent.getParentFile();                        // 列出当前目录下所有文件                        currentFiles = currentParent.listFiles();                        trimCurrentFiles(currentFiles);                    }                } catch (IOException e) {                    e.printStackTrace();                }            }        });        //为searchview设置监听事件        sv_.setOnQueryTextListener(this);    }    /**     * 初始化,返回上一级路径,进入下一级路径,     * 整理数据,放置到listItems中。然后adapter.notifyDataSetChanged().     */    private void trimCurrentFiles(File[] files) {        listItems.clear();        Map<String, Object> listItem;        for (int i = 0; i < files.length; i++) {            listItem = new HashMap<String, Object>();            // 如果当前File是文件夹,使用folder图标;否则使用file图标            if (files[i].isDirectory()) {                listItem.put("icon", R.mipmap.folder);            } else {                listItem.put("icon", R.mipmap.file);            }            listItem.put("fileName", files[i].getName());            // 添加List项            listItems.add(listItem);        }        tmplistItems.addAll(listItems);        myAdapter.notifyDataSetChanged();//每次listItems中的数据改变,通知adapter.        try {            textView.setText("当前路径为:"                    + currentParent.getCanonicalPath());        } catch (IOException e) {            e.printStackTrace();        }    }    @Override    public boolean onQueryTextChange(String s) {        //当搜索文字发生改变,此处执行的代码与activity_searchView相应位置执行的代码做比对,同一功能两种不同的实现。        if (TextUtils.isEmpty(s)) {            listView.clearTextFilter();        } else {            listView.setFilterText(s.toString());        }        return true;    }    //单击搜索按钮时激发该方法    @Override    public boolean onQueryTextSubmit(String s) {        return true;    }    public class MyAdapter extends BaseAdapter implements Filterable {        private MyFilter myFilter;        // private List<Map<String, Object>> list_Items;        private LayoutInflater mInflater;        public ImageView iv;        public TextView tv;        Bitmap bitmap;        public MyAdapter(Context c) {            mInflater = (LayoutInflater) c.getSystemService(Context.LAYOUT_INFLATER_SERVICE);        }        @Override        public int getCount() {            if (listItems == null)                return 0;            return listItems.size();        }        @Override        public View getView(int position, View convertView, ViewGroup Parent) {            convertView = mInflater.inflate(R.layout.activity_sdpathbrowse1_item, null);            iv = (ImageView) convertView.findViewById(R.id.iv_folder);            tv = (TextView) convertView.findViewById(R.id.tv_filename);            bitmap = BitmapFactory.decodeResource(getResources(), (Integer) listItems.get(position).get("icon"));            iv.setImageBitmap(bitmap);            tv.setText((CharSequence) listItems.get(position).get("fileName"));            return convertView;        }        @Override        public long getItemId(int position) {            return position;        }        @Override        public Object getItem(int position) {            return listItems.get(position);        }        @Override        public Filter getFilter() {            if (null == myFilter) {                myFilter = new MyFilter();            }            return myFilter;        }        class MyFilter extends Filter {            @Override            // 该方法在子线程中执行            // 自定义过滤规则            protected FilterResults performFiltering(CharSequence charSequence) {                FilterResults results = new FilterResults();                List<Map<String, Object>> newValues = new ArrayList<Map<String, Object>>();                String filterString = charSequence.toString().trim();                if (TextUtils.isEmpty(filterString)) {                    newValues = tmplistItems;                } else {                    for (int i = 0; i < tmplistItems.size(); i++) {                        String str = (String) tmplistItems.get(i).get("fileName");                        if (-1 != str.indexOf(filterString)) {                            newValues.add(tmplistItems.get(i));                        }                    }                }                results.values = newValues;                results.count = newValues.size();                return results;            }            @Override            protected void publishResults(CharSequence charSequence, FilterResults filterResults) {                listItems = (List<Map<String, Object>>) filterResults.values;                if (filterResults.count > 0) {                    myAdapter.notifyDataSetChanged();                } else {                    myAdapter.notifyDataSetInvalidated();                }            }        }    }}

架构 简单的说明:
     public class SDPathBrowse1 extends Activity implements SearchView.OnQueryTextListener
     本类implement SearchView.OnQueryTextListener
     然后实现接口中未实现的方法:  
       public boolean onQueryTextChange(String s) {
          if (TextUtils.isEmpty(s)) {                    listView.clearTextFilter();                } else {               listView.setFilterText(s.toString());           }        return true;
}
       public boolean onQueryTextSubmit(String s) {}
 在onQueryTextChange()中,listView调用setFilterText()方法。此方法是listView通过适配中getFilter()方法得到的。
所以上面的MyAdapter类实现了 Filterable接口。
MyFilter继承Filter 作为MyAdapter的内部类。
至此,这就是整个程序的逻辑架构。


0 0
原创粉丝点击