之前项目总会遇到很多搜索框类的功能,虽然不是很复杂,不过每次都要去自己处理数据,并且去处理搜索框的变化,写起来也比较麻烦,今天来做一个比较简单的通用搜索栏。
先看下效果图:
没什么特别的,只是今天要做的就是简单的把搜索框的内容封装一下.
一、分析功能
先考虑一下,搜索框一般都是由一个搜索图标(一般都是一个放大镜),一个输入框和一个清除按钮组成.然后会通过监听输入框的变化去处理清除按钮的显示和隐藏并且去过滤相关的数据.最后去刷新适配器,显示过滤后的数据.基本上搜索框的功能都大同小异.
有了上边的分析,我们可以去提取出一个通用的搜索框布局,然后写一个自定义ViewGroup去处理相关的页面显示等问题.
二、具体实现
先来写一些自定的属性,方便之后使用,新建一个attr文件并定义自定义属性如下:
然后写一下搜索栏的布局searchview_layout.xml:
布局很简单,就是一个搜索图标加上一个输入框和一个清除图标,下边来写一下具体的实现,建立一个CommolySearchView继承自LinearLayout即可,先来定义一些属性,获取自定义属性并且绑定布局文件.代码如下:
public class CommolySearchViewextends LinearLayout { private Context mContext; private EditText mEditText; private ImageView mClearImg; private ImageView mSearchBarImg; private baseAdapter mAdapter; private List mDatas = new ArrayList (); private List mDupDatas = new ArrayList (); private List mFilterDatas = new ArrayList (); private List mDupFilterDatas = new ArrayList (); 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完成清除按钮的显示隐藏,编辑框内容的处理,对适配器进行刷新的功能,具体数据的筛选工作,使用一个回调接口,由使用者去进行筛选,只需要获取筛选后的数据即可,然后通过筛选后的数据,去刷新适配器来完成要实现的功能.所以要对外提供一些方法,来获取到适配器,及一些数据源.
public void setDatas(Listdatas) { if (null == datas) { return; } if (null != mDatas) { mDatas.clear(); } if (null != mDupDatas) { mDupDatas.clear(); } mDatas = datas; mDupDatas.addAll(mDatas); } public void setAdapter(baseAdapter adapter) { if (null == adapter) { return; } mAdapter = adapter; }
获取到适配器及数据源,并且做了相关数据备份工作.
接着要提供一个回调接口来得到筛选后的数据.
interface SearchDatas{ List filterDatas(List datas, List filterdatas, String inputstr); } private SearchDatas mListener; public void setSearchDataListener(SearchDatas listener) { mListener = listener; }
同样需要对外提供一个方法,以便使用者获取到筛选后的数据去做相关操作.
public ListgetFilterDatas() { 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; public class CommolySearchViewextends LinearLayout { private Context mContext; private EditText mEditText; private ImageView mClearImg; private ImageView mSearchBarImg; private baseAdapter mAdapter; private List mDatas = new ArrayList (); private List mDupDatas = new ArrayList (); private List mFilterDatas = new ArrayList (); private List mDupFilterDatas = new ArrayList (); private Bitmap mSearchIcon; private int mSearchIconMarginLeft; private int mSearchIconMarginRight; private Bitmap mClearIcon; private int mClearIconMarginLeft; private int mClearIconMarginRight; private int mSearchTextSize; private int mSearchTextColor; interface SearchDatas { List filterDatas(List datas, List filterdatas, String inputstr); } private SearchDatas mListener; public void setSearchDataListener(SearchDatas 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) { } }); } public List 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(); } } public void setDatas(List datas) { if (null == datas) { return; } if (null != mDatas) { mDatas.clear(); } if (null != mDupDatas) { mDupDatas.clear(); } mDatas = datas; mDupDatas.addAll(mDatas); } public void setAdapter(baseAdapter adapter) { if (null == adapter) { return; } mAdapter = adapter; } 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; } public int px2dip(Context context, float pxValue) { final float scale = context.getResources().getDisplayMetrics().density; return (int) (pxValue / scale + 0.5f); } 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;
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:
适配器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;
public class SGAdapter extends baseAdapter {
private Context mContext;
private List mDatas;
public SGAdapter(Context context, List 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;
}
class ViewHolder {
TextView mNameTv;
TextView mDesTv;
TextView mPetNmaeTv;
ImageView mHeadImg;
}
}
MainActivity布局文件activity_main:
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 {
private static final String TAG = "MainActivity";
private ListView mListView;
private SearchAdapter adapter;
private CommolySearchView mSGCommolySearchView;
private List 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 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() {
@Override
public List filterDatas(List datas, List 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();
}
});
}
}
效果图如下:
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持考高分网。



