Android自定义View之有动画特效带清除按钮的输入框

概述:最近项目中,UI妹子需要我实现以下效果:这里写图片描述 这里写图片描述 中间的文字和搜索图标慢慢向左移动。

最后我实现的效果:这里写图片描述 在以前的项目中也实现过类似的功能只是少了动画的效果也是用自定义控件实现的传送门,不过这次和上次实现的方式大不一样。至于哪里不一样,请接着往下看。源码地址:点我下载吧,老铁

一 分析

在以前的实现中,我们使用了继承控件的自定义view实现方式。具体实现步骤,请查看以前的博客,传送门。其实两次的效果很明显可以发现只有多了动画这一点区别。在EditText中我们是没有办法用动画控制文字的移动的,所以我们考虑用组合控件的自定义view实现方式让EditText整个移动,达到我们想要的效果。

二 思路

在考虑使用组合控件自定义View实现之后,很明显我们的布局中有一个EditText接受我们的点击和输入事件,一个ImageView接受点击清除EditText内容的。最开始 ImageView在最右边,EditText的宽度是wrap_content居中的, 然后使用动画让整个EditText向左移动,在移动的过程中让EditText的宽度慢慢变成match_parent。考虑上面的种种情况,最终决定使用约束布局ConstraintLayout的方式实现。至于对ConstraintLayout还不熟悉的小伙伴,请阅读以下两篇文章:ConstraintLayout基础ConstraintLayout使用ConstraintLayout动画

三 实现

(1)布局实现
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/constraint_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:id="@+id/iv_clear"
        android:layout_width="30dp"
        android:layout_height="30dp"
        android:layout_marginRight="10dp"
        android:padding="4dp"
        android:src="@drawable/btn_search_clear"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <EditText
        android:id="@+id/et"
        android:layout_width="wrap_content"
        android:layout_height="0dp"
        android:background="@null"
        android:cursorVisible="false"
        android:drawableLeft="@drawable/icon_search"
        android:drawablePadding="5dp"
        android:focusable="false"
        android:hint="搜索商品\品牌"
        android:paddingLeft="10dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="@+id/iv_clear"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>
如果你阅读了上面推荐的ConstraintLayout博客,相信很容易就能读懂上面的布局代码,这里就不再赘述。
(2)自定义属性
<resources>
    <!-- 带动画效果的有清楚按钮的EditText-->
    <declare-styleable name="ConstraintEditText">
        <!--imageView的宽 -->
        <attr name="cet_iv_width" format="dimension|reference" />
        <!--imageView的高 -->
        <attr name="cet_iv_height" format="dimension|reference" />
        <!--imageView的图片 -->
        <attr name="cet_iv_src" format="reference" />
        <!--imageView的padding,通过这个属性和宽高可以设置图片显示大小以及点击区域的大小 -->
        <attr name="cet_iv_padding" format="dimension|reference" />
        <!--imageView的marginRight,通过这个属性可以这是图片距离父控件的右边距离 -->
        <attr name="cet_iv_marginRight" format="dimension|reference" />


        <!--EditText背景 没有背景的时候默认为@null-->
        <attr name="cet_et_bg" format="reference" />
        <!--EditText左边搜索图标-->
        <attr name="cet_et_left_drawable" format="reference" />
        <!--EditText左边搜索图标距离文字位置-->
        <attr name="cet_et_drawablePadding" format="reference" />
        <!--EditText距离imageView距离-->
        <attr name="cet_et_marginRight" format="dimension|reference" />
        <!--EditText距离父控件左边距离-->
        <attr name="cet_et_marginLeft" format="dimension|reference" />
        <!--EditText是否显示光标-->
        <attr name="cet_et_cursorVisible" format="boolean" />
        <!--EditText初始是否获取焦点-->
        <attr name="cet_et_focusable" format="boolean" />
        <!--EditText图片左边距离本身控件左边的距离-->
        <attr name="cet_et_paddingLeft" format="dimension|reference" />
        <!--EditText提示文字-->
        <attr name="cet_et_hint_text" format="string|reference" />
        <!--EditText提示文字大小-->
        <attr name="cet_et_hint_text_size" format="dimension|reference" />
        <!--EditText提示文字颜色-->
        <attr name="cet_et_text_hint_color" format="color|reference" />
        <!--EditText输入文字-->
        <attr name="cet_et_text" format="string|reference" />
        <!--EditText输入文字大小-->
        <attr name="cet_et_text_size" format="dimension|reference" />
        <!--EditText输入文字颜色-->
        <attr name="cet_et_text_color" format="color|reference" />

    </declare-styleable>

</resources>
为了考虑效果和美观以及多种情况,属性有点多,注释很详细,不再解释。
(3)获取自定义属性
private void init(Context context, AttributeSet attrs, int defStyleAttr) {
    ConstraintLayout.inflate(context, R.layout.layout_contraint_clear_edit_text, this);
    TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.ConstraintEditText, defStyleAttr, 0);
    // imageView
    cet_iv_width = array.getDimensionPixelSize(R.styleable.ConstraintEditText_cet_iv_width, 0);
    cet_iv_height = array.getDimensionPixelSize(R.styleable.ConstraintEditText_cet_iv_height, 0);
    cet_iv_src = array.getDrawable(R.styleable.ConstraintEditText_cet_iv_src);
    cet_iv_padding = array.getDimensionPixelSize(R.styleable.ConstraintEditText_cet_iv_padding, 0);
    cet_iv_marginRight = array.getDimensionPixelSize(R.styleable.ConstraintEditText_cet_iv_marginRight, 0);

    //EditText
    cet_et_bg = array.getDrawable(R.styleable.ConstraintEditText_cet_et_bg);
    cet_et_left_drawable = array.getDrawable(R.styleable.ConstraintEditText_cet_et_left_drawable);
    cet_et_cursorVisible = array.getBoolean(R.styleable.ConstraintEditText_cet_et_cursorVisible, false);
    cet_et_focusable = array.getBoolean(R.styleable.ConstraintEditText_cet_et_focusable, false);

    cet_et_marginLeft = array.getDimensionPixelSize(R.styleable.ConstraintEditText_cet_et_marginLeft, 0);
    cet_et_marginRight = array.getDimensionPixelSize(R.styleable.ConstraintEditText_cet_et_marginRight, 0);
    cet_et_drawablePadding = array.getDimensionPixelSize(R.styleable.ConstraintEditText_cet_et_drawablePadding, 0);

    cet_et_paddingLeft = array.getDimensionPixelSize(R.styleable.ConstraintEditText_cet_et_paddingLeft, 0);
    cet_et_hint_text = array.getString(R.styleable.ConstraintEditText_cet_et_hint_text);
    cet_et_text = array.getString(R.styleable.ConstraintEditText_cet_et_text);
    cet_et_hint_text_size = array.getDimension(R.styleable.ConstraintEditText_cet_et_hint_text_size, 16);
    cet_et_text_size = array.getDimension(R.styleable.ConstraintEditText_cet_et_text_size, 18);
    cet_et_text_hint_color = array.getColor(R.styleable.ConstraintEditText_cet_et_text_hint_color, Color.BLACK);
    cet_et_text_color = array.getColor(R.styleable.ConstraintEditText_cet_et_text_color, Color.BLACK);


    array.recycle();
}
api都很基础不再赘述。
(4)初始化控件
    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        constraintLayout = findViewById(R.id.constraint_layout);
        ivClear = findViewById(R.id.iv_clear);
        et = findViewById(R.id.et);

        setImageViewValue();
        setEditTextValue();

        mConstraintSet = new ConstraintSet();
        mConstraintSet.clone(constraintLayout);

        initListener();

    }
   //初始imageview的值
    private void setImageViewValue() {
        ivClear.getLayoutParams().width = cet_iv_width;
        ivClear.getLayoutParams().height = cet_iv_height;
        ivClear.setImageDrawable(cet_iv_src);
        ivClear.setPadding(cet_iv_padding, cet_iv_padding, cet_iv_padding, cet_iv_padding);
        setMargins(ivClear, 0, 0, cet_iv_marginRight, 0);
    }  
// 初始化EditTex的值
    private void setEditTextValue() {
        et.setBackgroundDrawable(cet_et_bg);
        if (cet_et_left_drawable != null) {
            cet_et_left_drawable.setBounds(0, 0, cet_et_left_drawable.getMinimumWidth(), cet_et_left_drawable.getMinimumHeight());
            et.setCompoundDrawables(cet_et_left_drawable, null, null, null);
        }
        et.setCompoundDrawablePadding(cet_et_drawablePadding);
        setMargins(et, cet_et_marginLeft, 0, cet_et_marginRight, 0);
        et.setPadding(cet_et_paddingLeft, 0, 0, 0);
        et.setCursorVisible(cet_et_cursorVisible);
        et.setFocusable(cet_et_focusable);
        et.setText(cet_et_text);
        et.setHintTextColor(cet_et_text_hint_color);
        et.setTextColor(cet_et_text_color);
        et.setTextSize(TypedValue.COMPLEX_UNIT_PX, cet_et_text_size);
        SpannableString ss = new SpannableString(cet_et_hint_text);//定义hint的值
        AbsoluteSizeSpan ass = new AbsoluteSizeSpan((int) cet_et_hint_text_size, true);//设置字体大小 true表示单位是sp
        ss.setSpan(ass, 0, ss.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        et.setHint(new SpannedString(ss));
    }  
// 设置监听

    private void initListener() {
        //默认设置隐藏图标
        setClearIconVisible(false);
        //清除按钮监听
        ivClear.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
                et.setText("");
            }
        });
        // 设置EditText点击之后的动画 以及焦点设置
        et.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
                if (!flag) {
                    //动画
                    showAnimal();
                    et.setEnabled(true);
                    et.setFocusable(true);//可以通过键盘得到焦点
                    et.setFocusableInTouchMode(true);//可以通过触摸得到焦点
                    ivClear.setVisibility(GONE);
                    flag = true;
                }
            }
        });


        //设置输入框里面内容发生改变的监听
        et.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

            }

            @Override
            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
                if (mHasFocus) {
                    setClearIconVisible(charSequence.length() > 0);
                }
            }

            @Override
            public void afterTextChanged(Editable editable) {

            }
        });
        // 焦点变化监听
        et.setOnFocusChangeListener(new OnFocusChangeListener() {
            @Override
            public void onFocusChange(View view, boolean hasFocus) {
                mHasFocus = hasFocus;
                if (hasFocus) {
                    setClearIconVisible(et.getText().length() > 0);
                } else {
                    setClearIconVisible(false);
                }
            }
        });
    }
(5)动画
   private void showAnimal() {
        TransitionManager.beginDelayedTransition(constraintLayout);
        mConstraintSet.clear(R.id.et);

        mConstraintSet.connect(R.id.et, ConstraintSet.LEFT, R.id.constraint_layout, ConstraintSet.LEFT, 1000);
        mConstraintSet.connect(R.id.et, ConstraintSet.RIGHT, R.id.iv_clear, ConstraintSet.LEFT);
        mConstraintSet.connect(R.id.et, ConstraintSet.TOP, R.id.constraint_layout, ConstraintSet.TOP);
        mConstraintSet.connect(R.id.et, ConstraintSet.BOTTOM, R.id.constraint_layout, ConstraintSet.BOTTOM);

        mConstraintSet.applyTo(constraintLayout);
    }
只要是看了上面推荐的ConstraintLayout动画介绍这点效果简直是easy啊。

四 源码

下载地址,点我吧,老铁

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
TypeArray 是 Android 中的一个特殊的资源类型,用于在 XML 中声明自定义 View 的属性。使用 TypeArray 可以方便地在 XML 布局中指定 View 的属性,而不需要在 Java 代码中进行硬编码。 使用 TypeArray 的步骤如下: 1. 在 res/values/attrs.xml 文件中定义自定义 View 的属性。 ```xml <resources> <declare-styleable name="MyCustomView"> <attr name="customAttr1" format="integer" /> <attr name="customAttr2" format="string" /> <attr name="customAttr3" format="boolean" /> </declare-styleable> </resources> ``` 2. 在自定义 View 的构造函数中获取 TypedArray 对象,并从中获取属性值。 ```java public class MyCustomView extends View { private int customAttr1; private String customAttr2; private boolean customAttr3; public MyCustomView(Context context, AttributeSet attrs) { super(context, attrs); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MyCustomView); customAttr1 = a.getInt(R.styleable.MyCustomView_customAttr1, 0); customAttr2 = a.getString(R.styleable.MyCustomView_customAttr2); customAttr3 = a.getBoolean(R.styleable.MyCustomView_customAttr3, false); a.recycle(); } } ``` 在上面的代码中,`context.obtainStyledAttributes(attrs, R.styleable.MyCustomView)` 用于获取 TypedArray 对象,`R.styleable.MyCustomView` 是在 attrs.xml 文件中定义的自定义属性集合,`a.getInt()`、`a.getString()`、`a.getBoolean()` 用于从 TypedArray 对象中获取属性值,最后需要调用 `a.recycle()` 来回收 TypedArray 对象。 3. 在 XML 布局中使用自定义 View,并设置属性值。 ```xml <com.example.MyCustomView android:layout_width="match_parent" android:layout_height="wrap_content" app:customAttr1="123" app:customAttr2="hello" app:customAttr3="true" /> ``` 在上面的代码中,`app:customAttr1`、`app:customAttr2`、`app:customAttr3` 是在 attrs.xml 文件中定义的自定义属性名,可以在 XML 布局中使用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值