-
前言
以前有接触过这个,不过也只是看到github上面的,看起来很炫酷,最近有看动画这一方面,所以突然兴致大发, 简简单单实现一个自定义的View, 纯动画, 没有什么需要计算的地方.
-
效果图
-
使用方法
-
在app/build.gradle中添加下面一行代码:
dependencies { compile 'com.example.thatnight:animbutton:1.5' }
-
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" //字体大小 />
-
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一行代码就能是实现,.