SearchView 学习_0

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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值