Android通用的搜索框

原创 2016年06月02日 10:31:41

之前项目总会遇到很多搜索框类的功能,虽然不是很复杂,不过每次都要去自己处理数据,并且去处理搜索框的变化,写起来也比较麻烦,今天来做一个比较简单的通用搜索栏。

先看下效果图:

简单效果图

没什么特别的,只是今天要做的就是简单的把搜索框的内容封装一下.


一、分析功能

先考虑一下,搜索框一般都是由一个搜索图标(一般都是一个放大镜),一个输入框和一个清除按钮组成.然后会通过监听输入框的变化去处理清除按钮的显示和隐藏并且去过滤相关的数据.最后去刷新适配器,显示过滤后的数据.基本上搜索框的功能都大同小异.
有了上边的分析,我们可以去提取出一个通用的搜索框布局,然后写一个自定义ViewGroup去处理相关的页面显示等问题.


二、具体实现

先来写一些自定的属性,方便之后使用,新建一个attr文件并定义自定义属性如下:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!--搜索图标左边margin-->
    <attr name="SearchBarIconMarginLeft" format="dimension"/>
    <!--搜索图标右边margin-->
    <attr name="SearchBarIconMarginRight" format="dimension"/>
    <!--搜索图标-->
    <attr name="SearchBarIconSrc" format="reference"/>
    <!--清除图标左边margin-->
    <attr name="ClearIconMarginLeft" format="dimension"/>
    <!--清除图标右边margin-->
    <attr name="ClearIconMarginRight" format="dimension"/>
    <!--清除图标-->
    <attr name="ClearIconSrc" format="reference"/>
    <!--搜索文字大小-->
    <attr name="SearchTextSize" format="dimension"/>
    <!--搜索文字颜色-->
    <attr name="SearchTextColor" format="color"/>
    <declare-styleable name="CommolySearchView">
        <attr name="SearchBarIconMarginLeft"/>
        <attr name="SearchBarIconMarginRight"/>
        <attr name="SearchBarIconSrc"/>
        <attr name="ClearIconMarginLeft"/>
        <attr name="ClearIconMarginRight"/>
        <attr name="ClearIconSrc"/>
        <attr name="SearchTextSize"/>
        <attr name="SearchTextColor"/>
    </declare-styleable>

</resources>

然后写一下搜索栏的布局searchview_layout.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center_vertical"
        android:orientation="horizontal"
        >

        <ImageView
            android:id="@+id/iv_search_icon"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:src="@mipmap/search_bar_icon"
            android:layout_marginRight="8dp"
            />

        <EditText
            android:id="@+id/et_search"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="@null"
            android:singleLine="true"
            />

        <ImageView
            android:id="@+id/iv_search_clear"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:src="@mipmap/search_clear_icon"
            android:visibility="gone"
            />
    </LinearLayout>

</LinearLayout>

布局很简单,就是一个搜索图标加上一个输入框和一个清除图标,下边来写一下具体的实现,建立一个CommolySearchView继承自LinearLayout即可,先来定义一些属性,获取自定义属性并且绑定布局文件.代码如下:

/**
 * Created by junweiliu on 16/5/31.
 */
public class CommolySearchView<T> extends LinearLayout {
    /**
     * 上下文
     */
    private Context mContext;
    /**
     * 编辑框
     */
    private EditText mEditText;
    /**
     * 清除按钮
     */
    private ImageView mClearImg;
    /**
     * 搜索图标
     */
    private ImageView mSearchBarImg;
    /**
     * 适配器
     */
    private BaseAdapter mAdapter;
    /**
     * 数据源
     */
    private List<T> mDatas = new ArrayList<T>();
    /**
     * 数据源副本
     */
    private List<T> mDupDatas = new ArrayList<T>();

    /**
     * 筛选后的数据源
     */
    private List<T> mFilterDatas = new ArrayList<T>();
    /**
     * 筛选后的数据源副本
     */
    private List<T> mDupFilterDatas = new ArrayList<T>();
    /**
     * 搜索图标
     */
    private Bitmap mSearchIcon;
    /**
     * 搜索框距离左边边距
     */
    private int mSearchIconMarginLeft;
    /**
     * 搜索框距离右边边距
     */
    private int mSearchIconMarginRight;
    /**
     * 清除图标
     */
    private Bitmap mClearIcon;
    /**
     * 清除图标距离左边边距
     */
    private int mClearIconMarginLeft;
    /**
     * 清除图标距离右边边距
     */
    private int mClearIconMarginRight;
    /**
     * 搜索文字大小
     */
    private int mSearchTextSize;
    /**
     * 搜索文字颜色
     */
    private int mSearchTextColor;

    public CommolySearchView(Context context) {
        this(context, null);
    }

    public CommolySearchView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CommolySearchView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mContext = context;
        // 自定义属性
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CommolySearchView);
        Drawable searchD = ta.getDrawable(R.styleable.CommolySearchView_SearchBarIconSrc);
        mSearchIcon = drawableToBitamp(searchD);
        mSearchIconMarginLeft = px2dip(context, ta.getDimensionPixelOffset(R.styleable.CommolySearchView_SearchBarIconMarginLeft, 0));
        mSearchIconMarginRight = px2dip(context, ta.getDimensionPixelOffset(R.styleable.CommolySearchView_SearchBarIconMarginRight, 0));
        Drawable clearD = ta.getDrawable(R.styleable.CommolySearchView_ClearIconSrc);
        mClearIcon = drawableToBitamp(clearD);
        mClearIconMarginLeft = px2dip(context, ta.getDimensionPixelOffset(R.styleable.CommolySearchView_ClearIconMarginLeft, 0));
        mClearIconMarginRight = px2dip(context, ta.getDimensionPixelOffset(R.styleable.CommolySearchView_ClearIconMarginRight, 0));
        mSearchTextSize = px2sp(context, ta.getDimensionPixelOffset(R.styleable.CommolySearchView_SearchTextSize, 0));
        mSearchTextColor = ta.getColor(R.styleable.CommolySearchView_SearchTextColor, 0);
        ta.recycle();
        // 绑定布局文件
        LayoutInflater.from(context).inflate(R.layout.searchview_layout, this);
        initView();
    }    

可以看到我们使用了泛型,目的是为了处理不同的数据源类型,接下来需要初始化控件,看一下initView方法:

    /**
     * 初始化控件
     */
    private void initView() {
        mEditText = (EditText) findViewById(R.id.et_search);
        mClearImg = (ImageView) findViewById(R.id.iv_search_clear);
        mSearchBarImg = (ImageView) findViewById(R.id.iv_search_icon);
        // 处理自定义属性
        if (0 != mSearchIconMarginLeft || 0 != mSearchIconMarginRight) {
            mSearchBarImg.setPadding(mSearchIconMarginLeft, 0, mSearchIconMarginRight, 0);
        }
        if (0 != mClearIconMarginLeft || 0 != mClearIconMarginRight) {
            mClearImg.setPadding(mClearIconMarginLeft, 0, mClearIconMarginRight, 0);
        }
        if (null != mSearchIcon) {
            mSearchBarImg.setImageBitmap(mSearchIcon);
        }
        if (null != mClearIcon) {
            mClearImg.setImageBitmap(mClearIcon);
        }
        if (0 != mSearchTextSize) {
            mEditText.setTextSize(mSearchTextSize);
        }
        if (0 != mSearchTextColor) {
            mEditText.setTextColor(mSearchTextColor);
        }
        // 清空按钮处理事件
        mClearImg.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {

            }
        });
        // 搜索栏处理事件
        mEditText.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

            }

            @Override
            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {

            }

            @Override
            public void afterTextChanged(Editable editable) {

            }
        });
    }

这样初始化控件的任务也完成了,下面就是处理具体逻辑的部分,我们打算在CommonlySearchView完成清除按钮的显示隐藏,编辑框内容的处理,对适配器进行刷新的功能,具体数据的筛选工作,使用一个回调接口,由使用者去进行筛选,只需要获取筛选后的数据即可,然后通过筛选后的数据,去刷新适配器来完成要实现的功能.所以要对外提供一些方法,来获取到适配器,及一些数据源.

   /**
     * 设置数据源
     *
     * @param datas
     */
    public void setDatas(List<T> datas) {
        if (null == datas) {
            return;
        }
        if (null != mDatas) {
            mDatas.clear();
        }
        if (null != mDupDatas) {
            mDupDatas.clear();
        }
        mDatas = datas;
        mDupDatas.addAll(mDatas);
    }

    /**
     * 设置适配器
     *
     * @param adapter
     */
    public void setAdapter(BaseAdapter adapter) {
        if (null == adapter) {
            return;
        }
        mAdapter = adapter;
    }

获取到适配器及数据源,并且做了相关数据备份工作.

接着要提供一个回调接口来得到筛选后的数据.

    /**
     * 回调接口
     *
     * @param <T>
     */
    interface SearchDatas<T> {
        /**
         * 参数一:全部数据,参数二:筛选后的数据,参数三:输入的内容
         *
         * @param datas
         * @param filterdatas
         * @param inputstr
         * @return 筛选后的数据
         */
        List<T> filterDatas(List<T> datas, List<T> filterdatas, String inputstr);
    }

    /**
     * 回调
     */
    private SearchDatas<T> mListener;

    /**
     * 设置回调
     *
     * @param listener
     */
    public void setSearchDataListener(SearchDatas<T> listener) {
        mListener = listener;

    }

同样需要对外提供一个方法,以便使用者获取到筛选后的数据去做相关操作.

    /**
     * 获取筛选后的数据
     *
     * @return
     */
    public List<T> getFilterDatas() {
        return (null != mDupFilterDatas && mDupFilterDatas.size() > 0) ? mDupFilterDatas : mDupDatas;
    }

得到数据之后,就是在输入框和清除按钮的监听方法中去做相关处理就可以了,完整代码如下:

package com.example.junweiliu.commonlysearchview;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;

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

/**
 * Created by junweiliu on 16/5/31.
 */
public class CommolySearchView<T> extends LinearLayout {
    /**
     * 上下文
     */
    private Context mContext;
    /**
     * 编辑框
     */
    private EditText mEditText;
    /**
     * 清除按钮
     */
    private ImageView mClearImg;
    /**
     * 搜索图标
     */
    private ImageView mSearchBarImg;
    /**
     * 适配器
     */
    private BaseAdapter mAdapter;
    /**
     * 数据源
     */
    private List<T> mDatas = new ArrayList<T>();
    /**
     * 数据源副本
     */
    private List<T> mDupDatas = new ArrayList<T>();

    /**
     * 筛选后的数据源
     */
    private List<T> mFilterDatas = new ArrayList<T>();
    /**
     * 筛选后的数据源副本
     */
    private List<T> mDupFilterDatas = new ArrayList<T>();
    /**
     * 搜索图标
     */
    private Bitmap mSearchIcon;
    /**
     * 搜索框距离左边边距
     */
    private int mSearchIconMarginLeft;
    /**
     * 搜索框距离右边边距
     */
    private int mSearchIconMarginRight;
    /**
     * 清除图标
     */
    private Bitmap mClearIcon;
    /**
     * 清除图标距离左边边距
     */
    private int mClearIconMarginLeft;
    /**
     * 清除图标距离右边边距
     */
    private int mClearIconMarginRight;
    /**
     * 搜索文字大小
     */
    private int mSearchTextSize;
    /**
     * 搜索文字颜色
     */
    private int mSearchTextColor;

    /**
     * 回调接口
     *
     * @param <T>
     */
    interface SearchDatas<T> {
        /**
         * 参数一:全部数据,参数二:筛选后的数据,参数三:输入的内容
         *
         * @param datas
         * @param filterdatas
         * @param inputstr
         * @return
         */
        List<T> filterDatas(List<T> datas, List<T> filterdatas, String inputstr);
    }

    /**
     * 回调
     */
    private SearchDatas<T> mListener;

    /**
     * 设置回调
     *
     * @param listener
     */
    public void setSearchDataListener(SearchDatas<T> listener) {
        mListener = listener;

    }

    public CommolySearchView(Context context) {
        this(context, null);
    }

    public CommolySearchView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CommolySearchView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mContext = context;
        // 自定义属性
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CommolySearchView);
        Drawable searchD = ta.getDrawable(R.styleable.CommolySearchView_SearchBarIconSrc);
        mSearchIcon = drawableToBitamp(searchD);
        mSearchIconMarginLeft = px2dip(context, ta.getDimensionPixelOffset(R.styleable.CommolySearchView_SearchBarIconMarginLeft, 0));
        mSearchIconMarginRight = px2dip(context, ta.getDimensionPixelOffset(R.styleable.CommolySearchView_SearchBarIconMarginRight, 0));
        Drawable clearD = ta.getDrawable(R.styleable.CommolySearchView_ClearIconSrc);
        mClearIcon = drawableToBitamp(clearD);
        mClearIconMarginLeft = px2dip(context, ta.getDimensionPixelOffset(R.styleable.CommolySearchView_ClearIconMarginLeft, 0));
        mClearIconMarginRight = px2dip(context, ta.getDimensionPixelOffset(R.styleable.CommolySearchView_ClearIconMarginRight, 0));
        mSearchTextSize = px2sp(context, ta.getDimensionPixelOffset(R.styleable.CommolySearchView_SearchTextSize, 0));
        mSearchTextColor = ta.getColor(R.styleable.CommolySearchView_SearchTextColor, 0);
        ta.recycle();
        // 绑定布局文件
        LayoutInflater.from(context).inflate(R.layout.searchview_layout, this);
        initView();
    }

    /**
     * 初始化控件
     */
    private void initView() {
        mEditText = (EditText) findViewById(R.id.et_search);
        mClearImg = (ImageView) findViewById(R.id.iv_search_clear);
        mSearchBarImg = (ImageView) findViewById(R.id.iv_search_icon);
        // 处理自定义属性
        if (0 != mSearchIconMarginLeft || 0 != mSearchIconMarginRight) {
            mSearchBarImg.setPadding(mSearchIconMarginLeft, 0, mSearchIconMarginRight, 0);
        }
        if (0 != mClearIconMarginLeft || 0 != mClearIconMarginRight) {
            mClearImg.setPadding(mClearIconMarginLeft, 0, mClearIconMarginRight, 0);
        }
        if (null != mSearchIcon) {
            mSearchBarImg.setImageBitmap(mSearchIcon);
        }
        if (null != mClearIcon) {
            mClearImg.setImageBitmap(mClearIcon);
        }
        if (0 != mSearchTextSize) {
            mEditText.setTextSize(mSearchTextSize);
        }
        if (0 != mSearchTextColor) {
            mEditText.setTextColor(mSearchTextColor);
        }
        // 清空按钮处理事件
        mClearImg.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
                mEditText.setText("");
                mClearImg.setVisibility(View.GONE);
                if (null != mDatas) {
                    mDatas.clear();
                }
                mDatas.addAll(mDupDatas);
                mAdapter.notifyDataSetChanged();
                reSetDatas();
            }
        });
        // 搜索栏处理事件
        mEditText.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

            }

            @Override
            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
                // 获取筛选后的数据
                mFilterDatas = mListener.filterDatas(mDupDatas, mFilterDatas, charSequence.toString());
                if (charSequence.toString().length() > 0 && !charSequence.toString().equals("")) {
                    mClearImg.setVisibility(View.VISIBLE);
                } else {
                    mClearImg.setVisibility(View.GONE);
                }
                if (null != mDatas) {
                    mDatas.clear();
                }
                mDatas.addAll(mFilterDatas);
                mAdapter.notifyDataSetChanged();
                reSetDatas();
            }

            @Override
            public void afterTextChanged(Editable editable) {

            }
        });
    }

    /**
     * 获取筛选后的数据
     *
     * @return
     */
    public List<T> getFilterDatas() {
        return (null != mDupFilterDatas && mDupFilterDatas.size() > 0) ? mDupFilterDatas : mDupDatas;
    }


    /**
     * 重置数据
     */
    private void reSetDatas() {
        if (null != mFilterDatas) {
            if (null != mDupFilterDatas) {
                mDupFilterDatas.clear();
                mDupFilterDatas.addAll(mFilterDatas);
            }
            mFilterDatas.clear();
        }
    }

    /**
     * 设置数据源
     *
     * @param datas
     */
    public void setDatas(List<T> datas) {
        if (null == datas) {
            return;
        }
        if (null != mDatas) {
            mDatas.clear();
        }
        if (null != mDupDatas) {
            mDupDatas.clear();
        }
        mDatas = datas;
        mDupDatas.addAll(mDatas);
    }

    /**
     * 设置适配器
     *
     * @param adapter
     */
    public void setAdapter(BaseAdapter adapter) {
        if (null == adapter) {
            return;
        }
        mAdapter = adapter;
    }

    /**
     * drawable转bitmap
     *
     * @param drawable
     * @return
     */
    private Bitmap drawableToBitamp(Drawable drawable) {
        if (null == drawable) {
            return null;
        }
        if (drawable instanceof BitmapDrawable) {
            BitmapDrawable bd = (BitmapDrawable) drawable;
            return bd.getBitmap();
        }
        int w = drawable.getIntrinsicWidth();
        int h = drawable.getIntrinsicHeight();
        Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        drawable.setBounds(0, 0, w, h);
        drawable.draw(canvas);
        return bitmap;
    }

    /**
     * 将px值转换为dip或dp值,保证尺寸大小不变
     *
     * @param pxValue
     * @return
     * @param(DisplayMetrics类中属性density)
     */
    public int px2dip(Context context, float pxValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (pxValue / scale + 0.5f);
    }


    /**
     * 将px值转换为sp值,保证文字大小不变
     *
     * @param pxValue
     * @return
     */
    public static int px2sp(Context context, float pxValue) {
        final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
        return (int) (pxValue / fontScale + 0.5f);
    }
}

三、完整代码及使用

换一个复杂点的listview来使用一下.很简单,就是普通的Listview绑定数据,我们结合CommolySearchView来使用一下.

实体Bean
SanGuoBean:

package com.example.junweiliu.commonlysearchview.bean;

/**
 * Created by junweiliu on 16/6/1.
 */
public class SanGuoBean {
    /**
     * 名称
     */
    private String sgName;
    /**
     * 描述
     */
    private String sgDescribe;
    /**
     * 头像
     */
    private int sgHeadBp;
    /**
     * 字
     */
    private String sgPetName;

    public SanGuoBean() {
    }

    public SanGuoBean(String sgName, String sgDescribe, int sgHeadBp, String sgPetName) {
        this.sgName = sgName;
        this.sgDescribe = sgDescribe;
        this.sgHeadBp = sgHeadBp;
        this.sgPetName = sgPetName;
    }

    public String getSgName() {
        return sgName;
    }

    public void setSgName(String sgName) {
        this.sgName = sgName;
    }

    public String getSgDescribe() {
        return sgDescribe;
    }

    public void setSgDescribe(String sgDescribe) {
        this.sgDescribe = sgDescribe;
    }

    public int getSgHeadBp() {
        return sgHeadBp;
    }

    public void setSgHeadBp(int sgHeadBp) {
        this.sgHeadBp = sgHeadBp;
    }

    public String getSgPetName() {
        return sgPetName;
    }

    public void setSgPetName(String sgPetName) {
        this.sgPetName = sgPetName;
    }
}

适配器每项布局文件sg_item:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:gravity="center_vertical"
              android:orientation="horizontal"
              android:padding="6dp"
    >

    <ImageView
        android:id="@+id/iv_sghead"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:scaleType="fitXY"
        android:src="@mipmap/ic_launcher"
        />

    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_marginLeft="8dp"
        android:layout_weight="1"
        android:orientation="vertical"
        >

        <TextView
            android:id="@+id/tv_sgname"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textSize="16sp"
            />

        <TextView
            android:id="@+id/tv_sgpetname"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="2dp"
            android:textSize="12sp"
            />

        <TextView
            android:id="@+id/tv_sgdes"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="2dp"
            android:textSize="12sp"
            />
    </LinearLayout>
</LinearLayout>

适配器SGAdapter:

package com.example.junweiliu.commonlysearchview.adapter;

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

import com.example.junweiliu.commonlysearchview.R;
import com.example.junweiliu.commonlysearchview.bean.SanGuoBean;
import com.example.junweiliu.commonlysearchview.bean.SearchBean;

import java.util.List;

/**
 * Created by junweiliu on 16/6/1.
 */
public class SGAdapter extends BaseAdapter {
    /**
     * 上下文
     */
    private Context mContext;

    /**
     * 数据源
     */
    private List<SanGuoBean> mDatas;


    /**
     * 构造函数
     *
     * @param context
     * @param datas
     */
    public SGAdapter(Context context, List<SanGuoBean> datas) {
        mContext = context;
        mDatas = datas;
    }

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

    @Override
    public Object getItem(int i) {
        return mDatas.get(i);
    }

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

    @Override
    public View getView(int position, View view, ViewGroup viewGroup) {
        ViewHolder vh = null;
        if (null == view) {
            vh = new ViewHolder();
            LayoutInflater mInflater = LayoutInflater.from(mContext);
            view = mInflater.inflate(R.layout.sg_item, null);
            vh.mNameTv = (TextView) view.findViewById(R.id.tv_sgname);
            vh.mPetNmaeTv = (TextView) view.findViewById(R.id.tv_sgpetname);
            vh.mDesTv = (TextView) view.findViewById(R.id.tv_sgdes);
            vh.mHeadImg = (ImageView) view.findViewById(R.id.iv_sghead);
            view.setTag(vh);
        } else {
            vh = (ViewHolder) view.getTag();
        }
        SanGuoBean bean = (SanGuoBean) getItem(position);
        if (null != bean) {
            vh.mNameTv.setText(bean.getSgName());
            vh.mDesTv.setText(bean.getSgDescribe());
            vh.mPetNmaeTv.setText(bean.getSgPetName());
            vh.mHeadImg.setImageResource(bean.getSgHeadBp());
        }
        return view;
    }


    /**
     * vh
     */
    class ViewHolder {
        /**
         * 姓名
         */
        TextView mNameTv;
        /**
         * 描述
         */
        TextView mDesTv;
        /**
         * 字
         */
        TextView mPetNmaeTv;
        /**
         * 头像
         */
        ImageView mHeadImg;
    }
}

MainActivity布局文件activity_main:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:search="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.example.junweiliu.commonlysearchview.MainActivity">


    <com.example.junweiliu.commonlysearchview.CommolySearchView
        android:id="@+id/csv_show"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:layout_margin="8dip"
        android:background="@drawable/login_et_bg"
        search:SearchTextColor="#ff0000"
        search:SearchTextSize="14sp"
        >
    </com.example.junweiliu.commonlysearchview.CommolySearchView>


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

</LinearLayout>

MainActivity:

package com.example.junweiliu.commonlysearchview;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.Toast;

import com.example.junweiliu.commonlysearchview.adapter.SGAdapter;
import com.example.junweiliu.commonlysearchview.adapter.SearchAdapter;
import com.example.junweiliu.commonlysearchview.bean.SanGuoBean;
import com.example.junweiliu.commonlysearchview.bean.SearchBean;

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


public class MainActivity extends Activity {
    /**
     * TAG
     */
    private static final String TAG = "MainActivity";
    /**
     * 数据显示listview
     */
    private ListView mListView;
    /**
     * 适配器
     */
    private SearchAdapter adapter;
    /**
     * 三国通用搜索框
     */
    private CommolySearchView<SanGuoBean> mSGCommolySearchView;
    /**
     * 三国数据源
     */
    private List<SanGuoBean> mSGDatas;
    /**
     * 三国适配器
     */
    private SGAdapter sgAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initDataI();
        initViewI();
    }
    /**
     * 初始化数据
     */
    private void initDataI() {
        mSGDatas = new ArrayList<SanGuoBean>();
        SanGuoBean sgbean1 = new SanGuoBean();
        sgbean1.setSgName("刘备");
        sgbean1.setSgPetName("玄德");
        sgbean1.setSgHeadBp(R.drawable.lb);
        sgbean1.setSgDescribe("刘备(161年-223年6月10日),字玄德,东汉末年幽州涿郡涿县(今河北省涿州市)人");
        SanGuoBean sgbean2 = new SanGuoBean();
        sgbean2.setSgName("关羽");
        sgbean2.setSgPetName("云长");
        sgbean2.setSgHeadBp(R.drawable.gy);
        sgbean2.setSgDescribe("关羽(?-220年),本字长生,后改字云长,河东郡解良(今山西运城)人");
        SanGuoBean sgbean3 = new SanGuoBean();
        sgbean3.setSgName("张飞");
        sgbean3.setSgPetName("翼德");
        sgbean3.setSgHeadBp(R.drawable.zf);
        sgbean3.setSgDescribe("张飞(?-221年),字益德[1]  ,幽州涿郡(今河北省保定市涿州市)人氏");
        SanGuoBean sgbean4 = new SanGuoBean();
        sgbean4.setSgName("赵云");
        sgbean4.setSgPetName("子龙");
        sgbean4.setSgHeadBp(R.drawable.zy);
        sgbean4.setSgDescribe("赵云(?-229年),字子龙,常山真定(今河北省正定)人");
        SanGuoBean sgbean5 = new SanGuoBean();
        sgbean5.setSgName("马超");
        sgbean5.setSgPetName("孟起");
        sgbean5.setSgHeadBp(R.drawable.mc);
        sgbean5.setSgDescribe("马超(176年-222年),字孟起,司隶部扶风郡茂陵(今陕西兴平)人");
        SanGuoBean sgbean6 = new SanGuoBean();
        sgbean6.setSgName("黄忠");
        sgbean6.setSgPetName("汉升");
        sgbean6.setSgHeadBp(R.drawable.hz);
        sgbean6.setSgDescribe("黄忠(?-220年),字汉升(一作“汉叔”[1]  ),南阳(今河南南阳)人");
        SanGuoBean sgbean7 = new SanGuoBean();
        sgbean7.setSgName("张辽");
        sgbean7.setSgPetName("文远");
        sgbean7.setSgHeadBp(R.drawable.zl);
        sgbean7.setSgDescribe("张辽(169年-222年),字文远,雁门马邑(今山西朔州)人");
        mSGDatas.add(sgbean1);
        mSGDatas.add(sgbean2);
        mSGDatas.add(sgbean3);
        mSGDatas.add(sgbean4);
        mSGDatas.add(sgbean5);
        mSGDatas.add(sgbean6);
        mSGDatas.add(sgbean7);

    }

    /**
     * 初始化控件
     */
    private void initViewI() {
        mSGCommolySearchView = (CommolySearchView) findViewById(R.id.csv_show);
        mListView = (ListView) findViewById(R.id.lv_show);
        sgAdapter = new SGAdapter(this, mSGDatas);
        mListView.setAdapter(sgAdapter);
        // 设置数据源
        mSGCommolySearchView.setDatas(mSGDatas);
        // 设置适配器
        mSGCommolySearchView.setAdapter(sgAdapter);
        // 设置筛选数据
        mSGCommolySearchView.setSearchDataListener(new CommolySearchView.SearchDatas<SanGuoBean>() {
            @Override
            public List<SanGuoBean> filterDatas(List<SanGuoBean> datas, List<SanGuoBean> filterdatas, String inputstr) {
                for (int i = 0; i < datas.size(); i++) {
                    // 筛选条件
                    if ((datas.get(i).getSgDescribe()).contains(inputstr) || datas.get(i).getSgName().contains(inputstr) || datas.get(i).getSgPetName().contains(inputstr)) {
                        filterdatas.add(datas.get(i));
                    }
                }
                return filterdatas;
            }
        });
        mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
                Toast.makeText(MainActivity.this, mSGCommolySearchView.getFilterDatas().get(i).getSgName() + "字" + mSGCommolySearchView.getFilterDatas().get(i).getSgPetName() + "\n" + mSGCommolySearchView.getFilterDatas().get(i).getSgDescribe(), Toast.LENGTH_SHORT).show();
            }
        });

    }
}

效果图如下:

最终效果图

下载地址

进一步优化与封装

进一步的优化和封装请看我的另一篇博客Android通用搜索页的分析与封装

版权声明:本文为博主原创文章,未经博主允许不得转载。

Android 搜索框:SearchView 的属性和用法详解

SearchView是Android原生的搜索框控件,它提供了一个用户界面,用于用户搜索查询。...
  • Airsaid
  • Airsaid
  • 2016年04月07日 16:55
  • 42637

Android自定义View——自定义搜索框(SearchView)

概述 在Android开发中,当系统数据项比较多时,常常会在app添加搜索功能,方便用户能快速获得需要的数据。搜索栏对于我们并不陌生,在许多app都能见到它,比如豌豆荚 在某些情况下,我们希望...
  • jdsjlzx
  • jdsjlzx
  • 2015年06月16日 10:06
  • 105000

Android自定义View:你需要一个简单好用、含历史搜索记录的搜索框吗?

前言 像下图的搜索功能在Android开发中非常常见今天我将手把手教大家如何实现具备历史搜索记录的搜索框 目录1. 使用场景在敲下代码前,理解用户的功能使用场景是非常重要的,这样有助于我们更好地去进行...

Android开发中的一个小功能 清空搜索框的文字

需求:项目中的有关搜索的地方,加上清空文字的功能,目的是为了增加用户体验,使用户删除文本更加快捷 解决过程:开始的时候感觉这个东西不太好实现,主要就是布局的问题,可能是开始顾虑的太多了,再加上当时产...
  • walker02
  • walker02
  • 2012年08月28日 19:33
  • 37529

Android中的搜索框(SearchView)的功能和用法

1、SearchView是搜索框组件,它可以让用户在文本框里输入文字,通过监听器取得用户的输入,当用户点击搜索时,监听器执行实际的搜索。 2、SearchView组件的常用方法如下: ①s...
  • Lee_my_
  • Lee_my_
  • 2015年02月08日 12:34
  • 3193

Android floatingSearchView 开源 仿谷歌搜索框

来源 https://github.com/arimorty/floatingsearchview翻译 chromeFloating Search View一个具有搜索建议的浮动搜索框的实现,也称...

详细解读Android中的搜索框(一)—— 简单小例子

详细解读Android中的搜索框(一)—— 简单小例子   这次开的是一个讲解SearchView的栏目,第一篇主要是给一个小例子,让大家对这个搜索视图有一个了解,之后再分布细化来说。...

android搜索框功能实现

这里实现的是搜索框时时查询,代码中是在数据库中使用的模糊查询; 整个布局使用的是线性布局,搜索框又是一个线性布局(里面包含一个相对布局和一个TextView,相对布局里面有一个EditText和Ima...

android顶部(toolbar)搜索框实现

本文介绍两种SearchView的使用情况,一种是输入框和搜索结果不在一个activity中,另一种是在一个activity中。 首先编写toolbar的布局文件 toolbar中图标在menu文...

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Android通用的搜索框
举报原因:
原因补充:

(最多只允许输入30个字)