自定义viewAndroid原生控件集中营android经验

和我一起实现EditText一键清空功能

2016-06-21  本文已影响6120人  积木Blocks

在实际项目中我们经常看到这样的效果:


一键清除功能

这就是我们常说的一键清除功能,Android并没有自带的API供我们使用,所以我们需要自己来编写,下面我将介绍常见实现方式.


1.常见的实现方式

目前主要实现的方式有2种:

2种方式的优劣


2.自定义EditText实现一键清除功能

这里我会基于第二种实现方式一步步实现一键清除的EditText控件,相信你也会选择第二种实现方式吧,毕竟一切为了优化(偷懒)。

步骤1:创建一个控件继承于EditText并实现其构造方法
public class OneKeyClearEditText extends AppCompatEditText {

    public OneKeyClearEditText(Context context) {
        this(context, null);
    }

    public OneKeyClearEditText(Context context, AttributeSet attrs) {
        this(context, attrs, R.attr.editTextStyle);
    }

    public OneKeyClearEditText(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

特别说明:R.attr.editTextStyle是源码中AppCompatEditText,由于使用了AppCompatEditText,所以我们需要依赖V7包,如果没有可以简信我,主题也需要是Theme.AppCompat,我这里为了看的清楚在AndroidManifest.xml中使用的主题是:Theme.AppCompat.Light。

步骤2:利用EditText的CompoundDrawables设置删除图标
private Drawable mClearDrawable;// 一键删除的按钮
private int colorAccent;//获得主题的颜色
@SuppressLint("InlinedApi")
    public OneKeyClearEditText(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray array = context.getTheme()
                .obtainStyledAttributes(new int[] {android.R.attr.colorAccent});
        colorAccent = array.getColor(0, 0xFF00FF);
        array.recycle();
        initClearDrawable(context);
    }

    @SuppressLint("NewApi")
    private void initClearDrawable(Context context) {
        mClearDrawable = getCompoundDrawables()[2];// 获取EditText的DrawableRight,假如没有设置我们就使用默认的图片
        if (mClearDrawable == null) {
            mClearDrawable = getResources().getDrawable(R.drawable.ic_delete_01, context.getTheme());
        }
        DrawableCompat.setTint(mClearDrawable, colorAccent);//设置删除按钮的颜色和TextColor的颜色一致
        mClearDrawable.setBounds(0, 0, (int) getTextSize(), (int) getTextSize());//设置Drawable的宽高和TextSize的大小一致
        setClearIconVisible(true);

    }

    /**
     * 设置清除图标的显示与隐藏,调用setCompoundDrawables为EditText绘制上去
     *
     * @param visible
     */
    private void setClearIconVisible(boolean visible) {
        Drawable right = visible ? mClearDrawable : null;
        setCompoundDrawables(getCompoundDrawables()[0], getCompoundDrawables()[1], right, getCompoundDrawables()[3]);
    }

这一步主要是为了设置删除的图标,图标的颜色和colorAccent颜色一致,大小和TextSize一致,解决适配的问题。

先在布局设置colorAccent为红色

    <!-- Application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light">
        <!-- All customizations that are NOT specific to a particular API-level can go here. -->
        <item name="colorAccent">#ff0000</item>
    </style>

下面我们看看效果图:

一键清除样式.png
效果还是不错的,到这里基本的UI样式就完成了,目前的控件还只是个“花瓶”,点击的方法还没有实现,接下来我们来实现点击的事件。
步骤3:实现删除图标的点击事件

我们知道Drawable本身没有点击事件,那么怎么办呢?这里从写了onTouch事件,然后模拟点击的区域(图标大小)来现实点击事件:

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        if (mClearDrawable != null && event.getAction() == MotionEvent.ACTION_UP) {
            int x = (int) event.getX();
            // 判断触摸点是否在水平范围内
            boolean isInnerWidth = (x > (getWidth() - getTotalPaddingRight()))
                    && (x < (getWidth() - getPaddingRight()));
            // 获取删除图标的边界,返回一个Rect对象
            Rect rect = mClearDrawable.getBounds();
            // 获取删除图标的高度
            int height = rect.height();
            int y = (int) event.getY();
            // 计算图标底部到控件底部的距离
            int distance = (getHeight() - height) / 2;
            // 判断触摸点是否在竖直范围内(可能会有点误差)
            // 触摸点的纵坐标在distance到(distance+图标自身的高度)之内,则视为点中删除图标
            boolean isInnerHeight = (y > distance) && (y < (distance + height));
            if (isInnerHeight && isInnerWidth) {
                this.setText("");
         Toast.makeText(getContext(), "一键清除", Toast.LENGTH_SHORT).show();//为了看清效果,测试
            }
        }
        return super.onTouchEvent(event);
    }

如果在EditText的范围和图标的范围之类,则表示有效。

下面看看效果:

一键清除.gif

到现在已经实现了一键清除功能了,可是功能还不够完善,我们需要在获取焦点并且有文字内容的时候才显示删除图标,下面继续开始优化。

步骤4: 对获取焦点已经文字输入进行监听优化体验
    private boolean hasFocus;// 控件是否有焦点
    
    private void initClearDrawable(Context context) {
        ...
        setClearIconVisible(true);
        // 设置焦点改变的监听
        setOnFocusChangeListener(this);
        // 设置输入框里面内容发生改变的监听
        addTextChangedListener(this);

    }
    @Override
    public void onFocusChange(View v, boolean hasFocus) {
        this.hasFocus = hasFocus;
        if (hasFocus) {
            setClearIconVisible(getText().length() > 0);
        } else {
            setClearIconVisible(false);
        }
        
    }
   /**
     * 当输入框里面内容发生变化的时候回调的方法
     */
    @Override
    public void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
        if (hasFocus) {
            setClearIconVisible(text.length() > 0);
        }
    }
    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
        // TODO Auto-generated method stub
        
    }

    @Override
    public void afterTextChanged(Editable s) {
        // TODO Auto-generated method stub
        
    }

基本代码就是这样,在获取焦点和文字输入之前判断是否有文字,从而决定是否显示图标。

** 效果:**

一键删除1.0.gif

3.优化OneKeyClearEditText(一键删除控件)

上面基本是实现了一键清除的功能,对于图标的颜色,有些人可能需要自己定义,这里补充一个方法,

添加自定义属性

        TypedArray array2 = context.obtainStyledAttributes(attrs,R.styleable.OneKeyClearEditText);
        DrawableColor = array2.getColor(R.styleable.OneKeyClearEditText_deletecolor, colorAccent);
        array2.recycle();
                ...     
DrawableCompat.setTint(mClearDrawable, DrawableColor);// 设置删除按钮的颜色和TextColor的颜色一致

values-attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <declare-styleable name="OneKeyClearEditText">
        <attr name="deletecolor" format="reference|color" />
    </declare-styleable>

</resources>

使用

    <com.yh.clearedittextdemo.view.OneKeyClearEditText
        android:id="@+id/okcet"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:drawableRight="@drawable/ic_delete_03"
        android:hint="请输入手机"
        android:textCursorDrawable="@drawable/cursor"
        app:deletecolor="@android:color/holo_orange_dark" />

最后修改了游标的颜色,下面展示效果:(修改游标颜色:http://www.jianshu.com/p/660e93e1064f

最后样式

4.源码地址

http://download.csdn.net/detail/android_yh/9555816


5.感谢

参考地址:


6.总结

核心技术:

这是EditText系列的第三篇:
EditText(第1章)-游标位置和样式
EditText(第2章)-对hint进行整容

接下来我将实现EditText的密码可见与隐藏的功能。
如有侵权,麻烦简信我,我会及时修改。
如果这篇文章对你有帮助,请点下“喜欢”~

上一篇下一篇

猜你喜欢

热点阅读