SearchView的实现

   SearchView是android中一个搜索框组件,它不是一个单独的view,而是一个LinearLayout布局,包括表示Search图标和清除图标等其它图标的imageView、具有下拉建议列表的AutoCompleteTextView等。在api11以后才出现,我们先看下源码
 SearchView的层级结构:search_view.xml
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
 * Copyright (C) 2010 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

-->
<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"
    >

    <!--  -->
    <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>
3. 实例框架:
private void traversSearchView(View view, int index) {
     if (view instanceof SearchView) {
         SearchView searchView = (SearchView)view;
         for (int i = 0; i < searchView.getChildCount(); ++i) {
             traverseSearchView(searchView.getChildAt(i), i);
         }
     }
     else if (view instanceof LinearLayout) {
         if (/*id value from search_view.xml*/ == view.getId()) {
             //TODO
         }
         LinearLayout linearlayout = (LinearLayout)view;
         for (int i = 0; i < linearlayout.getChildAt(i), i) {
	    traverseSearchView(linearlayout.getChildAt(i), i);
	 }
     }
     else if (view instanceof EditText) {
         if (/*id value from search_view.xml*/ == view.getId()) {
             //TODO
         }
         //TODO
     }
     else if (view instanceof ImageView) {
         if (/*id value from search_view.xml*/ == view.getId()) {
             //TODO
         }
         //TODO
     }
     //other 'else if' clause
 }返回 

以上就是searchView的源码,其实searchView是一个linerlayout,通过遍历里面的子view来进行相关处理。下面我们用searchView+listView来实现查找联系人。

main.xml

SearchView的实现_第1张图片
searchView这控件里面有几个属性:

android:iconifiedByDefault表示搜索图标是否在输入框内。true效果更加
android:imeOptions设置IME options,即输入法的回车键的功能,可以是搜索、下一个、发送、完成等等。这里actionSearch表示搜索
android:inputType输入框文本类型
android:queryHint输入框默认文本

java代码:

myAdapter

import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.TextView;

public class MyAdapter extends BaseAdapter implements Filterable {
	private Context context;
	private List<String> data, copyData;

	public MyAdapter(Context context, List<String> data) {
		super();
		this.context = context;
		this.data = data;
		copyData = data;
	}

	@Override
	public int getCount() {
		return data.size();
	}

	@Override
	public Object getItem(int postion) {
		return data.get(postion);
	}

	@Override
	public long getItemId(int postion) {
		return postion;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		if (convertView == null) {
			convertView = LayoutInflater.from(context).inflate(
					android.R.layout.simple_list_item_1, null);
		}
		TextView tv = (TextView) convertView.findViewById(android.R.id.text1);
		tv.setText(data.get(position));
		return convertView;
	}

	private Filter filter;
    /*单利模式*/
	@Override
	public Filter getFilter() {
		if (filter == null) {
			filter = new MyFilter();
		}
		return filter;
	}

	class MyFilter extends Filter {
		/*调用一个工作线程过滤数据。子类必须实现该方法来执行过滤操作。过滤结果以Filter.FilterResults的形式返回*/
		@Override
		protected FilterResults performFiltering(CharSequence constraint) {
			List<String>filterData=new ArrayList<String>();
			if(constraint!=null&&constraint.toString().trim().length()>0){//输入的内容不为空
				String key=constraint.toString().trim().toLowerCase();//把输入的转为大写
				for (String i:copyData) {//遍历数据
					if(i.toLowerCase().indexOf(key)!=-1){//取出的数据包含输入的那个字母
						filterData.add(i);
					}
				}
			}else{
				filterData=copyData;
			}
			FilterResults filterResults=new FilterResults();//过滤集
			filterResults.values=filterData;
			filterResults.count=filterData.size();
			return filterResults;
		}
		/*通过调用UI线程在用户界面发布过滤结果。来显示performFiltering(CharSequence)的过滤结果。*/
		@Override
		protected void publishResults(CharSequence constraint,
				FilterResults results) {
             data=(List<String>) results.values;
             if(data!=null){//重绘当前可见区域
            	 notifyDataSetChanged();
      }else{//重绘控件(还原到初始状态)
            	 notifyDataSetInvalidated();
             }
		}

	}
}
搞那么久开发了,其实对notifyDataSetChanged()和notifyDataSetInvalidated()的区别还不是很了解,以前只知道两个方法都是刷新adapter的方法,现在我想说一下:<span style="color:#ff0000;">notifyDataSetChanged</span>方法通过一个外部的方法控制,如果适配器的内容改变时需要强制调用getView来刷新每个Item的内容,调用onChanged事件。每当发现数据集有改变的情况,或者读取到数据的新状态时,就会调用此方法。而<span style="color:#ff0000;">notifyDataSetInvalidated()</span><span style="color:#000000;">调用onInvalidated事件。每当发现数据集监控有改变的情况,比如该数据集不再有效,就会调用此方法。</span>

SearchViewActivity.java

 

 

import java.util.ArrayList;
import java.util.List;

import android.app.Activity;
import android.content.Context;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.provider.ContactsContract.RawContacts;
import android.view.inputmethod.InputMethodManager;
import android.widget.ListView;
import android.widget.SearchView;
import android.widget.SearchView.OnCloseListener;
import android.widget.SearchView.OnQueryTextListener;

public class SearchViewActivity extends Activity {
    private SearchView searchview;
    private ListView listview;
    private MyAdapter mAdapter;
    private List<String>data;
    private Cursor mCursor;
    static final String[] PROJECTION = new String[] {//联系人id和姓名
        ContactsContract.RawContacts._ID, ContactsContract.RawContacts.DISPLAY_NAME_PRIMARY };  
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        findView();
    }
	private void findView() {
		searchview=(SearchView) findViewById(R.id.searchview);
		listview=(ListView) findViewById(R.id.listview);
		listview.setTextFilterEnabled(true);//设置对字符串过滤 对应适配器
		searchview.setIconifiedByDefault(true); //表示搜索图标是否在输入框内。true效果更加 
		searchview.onActionViewExpanded(); //表示在内容为空时不显示取消的x按钮,内容不为空时显示.
		searchview.setSubmitButtonEnabled(true);//编辑框后显示search按钮
		searchview.setFocusable(false);  
		searchview.clearFocus(); 
      	data = new ArrayList<String>() ;
//		data.add("Hello"); data.add("Hebe") ; data.add("nick") ; data.add("ahha") ; data.add("jack") ; data.add("hello") ; data.add("welcome") ;
		  mCursor = getContentResolver().query(RawContacts.CONTENT_URI, PROJECTION, null, null, null);  
		 if(mCursor!=null){
			  while(mCursor.moveToNext()){
			         String name = mCursor.getString(mCursor.getColumnIndex(ContactsContract.RawContacts.DISPLAY_NAME_PRIMARY));  
					 data.add(name);
				  }
		 }
		
		mAdapter=new MyAdapter(this, data);
		listview.setAdapter(mAdapter);
		/*输入框文字listener*/
		searchview.setOnQueryTextListener(new OnQueryTextListener() {// 监听 SearchView 中的数据变化

			/*开始搜索listener*/
			@Override
			public boolean onQueryTextSubmit(String queryText) {
				 String selection = RawContacts.DISPLAY_NAME_PRIMARY + " LIKE '%"  
		                 + queryText + "%' " + " OR "  
		                 + RawContacts.SORT_KEY_PRIMARY + " LIKE '%" + queryText  
		                 + "%' ";     
		         mCursor = getContentResolver().query(RawContacts.CONTENT_URI, PROJECTION, selection, null, null);  
		         if(mCursor!=null){
		        	 while(mCursor.moveToNext()){
			        	 String name = mCursor.getString(mCursor.getColumnIndex(ContactsContract.RawContacts.DISPLAY_NAME_PRIMARY));  
						 data.add(name);
					  }
		         }
		         
		         mAdapter.notifyDataSetChanged();
				return true;
			}
			/*搜索变化listener*/
			@Override
			public boolean onQueryTextChange(String newText) {
				if(newText!=null&&newText.length()>0){
					listview.setFilterText(newText);
				}else{
					listview.clearTextFilter();
				}
				if (searchview!= null) {  
                    InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);  
                    if (imm != null) {  
                        imm.hideSoftInputFromWindow(  
                        		searchview.getWindowToken(), 0);  
                    }  
                    searchview.clearFocus();  
                } 
				return true;
			}
		});
		/*点击取消按钮listener,默认点击搜索输入框*/
		 searchview.setOnCloseListener(new OnCloseListener() {

	            @Override
	            public boolean onClose() {
	                return true;
	            }
	        });
	}
}

以上就是整个的代码,里面包含了一部分contentProvider的内容,本来listView用的是simpleCurrsorAdapter,那样的话就不要把游标改成list集合了,而我的习惯是用baseAdapter,所以呢就走了点小弯路,以致输入文本时适配器刷新写了重复的代码,消耗了性能。然后也学了一下filter这个类的编写,以前还真的没有写过,记得一定要在
listView加上setTextFilterEnabled(true)不然写的那个文本过滤可就完全没有效果了。最后记得在清单文件里加上

写的不好,就到这里了,至于效果图就不贴了,呵呵呵,如果你觉得对你有帮助就看一下,勿喷就行,欢迎给给意见

源码下载地址http://download.csdn.net/detail/u013278099/8000693

你可能感兴趣的:(ListView,searchView)