欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

可支持快速搜索筛选的Android自定义选择控件

程序员文章站 2023-08-25 13:11:16
android 自定义支持快速搜索筛选的选择控件使用方法,具体如下 项目中遇到选择控件选项过多,需要快速查找匹配的情况。 做了简单的demo,效果图如下: 源码地址...

android 自定义支持快速搜索筛选的选择控件使用方法,具体如下

项目中遇到选择控件选项过多,需要快速查找匹配的情况。
做了简单的demo,效果图如下:

源码地址:https://github.com/whieenz/searchselect

可支持快速搜索筛选的Android自定义选择控件

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

可支持快速搜索筛选的Android自定义选择控件

一、自定义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>

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。