Android 自定义搜索框(带搜索图标、清除图标、语音图标)

相信大家都用过android自带的SearchView,至于疗效如何相信用过的人都知道。既然自带的搜索框疗效不足,那我们就来自己定义。本篇文章是在EditText上给大家自定义搜索框,并且带了搜索图标,清除图标,语音图标。
按照国际惯例,先给大家上最后的效果图:
Android 自定义搜索框(带搜索图标、清除图标、语音图标)_第1张图片
输入值后:
Android 自定义搜索框(带搜索图标、清除图标、语音图标)_第2张图片

接下来我们来看看到底是如何自定义EditTextSearch的:
public class EditTextSearch extends AppCompatEditText {
        /**
         * 步骤1:定义左侧搜索图标 & 一键删除图标 & 语音图标
         */
        private Drawable clearDrawable,searchDrawable,voiceDrawable;
        private Context context;

        private boolean isShowClear;

        public EditTextSearch(Context context) {
            super(context);
            this.context = context;
            init();
            // 初始化该组件时,对EditText_Clear进行初始化 ->>步骤2
        }

        public EditTextSearch(Context context, AttributeSet attrs) {
            super(context, attrs);
            this.context = context;
            init();
        }

        public EditTextSearch(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            this.context = context;
            init();
        }

        /**
         * 步骤2:初始化 图标资源
         */
        private void init() {
            clearDrawable = getResources().getDrawable(R.drawable.delete_icon);
            searchDrawable = getResources().getDrawable(R.drawable.search_icon);
            voiceDrawable = getResources().getDrawable(R.drawable.voice_icon);
            setCompoundDrawablesWithIntrinsicBounds(searchDrawable, null,
                    voiceDrawable, null);
            // setCompoundDrawablesWithIntrinsicBounds(Drawable left, Drawable top, Drawable right, Drawable bottom)介绍
            // 作用:在EditText上、下、左、右设置图标(相当于android:drawableLeft=""  android:drawableRight="")
            // 注1:setCompoundDrawablesWithIntrinsicBounds()传入的Drawable的宽高=固有宽高(自动通过getIntrinsicWidth()& getIntrinsicHeight()获取)
            // 注2:若不想在某个地方显示,则设置为null
            // 此处设置了左侧搜索图标

            // 另外一个相似的方法:setCompoundDrawables(Drawable left, Drawable top, Drawable right, Drawable bottom)介绍
            // 与setCompoundDrawablesWithIntrinsicBounds()的区别:可设置图标大小
            // 传入的Drawable对象必须已经setBounds(x,y,width,height),即必须设置过初始位置、宽和高等信息
            // x:组件在容器X轴上的起点 y:组件在容器Y轴上的起点 width:组件的长度 height:组件的高度
        }


        /**
         * 步骤3:通过监听复写EditText本身的方法来确定是否显示删除图标
         * 监听方法:onTextChanged() & onFocusChanged()
         * 调用时刻:当输入框内容变化时 & 焦点发生变化时
         */

        @Override
        protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
            super.onTextChanged(text, start, lengthBefore, lengthAfter);
            setClearIconVisible(hasFocus() && text.length() > 0);
            // hasFocus()返回是否获得EditTEXT的焦点,即是否选中
            // setClearIconVisible() = 根据传入的是否选中 & 是否有输入来判断是否显示删除图标->>关注1
        }

        @Override
        protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
            super.onFocusChanged(focused, direction, previouslyFocusedRect);
            setClearIconVisible(focused && length() > 0);
            // focused = 是否获得焦点
            // 同样根据setClearIconVisible()判断是否要显示删除图标
        }

        /**
         * 关注1
         * 作用:判断是否显示删除图标
         * 当显示删除图标时就隐藏语音图标
         */
        private void setClearIconVisible(boolean visible) {
            isShowClear = visible;
            setCompoundDrawablesWithIntrinsicBounds(searchDrawable, null,
                    visible ? clearDrawable : voiceDrawable, null);
        }

        /**
         * 步骤4:对删除图标区域设置点击事件,即"点击 = 清空搜索框内容"
         * 原理:当手指抬起的位置在删除图标的区域,即视为点击了删除图标 = 清空搜索框内容
         */
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            switch (event.getAction()) {
                // 原理:当手指抬起的位置在删除图标的区域,即视为点击了删除图标 = 清空搜索框内容
                // isShowClear:为true,点击删除图标;为false,点击语音图标
                case MotionEvent.ACTION_UP:
                    if (isShowClear){
                        Drawable drawable = clearDrawable;
                        if (drawable != null && event.getX() <= (getWidth() - getPaddingRight())
                                && event.getX() >= (getWidth() - getPaddingRight() - drawable.getBounds().width())) {
                            setText("");
                             Toast.makeText(context,"点击了清除图标",Toast.LENGTH_SHORT).show();
                        }
                    }else {
                        Drawable drawable = voiceDrawable;
                        if (drawable != null && event.getX() <= (getWidth() - getPaddingRight())
                                && event.getX() >= (getWidth() - getPaddingRight() - drawable.getBounds().width())) {
                            Toast.makeText(context,"点击了语音图标",Toast.LENGTH_SHORT).show();
                        }
                    }

                    // 判断条件说明
                    // event.getX() :抬起时的位置坐标
                    // getWidth():控件的宽度
                    // getPaddingRight():删除图标图标右边缘至EditText控件右边缘的距离
                    // 即:getWidth() - getPaddingRight() = 删除图标的右边缘坐标 = X1
                    // getWidth() - getPaddingRight() - drawable.getBounds().width() = 删除图标左边缘的坐标 = X2
                    // 所以X1与X2之间的区域 = 删除图标的区域
                    // 当手指抬起的位置在删除图标的区域(X2=
                    // 具体示意图请看下图
                    break;
            }
            return super.onTouchEvent(event);
        }
        
}

上面的自定义EditTextSearch,继承于AppCompatEditText。首先我们通过init()定义了private Drawable clearDrawable,searchDrawable,voiceDrawable;三个图标,然后通过setCompoundDrawablesWithIntrinsicBounds方法初始化显示了搜索图标和语音图标。然后我们去监控EditText的值和焦点变化。当有输入值时就显示清除图标,不显示语音图标(两个图标对立,有我没它,有它没我):setCompoundDrawablesWithIntrinsicBounds(searchDrawable, null,
visible ? clearDrawable : voiceDrawable, null); 最后我们通过onTouchEvent来监控操作,我们到底点击的是清除图标还是语音图标,然后各自执行它们自己的功能。到这里自定义搜索框就完全的实现了,是不是很简单?
接下来我们就来看看如何去使用这个自定义的搜索框控件。
布局文件:
android:paddingLeft=“5dp” //设置搜索图标离左边框的距离
android:paddingRight=“5dp” //设置语音图或者清除图标离右边框的距离
android:background="@drawable/search_edit_round" //这个是我自己写的圆角背景

  <cn.xie.ourctrip.view.EditTextSearch
            android:layout_marginLeft="10dp"
            android:layout_marginRight="10dp"
            android:layout_centerInParent="true"
            android:layout_toRightOf="@+id/back"
            android:layout_toLeftOf="@+id/search_to"
            android:id="@+id/search_text"
            android:background="@drawable/search_edit_round"
            android:layout_width="match_parent"
            android:layout_height="30dp"
            android:paddingLeft="5dp"
            android:paddingRight="5dp"/>  

search_edit_round圆角白色背景:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <corners android:radius="10dp"/>

    <stroke android:color="@android:color/white"/>

    <solid android:color="@android:color/white"/>

</shape>

这样就已经完成了。随你在哪里调用了。

你可能感兴趣的:(Android)