Android 一行代码实现炫酷Button

  • 前言

    以前有接触过这个,不过也只是看到github上面的,看起来很炫酷,最近有看动画这一方面,所以突然兴致大发, 简简单单实现一个自定义的View, 纯动画, 没有什么需要计算的地方.

  • 效果图

    img

  • 使用方法

  1. 在app/build.gradle中添加下面一行代码:

    dependencies {
        compile 'com.example.thatnight:animbutton:1.5'
    }
    
  2. layout.xml中

    <com.example.animbutton.AnimButton
        android:id="@+id/rl"
        android:layout_width="match_parent"
        android:layout_height="@dimen/button_height"
        app:color_normal="@color/colorPrimary"		//正常button颜色
        app:color_pressed="@color/colorPrimaryDark"	//按下button颜色
        app:color_progress="@color/colorPrimaryDark"//进度条颜色
        app:color_text="@color/white"			   //字体颜色		
        app:button_radius="0"					  //button圆角
        app:duration="300"             //动画时长
        app:start_text="Login"         //默认字符串
        app:end_text="Error"           //错误字符串
        app:size_text="15sp"           //字体大小
        />
    
  3. activity中

    private AnimButton mButton;
    private ProgressBar mProgress;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mButton = (AnimButton) findViewById(R.id.rl);
        mButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //todo
            }
        });
    }
    

    就跟原先的Button一样的使用方法.很简单吧


  • 主要代码

    • 布局文件
    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout      xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:anim="http://schemas.android.com/apk/res-auto"
        android:id="@+id/rl_button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
    
        <RelativeLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true">
            <Button
                android:id="@+id/button"
                android:layout_width="match_parent"
                android:layout_height="@dimen/button_height"
                android:layout_centerInParent="true"
                android:layout_margin="10dp"
                android:gravity="center"
                android:textColor="@color/white"
                android:textSize="18sp"
              />
        </RelativeLayout>
    
        <RelativeLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true">
            <ProgressBar
                android:id="@+id/pb_button"
                android:layout_width="wrap_content"
                android:layout_height="@dimen/button_height"
                android:layout_centerInParent="true"
                android:alpha="0"
                android:indeterminateDuration="300" />
        </RelativeLayout>
    </RelativeLayout>
    
      很简单, 就一个button和一个progressbar, 这都是系统自带的应用, 我这里只不过是将它们组合在一起了而已
    
      ---
    
    • AnimButton

      先来看看构造方法

      public AnimButton(Context context) {
          this(context, null);
      }
      
      public AnimButton(Context context, @Nullable AttributeSet attrs) {
          this(context, attrs, 0);
      }
      
      public AnimButton(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
          super(context, attrs, defStyleAttr);
          TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AnimButton);
          mStartText = a.getString(R.styleable.AnimButton_start_text);
          mEndText = a.getString(R.styleable.AnimButton_end_text);
          mDuration = a.getInt(R.styleable.AnimButton_duration, 300);
          mNormalColor = a.getColor(R.styleable.AnimButton_color_normal, ContextCompat.getColor(context, R.color.colorPrimary));
          mPressedColor = a.getColor(R.styleable.AnimButton_color_pressed, ContextCompat.getColor(context, R.color.colorPrimaryDark));
          mProgressColor = a.getColor(R.styleable.AnimButton_color_progress, ContextCompat.getColor(context, R.color.colorAccent));
          mTextColor = a.getColor(R.styleable.AnimButton_color_text, ContextCompat.getColor(context, R.color.colorAccent));
          mRadius = a.getFloat(R.styleable.AnimButton_button_radius, 0);
          a.recycle();
      
          //inflate layout
          LayoutInflater.from(context).inflate(R.layout.fm_button_progress, this, true);
          mProgress = (ProgressBar) findViewById(R.id.pb_button);
          setProgressDrawable(context);
          mTarget = (Button) findViewById(R.id.button);
          setWrapper(mTarget);
          buildDrawableState();
      
          if (mStartText != null && mStartText.length() > 0) {
              mTarget.setText(mStartText);
          }
      }
      

      这里三个构造方法其实只有一个会运行, 就是第三个, 其他两个修改了this(…), 这里是个坑

      这里先是获取自定义的属性, 然后是很普通的绑定控, setWrapper后面会讲


      接下里看看buildDrawableState(), 也就是创建button和ProgressBar的样式

      /**
       * change the button drawable
       */
      private void buildDrawableState() {
          float radius[] = new float[]{mRadius, mRadius, mRadius, mRadius, mRadius, mRadius, mRadius, mRadius};
          StateListDrawable drawable = new StateListDrawable();
      
          RoundRectShape rectShape = new RoundRectShape(radius, null, null);
          ShapeDrawable pressedDrawable = new ShapeDrawable(rectShape);
          pressedDrawable.getPaint().setColor(mPressedColor);
          drawable.addState(mPressedState, pressedDrawable);
      
          ShapeDrawable normalDrawable = new ShapeDrawable(rectShape);
          normalDrawable.getPaint().setColor(mNormalColor);
          drawable.addState(mNormalState, normalDrawable);
          mTarget.setBackground(drawable);
          mTarget.setTextColor(mTextColor);
      }
      
      /**
       * change the progressbar drawable     * Build.VERSION >= 21(5.0)
       * @param context
       */
      private void setProgressDrawable(Context context) {
          if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
              RotateDrawable rotateDrawable = (RotateDrawable) ContextCompat.getDrawable(context, R.drawable.bg_progress);
              GradientDrawable gradientDrawable = (GradientDrawable) rotateDrawable.getDrawable();
              if (gradientDrawable != null) {
                  gradientDrawable.setColors(new int[]{mProgressColor, Color.WHITE});
                  rotateDrawable.setDrawable(gradientDrawable);
                  mProgress.setIndeterminateDrawable(rotateDrawable);
              }
          }
      }
      

      我们看看主要的动画代码

      开始动画
      public void startAnimation() {
      if (mStartSet == null) {
          initStartAnim();
          initErrorAnim();
      }
      mStartSet.start();
      }   
      

      再看看初始化动画这里, 使用的是ObjectAnimator对象动画,我觉得实现起来很简单.

      if (mProgress == null || mTarget == null) {
          try {
              throw new Exception("No binding a progress or target");
          } catch (Exception e) {
              e.printStackTrace();
          }
      }
      mStartSet = new AnimatorSet();
      ObjectAnimator progressAnim = ObjectAnimator.ofFloat(mProgress, "alpha", 1);
      progressAnim.addListener(new AnimatorListenerAdapter() {
          @Override
          public void onAnimationEnd(Animator animation) {
              super.onAnimationEnd(animation);
          }
      
          @Override
          public void onAnimationStart(Animator animation) {
              super.onAnimationStart(animation);
              mTarget.setText("");
              mTarget.setClickable(false);
          }
      });
      ObjectAnimator startAnim = ObjectAnimator.ofInt(mViewWrapper, "width", mWidth, mHeight);
      startAnim.addListener(new AnimatorListenerAdapter() {
          @Override
          public void onAnimationEnd(Animator animation) {
              super.onAnimationEnd(animation);
          }
      });
      mStartSet.setDuration(mDuration);
      mStartSet.playTogether(progressAnim, startAnim);
      

      其实效果就是改变button的宽度, 主要是使用了viewwrapper来修改button的宽度

      什么是ViewWrapper, 就是用来实现button的width,get和set方法, 虽然本来button就有这两个方法,但是是写死的了.

       private static class ViewWrapper {
      private View mTarget;
      
      public ViewWrapper(View target) {
          mTarget = target;
      }
      
      public int getWidth() {
          return mTarget.getLayoutParams().width;
      }
      
      public void setWidth(int width) {
          mTarget.getLayoutParams().width = width;
          mTarget.requestLayout();
      }
      }
      

      复原动画这里就不贴代码了,同样的道理. 那么动画就这么完成了, 不对, 我还没讲button的宽度和高度怎么获取的呢 .


      之前也遇到很多的问题, 所以我今天要讲.

      @Override
      protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
          super.onLayout(changed, left, top, right, bottom);
          if (mWidth == 0 && mHeight == 0) {
              mWidth = mTarget.getMeasuredWidth();
              mHeight = mTarget.getMeasuredHeight();
              mLeft = mTarget.getLeft();
          }
      }
      

      哇, 这么点代码的吗?是的,之前没弄明白的时候, 就一直碰壁, 到处百度google,不得不说, 还是要好好掌握这个基础啊.


  • GitHub

    我做了个这样子的项目, 我觉的我可以让别人很方便的使用, 于是乎, 又有了另外一篇博客, 如何将项目上传到jcenter, 让别人使用gradle一行代码就能是实现,.

    https://github.com/charlie-captain

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值