Android custom selection control that supports quick search filtering (1)

Android custom selection control that supports quick search filtering

There are too many selection control options in the project, and you need to quickly find a match.
Made a simple Demo, the effect is as follows:

Source address: https://github.com/whienz/SearchSelect

image

This control is implemented by Dialog+SearchView+ListView. Dialog is used to carry selection controls, SearchView implements input, and ListView displays results. The design outline is as follows:

image

1. Custom Dialog

Dialog layout file

<?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 file

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;
        }
    }
}

2. Customize SearchView

SearchView layout file

<?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 code

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);
    }
}  

Custom ListView Adapter

listItem layout file

<?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 file

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 implementation

layout file

<?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 file

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);
            }
        }
    }
}

Other configuration

Dialog style

    <style name="selectDialog" parent="@android:style/Theme.Dialog">
        <item name="android:windowNoTitle">true</item>//无标题
        <item name="android:windowBackground">@color/transparent</item>
    </style>

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326841779&siteId=291194637