Android 自定义支持快速搜索筛选的选择控件使用方法,具体如下
项目中遇到选择控件选项过多,需要快速查找匹配的情况。 
做了简单的Demo,效果图如下:
源码地址:https://github.com/whieenz/SearchSelect

这个控件是由Dialog+SearchView+ListView实现的。Dialog用来承载选择控件,SearchView实现输入,ListView展示结果。设计概要图如下:

一、自定义Dialog
Dialog布局文件
<?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="wrap_content" android:layout_weight="1" android:background="@drawable/dialog_bg" android:layout_height="match_parent" android:orientation="vertical" > <RelativeLayout android:layout_width="match_parent" android:layout_height="50dp"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="20dp" android:layout_centerVertical="true" android:textSize="18sp" android:textColor="#000000" android:id="@+id/tv_dialog_select_title"/> <ImageButton android:layout_width="50dp" android:layout_height="match_parent" android:padding="8dp" android:layout_marginRight="10dp" android:layout_centerVertical="true" android:layout_alignParentRight="true" android:scaleType="centerInside" android:background="@color/transparent" android:src="@drawable/im_search_back" android:id="@+id/btn_dialog_select_search"/> </RelativeLayout> <com.whieenz.searchselect.DialogSearchView android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/searchView" android:visibility="gone"/> <ListView android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:orientation="vertical" android:id="@+id/listview" android:layout_gravity="center_horizontal" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="80dp" android:gravity="center" android:background="@color/transparent"> <ImageButton android:layout_width="40dp" android:layout_height="40dp" android:id="@+id/imb_dialog_select_close" android:scaleType="centerInside" android:src="@drawable/dialog_close" android:background="@color/transparent"/> </LinearLayout></LinearLayout>
Dialog Java文件
package com.whieenz.searchselect;import android.app.Activity;import android.app.Dialog;import android.content.Context;import android.content.DialogInterface;import android.util.DisplayMetrics;import android.view.Gravity;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.view.Window;import android.view.WindowManager;import android.widget.AdapterView;import android.widget.ImageButton;import android.widget.ListView;import android.widget.TextView;import java.util.ArrayList;import java.util.List;/** * Created by whieenz on 2017/7/18. */public class SerachSelectDialog extends Dialog {  public SerachSelectDialog(Context context, int themeResId) {    super(context, themeResId);  }  /**   * 设置 Dialog的大小   * @param x 宽比例   * @param y 高比例   */  public void setDialogWindowAttr(double x, double y, Activity activity){    if (x<0||x>1||y<0||y>1){      return;    }    Window window = this.getWindow();    WindowManager.LayoutParams lp = window.getAttributes();    WindowManager manager = activity.getWindowManager();    DisplayMetrics outMetrics = new DisplayMetrics();    manager.getDefaultDisplay().getMetrics(outMetrics);    int width = outMetrics.widthPixels;    int height = outMetrics.heightPixels;    lp.gravity = Gravity.CENTER;    lp.width = (int) (width * x);    lp.height = (int) (height * y);    this.getWindow().setAttributes(lp);  }  public static class Builder {    private String title;    private View contentView;    private String positiveButtonText;    private String negativeButtonText;    private String singleButtonText;    private List<String> listData;    private View.OnClickListener positiveButtonClickListener;    private View.OnClickListener negativeButtonClickListener;    private View.OnClickListener singleButtonClickListener;    private View layout;    private Context context;    private SerachSelectDialog dialog;    private OnSelectedListiner selectedListiner;    ListView listView;    //SearchView searchView ;    DialogSearchView searchView;    ImageButton searchBtn;    ImageButton closeBtn;    TextView titleView;    private boolean state = false;    public Builder(Context context) {      //这里传入自定义的style,直接影响此Dialog的显示效果。style具体实现见style.xml      this.context = context;      dialog = new SerachSelectDialog(context,R.style.selectDialog);      LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);      layout = inflater.inflate(R.layout.dialog_select_search, null);      listView = (ListView)layout.findViewById(R.id.listview);      //searchView = (SearchView) layout.findViewById(R.id.searchView);      searchView = (DialogSearchView) layout.findViewById(R.id.searchView);      searchBtn = (ImageButton) layout.findViewById(R.id.btn_dialog_select_search);      closeBtn = (ImageButton) layout.findViewById(R.id.imb_dialog_select_close);      titleView = (TextView) layout.findViewById(R.id.tv_dialog_select_title);      dialog.addContentView(layout, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));    }    public Builder setTitle(String title) {      this.title = title;      return this;    }    public Builder setContentView(View v) {      this.contentView = v;      return this;    }    public void setListData(List<String> listData) {      this.listData = listData;    }    public Builder setPositiveButton(String positiveButtonText, View.OnClickListener listener) {      this.positiveButtonText = positiveButtonText;      this.positiveButtonClickListener = listener;      return this;    }    public Builder setNegativeButton(String negativeButtonText, View.OnClickListener listener) {      this.negativeButtonText = negativeButtonText;      this.negativeButtonClickListener = listener;      return this;    }    /**     * 单按钮对话框和双按钮对话框的公共部分在这里设置     */    private SerachSelectDialog create() {      titleView.setText(title);      final SearchSelectAdapter sa = new SearchSelectAdapter(context,listData);      listView.setAdapter(sa);      listView.invalidate();      searchBtn.setOnClickListener(new View.OnClickListener() {        @Override        public void onClick(View view) {          if (!state){            searchView.setVisibility(View.VISIBLE);            state = true;          }else {            searchView.setVisibility(View.GONE);            state = false;          }        }      });      searchView.setDialogSearchViewListener(new DialogSearchView.DialogSearchViewListener() {        @Override        public boolean onQueryTextChange(String text) {          updateLayout(searchItem(text));          return false;        }      });      closeBtn.setOnClickListener(new View.OnClickListener() {        @Override        public void onClick(View v) {          dialog.dismiss();        }      });      dialog.setOnDismissListener(new DialogInterface.OnDismissListener() {        @Override        public void onDismiss(DialogInterface dialog) {        }      });      listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {        @Override        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {          selectedListiner.onSelected(sa.getItem(position));          dialog.dismiss();        }      });      dialog.setContentView(layout);      //用户可以点击手机Back键取消对话框显示      dialog.setCancelable(true);      //用户不能通过点击对话框之外的地方取消对话框显示      dialog.setCanceledOnTouchOutside(false);      return dialog;    }    public List<String> searchItem(String name) {      ArrayList<String> mSearchList = new ArrayList<String>();      for (int i = 0; i < listData.size(); i++) {        int index = listData.get(i).indexOf(name);        // 存在匹配的数据        if (index != -1) {          mSearchList.add(listData.get(i));        }      }      return mSearchList;    }    public void updateLayout(List<String> newList) {      final SearchSelectAdapter sa = new SearchSelectAdapter(context,newList);      listView.setAdapter(sa);      listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {        @Override        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {          selectedListiner.onSelected(sa.getItem(position));          dialog.dismiss();        }      });    }    public void setSelectedListiner(SerachSelectDialog.Builder.OnSelectedListiner selectedListiner) {      this.selectedListiner = selectedListiner;    }    public static abstract class OnSelectedListiner{      public abstract void onSelected(String String);    }    public SerachSelectDialog show() {      create();      dialog.show();      return dialog;    }  }}二、自定义SearchView
SearchView 布局文件
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:gravity="center" android:background="#ffffff" android:layout_height="50dp"> <LinearLayout android:layout_width="match_parent" android:layout_height="35dp" android:orientation="horizontal" android:gravity="center_vertical" android:layout_marginLeft="15dp" android:layout_marginRight="15dp" android:background="@drawable/search_layout_bg"> <ImageButton android:layout_width="20dp" android:layout_height="20dp" android:id="@+id/imb_search_search" android:layout_marginLeft="15dp" android:scaleType="centerInside" android:src="@drawable/im_search_gray" android:background="#F0F0F0" /> <EditText android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="10dp" android:layout_marginRight="15dp" android:id="@+id/et_search_text" android:layout_weight="1" android:lines="1" android:textSize="14sp" android:background="@null" android:hint="请输入搜索内容"/> <ImageButton android:layout_width="35dp" android:layout_height="35dp" android:padding="12.5dp" android:id="@+id/imb_search_clear" android:layout_marginRight="20dp" android:src="@drawable/im_x" android:visibility="gone" android:scaleType="centerInside" android:background="#F0F0F0" /> </LinearLayout></LinearLayout>
SearchView Java代码
package com.whieenz.searchselect;import android.content.Context;import android.text.Editable;import android.text.TextWatcher;import android.util.AttributeSet;import android.view.LayoutInflater;import android.view.View;import android.widget.EditText;import android.widget.ImageView;import android.widget.LinearLayout;/** * Created by whieenz on 2017/7/19. */public class DialogSearchView extends LinearLayout implements View.OnClickListener {  /**   * 输入框    */  private EditText etInput;  /**   * 删除键    */  private ImageView ivDelete;  /**   * 上下文对象    */  private Context mContext;  /**   * 搜索回调接口    */  private DialogSearchViewListener mListener;  /**   * 设置搜索回调接口    *   * @param listener 监听者    */  public void setDialogSearchViewListener(DialogSearchViewListener listener) {    mListener = listener;  }  public DialogSearchView(Context context, AttributeSet attrs) {    super(context, attrs);    mContext = context;    LayoutInflater.from(context).inflate(R.layout.view_search_layout, this);    initViews();  }  private void initViews() {    etInput = (EditText) findViewById(R.id.et_search_text);    ivDelete = (ImageView) findViewById(R.id.imb_search_clear);    ivDelete.setOnClickListener(this);    etInput.addTextChangedListener(new EditChangedListener());    etInput.setOnClickListener(this);  }  private class EditChangedListener implements TextWatcher {    @Override    public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) {    }    @Override    public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) {      if (!"".equals(charSequence.toString())) {        ivDelete.setVisibility(VISIBLE);        //更新autoComplete数据        if (mListener != null) {          mListener.onQueryTextChange(charSequence + "");        }      } else {        ivDelete.setVisibility(GONE);      }    }    @Override    public void afterTextChanged(Editable editable) {    }  }  @Override  public void onClick(View view) {    switch (view.getId()) {      case R.id.imb_search_clear:        etInput.setText("");        if (mListener != null) {          mListener.onQueryTextChange("");        }        ivDelete.setVisibility(GONE);        break;    }  }  /**   * search view回调方法    */  public interface DialogSearchViewListener {    boolean onQueryTextChange(String text);  }} 自定义ListView Adapter
listItem 布局文件
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="50dp" android:paddingLeft="10dp" android:paddingTop="15dp" android:paddingBottom="15dp" android:orientation="horizontal"> <TextView android:id="@+id/tv_select_info" android:layout_width="match_parent" android:layout_height="match_parent" android:textSize="20sp" android:layout_centerInParent="true" android:gravity="center" android:lines="1"/></RelativeLayout>
Adapter 文件
package com.whieenz.searchselect;import android.content.Context;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;import android.widget.TextView;import java.util.List;public class SearchSelectAdapter extends BaseAdapter {  private List<String> Datas;  private Context context;  private LayoutInflater inflater;  public SearchSelectAdapter(Context ctx, List<String> datas){    this.context = ctx;    this.Datas = datas;    this.inflater = LayoutInflater.from(ctx);  }  @Override  public int getCount() {    return Datas.size();  }  @Override  public String getItem(int i) {    return Datas.get(i);  }  @Override  public long getItemId(int i) {    return i;  }  @Override  public View getView(int i, View view, ViewGroup viewGroup) {    ViewHolder holder = null;    if (view == null ) {      view = inflater.inflate(R.layout.list_cell_select_single, null);      holder = new ViewHolder(view);      view.setTag(holder);    } else {      holder = (ViewHolder) view.getTag();    }    holder.info.setText(Datas.get(i));    return view;  }  static class ViewHolder {    TextView info;    public ViewHolder(View view) {      info = view.findViewById(R.id.tv_select_info);    }  }}MainActivity 实现
布局文件
<?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:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="10dp" tools:context="com.whieenz.searchselect.MainActivity"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="150dp" android:orientation="horizontal"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="20sp" android:gravity="left" android:text="选择结果:" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="20sp" android:textColor="#ff5c5c" android:id="@+id/tv_result" /> </LinearLayout> <Button android:layout_width="match_parent" android:layout_height="40dp" android:layout_marginTop="20dp" android:gravity="center" android:textSize="20sp" android:textColor="#ffffff" android:background="@drawable/btn_bg" android:text="打开选择器" android:onClick="doSelect"/></LinearLayout>
Java文件
package com.whieenz.searchselect;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.view.View;import android.widget.TextView;import java.util.ArrayList;import java.util.List;public class MainActivity extends AppCompatActivity { private List<String> mDatas; private TextView textView; @Override protected void onCreate(Bundle savedInstanceState) {  super.onCreate(savedInstanceState);  setContentView(R.layout.activity_main);  textView = (TextView) findViewById(R.id.tv_result);  initData(); } public void doSelect(View view){  SerachSelectDialog.Builder alert = new SerachSelectDialog.Builder(this);  alert.setListData(mDatas);  alert.setTitle("请选择城市");  alert.setSelectedListiner(new SerachSelectDialog.Builder.OnSelectedListiner() {   @Override   public void onSelected(String info) {    textView.setText(info);   }  });  SerachSelectDialog mDialog = alert.show();  //设置Dialog 尺寸  mDialog.setDialogWindowAttr(0.9,0.9,this); } /**  * 初始化数据  */ private void initData(){  mDatas = new ArrayList<>();  String [] citys = {"武汉","北京","上海","深圳","兰州","成都","天津"};  for (int i = 0; i < 10; i++) {   for (int j = 0; j < citys.length; j++) {    mDatas.add(citys[j]+i);   }  } }}其他配置
Dialog style(样式)
<style name="selectDialog" parent="@android:style/Theme.Dialog"> <item name="android:windowNoTitle">true</item>//无标题 <item name="android:windowBackground">@color/transparent</item> </style>
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持武林网。
新闻热点
疑难解答