Android 一行代码实现炫酷Button

来源:互联网 发布:铁道工程就业 知乎 编辑:程序博客网 时间:2024/06/06 06:30
  • 前言

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

  • 效果图

    img

  • 使用方法

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

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

     <com.example.animbutton.AnimButton    android:id="@+id/rl"    android:layout_width="match_parent"    android:layout_height="wrap_content"    app:duration="300"    app:start_text="login"    app:end_text="error"    ></com.example.animbutton.AnimButton>

    需要修改属性的话, 可以按住ctrl+ 鼠标左键 点击fm_button_progress, 如下

    <com.example.animbutton.AnimButton        android:id="@+id/rl"        android:layout_width="match_parent"        android:layout_height="@dimen/button_height"        anim:duration="300"             //动画时长        anim:start_text="Login"         //默认字符串        anim:end_text="Error"           //错误字符串        />
    1. activity中
    private AnimButton mButton;private ProgressBar mProgress;@Overrideprotected 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) {            mButton.startAnimation();        }    });}

    就跟原先的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的宽度和高度怎么获取的呢 .


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

      @Overrideprotected 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/thatnight/AnimButton

原创粉丝点击