天天看点

Android ShrinkButton源码简析

刚刚发现一个开源项目ShrinkButton 感觉挺漂亮的(作者的代码地址:https://github.com/wusp/IndicatorBox#shrinkbutton),

Android ShrinkButton源码简析

可以用在很多地方,登录的时候或者图片上传的时候,

代码不是很难就拿出来研究一下,并且稍微改动了一下更加符合自己的需求。简单介绍一下代码的思路.

ShrinkButton,设置圆角背景,radius 25dp, 高度45dp 当你点击按钮时候,button将会动态缩小自己的宽度。

利用属性动画里valueAnimator 将宽度缩小到与高度相等,圆角矩形按钮就变成了圆形按钮。此时再利用属性动画

画进度条。

就完成了,点击登录按钮,按钮变成了进度条的动作。很巧妙。

代码分析如下:

bt = (ShrinkButton)findViewById(R.id.login);
        bt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.e("gac", "login");
                Toast.makeText(MainActivity.this, "login", Toast.LENGTH_SHORT).show();

            }
        });
           

调用如此简单,跟普通的button 调用一样。

那么它是在什么时候让button改变宽度的呢?因为调用了onClickListener.它应该在点击事件上做了文章。

在ShrinkButton 找到事件处理的函数如下:
 @Override
    public boolean onTouch(View v, MotionEvent event) {
        switch (MotionEventCompat.getActionMasked(event)){
            case MotionEvent.ACTION_DOWN:
                if (!isWindowFocused){//如果界面还未完全显示 则此时不进行事件处理
                    return true;
                }
                if (animationState == STATE_EXPANDED){//当按钮的动作状态处于 扩展状态时候,(正常状态时候),此时点击事件发生,开始执行动画效果,
                    startWholeAnimation();              //并且应该onTouch返回fasle,不拦截onClickListener事件 ,按钮动作状态处于其它状态,
                    //this.callOnClick();               //此时onTouch返回true 拦截onClickListener 不让点击事件发生。
                    return false;
                }else{
                    return true;
                }


            case MotionEvent.ACTION_UP:

                return false;
        }
        return true;
    }
           

在这里你可以找到按钮状态变化的入口点startWholeAnimatoin

此时你需要搞明白一个变量animationState

public static final int STATE_EXPANDED = ;//按钮属于正常状态
    public static final int STATE_SHRINKING = ;//按钮属于 正在收缩动作的状态
    public static final int STATE_SHRINKED = ;//按钮完成收缩动作的状态
    public static final int STATE_PROGRESSING = ;//按钮处于进度条执行状态
    public static final int STATE_EXPANDING = ;//按钮处于 由进度条变为正常状态的动作时候
           

作者代码命名挺规范的,基本看变量名就知道按钮的状态了。

public void startWholeAnimation(){
        //animationState > 0 说明按钮此时不是正常状态,那么不管他处于什么状态,我们基本这个方法不需要执行了
        //这个方法是让按钮从正常状态变为进度条状态 isWindowFocused 是界面是否显示的变量 界面没有显示直接return
        if (animationState >  || !isWindowFocused){
            return;
        }
        //Initial those animation fraction firstly.
         initAnimationParameters();
         //初始化两个animation 收缩的animation和 进度条的animation
        if (mShrinkingController == null || mProgressingController == null){
            initShrinkingAnimationController();
            initProgressingAnimationController();
        }
        if (mShrinkingController.isRunning() || mProgressingController.isRunning()){
            mShrinkingController.end();
            mShrinkingController.cancel();
            mProgressingController.end();
            mProgressingController.cancel();
        }
        //执行收缩animation动作
        mShrinkingController.start();
    }
           

我们先来分析initShrinkingAnimationController这个方法:

大概思路就是,动作开始时候讲button的文本内容去掉,然后,改变animastate这个变量状态,

在动作变化的时候,lp.width = (int) (mButtonInitialWidth - (mButtonInitialWidth - lp.height) * (float) animation.getAnimatedValue());

lp.width不断变化,根据这个值animation.getAnimatedValue(0,1)最后lp.width = lp.height;

这样button就会变成一个园。

此时动作结束按钮 startProgressAnimation开始执行进度条animation

//button 开始收缩的的动作

private void initShrinkingAnimationController(){
        mShrinkingController = ValueAnimator.ofFloat(, );
        mShrinkingController.setDuration(mShrinkingDuration);
        mShrinkingController.setInterpolator(new DecelerateInterpolator());
        mShrinkingController.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                //不断更新按钮的宽度
                ViewGroup.LayoutParams lp = getLayoutParams();
                //最后放缩到button 宽高值一样 ,高的设置为45dp
                lp.width = (int) (mButtonInitialWidth - (mButtonInitialWidth - lp.height) * (float) animation.getAnimatedValue());
                setLayoutParams(lp);
            }
        });
        mShrinkingController.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {
                //Make text disappeared.
                buttonText = getText().toString();
                setText(null);
               // setEnabled(false);
                animationState = STATE_SHRINKING;
            }

            @Override
            public void onAnimationEnd(Animator animation) {
                animationState = STATE_SHRINKED;
                //放缩完成后 开始执行 进度条动作
                //setBackground(generateCircleDrawable(Color.RED));
                startProgressingAnimation();
            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });
    }
           

进度条的变化,作者将代码分离出来,利用一个接口。为什么别人代码写的总是那么好。

哎!

我改动的地方仅仅是,onTouch方法,我任务按钮处于正常状态,可以有点击事件。处于其它状态时候

点击事件应该不可以用的。

继续阅读