自定義控制元件之58同城載入
阿新 • • 發佈:2019-01-02
分析:這是一個組合控制元件加上屬性動畫來實現,佈局是一個線性佈局,一個變化的控制元件ShapeView,圓形,正方形,三角形不斷變換,底部還有一個陰影,先下落動畫和縮放,接著上拋和縮放動畫並旋轉,通過動畫監聽來控制旋轉動畫。效果如下圖所示
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:orientation="vertical" android:background="#FFFFFF" android:gravity="center" android:layout_height="match_parent"> <com.cmj.myview.view.ShapeView android:id="@+id/shape_view" android:layout_width="25dp" android:layout_marginBottom="82dp" android:layout_height="25dp" /> <View android:id="@+id/shadow_view" android:background="@drawable/loading_shadow_bg" android:layout_width="25dp" android:layout_height="3dp"/> <TextView android:layout_marginTop="5dp" android:layout_width="wrap_content" android:text="玩命記載中..." android:layout_height="wrap_content" /> </LinearLayout>
陰影佈局
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="#000000"/>
</shape>
/**
* @author [email protected]
* @date 2018/12/17
* 先下落動畫,同時縮放,接著上拋動畫,同時旋轉
*/
public class ShapeView extends View { private Shape mCurrentShape = Shape.Circle; private Paint mPaint; private Path mPath; public ShapeView(Context context) { this(context, null); } public ShapeView(Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); } public ShapeView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mPaint = new Paint(); mPaint.setAntiAlias(true); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); //只保證正方形 int width = MeasureSpec.getSize(widthMeasureSpec); int height = MeasureSpec.getSize(heightMeasureSpec); setMeasuredDimension(Math.min(width, height), Math.min(width, height)); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); switch (mCurrentShape) { case Circle: //畫圓形 int center = getWidth() / 2; mPaint.setColor(ContextCompat.getColor(getContext(), R.color.circle)); canvas.drawCircle(center,center,center,mPaint); break; case Square: //畫正方形 mPaint.setColor(ContextCompat.getColor(getContext(),R.color.rect)); canvas.drawRect(0,0,getWidth(),getHeight(),mPaint); break; case Triangle: //三角 mPaint.setColor(ContextCompat.getColor(getContext(),R.color.triangle)); if (mPath==null){ mPath = new Path(); mPath.moveTo(getWidth() / 2, 0); mPath.lineTo(0, (float) ((getWidth()/2)*Math.sqrt(3))); mPath.lineTo(getWidth(), (float) ((getWidth()/2)*Math.sqrt(3))); // path.lineTo(getWidth()/2,0); mPath.close();// 把路徑閉合 } canvas.drawPath(mPath,mPaint); break; } } public Shape getCurrentShape() { return mCurrentShape; } /** * 改變形狀 */ public void exchange() { switch (mCurrentShape) { case Circle: //畫圓形 mCurrentShape=Shape.Square; break; case Square: mCurrentShape=Shape.Triangle; break; case Triangle: mCurrentShape=Shape.Circle; break; } invalidate(); } public enum Shape { Circle, Square, Triangle } }
public class LoadingView extends LinearLayout {
private final ShapeView mShapeView;
private final View mShadowView;
private int mTranslationDistance = 0;
// 動畫執行的時間
private final long ANIMATOR_DURATION = 300;
// 是否停止動畫
private boolean mIsStopAnimator = false;
public LoadingView(Context context) {
this(context, null);
}
public LoadingView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public LoadingView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
inflate(context, R.layout.ui_loading_view, this);
mShapeView = (ShapeView) findViewById(R.id.shape_view);
mShadowView = findViewById(R.id.shadow_view);
mTranslationDistance = dip2px(80);
post(new Runnable() {
@Override
public void run() {
startFallAnimator();
}
});
}
/**
* 開始下落動畫
*/
private void startFallAnimator() {
if (mIsStopAnimator){
return;
}
//下落位移動畫
ObjectAnimator translationY = ObjectAnimator.ofFloat(mShapeView, "translationY", 0, mTranslationDistance);
//配合中間陰影縮小
ObjectAnimator scaleX = ObjectAnimator.ofFloat(mShapeView, "scaleX", 1f, 0.3f);
//組合動畫
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.setDuration(ANIMATOR_DURATION);
//加速差值器
animatorSet.setInterpolator(new AccelerateInterpolator());
animatorSet.playTogether(translationY, scaleX);
animatorSet.start();
animatorSet.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
//改變形狀
mShapeView.exchange();
//下落結束後就進行上拋動畫
startUpAnimator();
}
});
}
/**
* 開始上拋動畫
*/
private void startUpAnimator() {
if (mIsStopAnimator){
return;
}
ObjectAnimator translationY = ObjectAnimator.ofFloat(mShapeView, "translationY", mTranslationDistance, 0);
ObjectAnimator scaleX = ObjectAnimator.ofFloat(mShapeView, "scaleX", 0.3f, 1f);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.setDuration(ANIMATOR_DURATION);
//減速差值器
animatorSet.setInterpolator(new DecelerateInterpolator());
animatorSet.playTogether(translationY, scaleX);
animatorSet.start();
animatorSet.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
//上拋結束就下落
startFallAnimator();
}
@Override
public void onAnimationStart(Animator animation) {
//開始旋轉
startRotateAnimator();
}
});
}
/**
* 開始旋轉動畫
*/
private void startRotateAnimator() {
ObjectAnimator rotationAnimator = null;
switch (mShapeView.getCurrentShape()) {
case Circle:
case Square:
rotationAnimator.ofFloat(mShapeView,"rotation",0,180);
break;
case Triangle:
rotationAnimator.ofFloat(mShapeView,"rotation",0,-120);
break;
}
rotationAnimator.setDuration(ANIMATOR_DURATION);
rotationAnimator.setInterpolator(new DecelerateInterpolator());
rotationAnimator.start();
}
@Override
public void setVisibility(int visibility) {
super.setVisibility(View.INVISIBLE);
//清理動畫
mShapeView.clearAnimation();
mShadowView.clearAnimation();
ViewGroup parent = (ViewGroup) getParent();
if (parent!=null){
parent.removeView(this);
removeAllViews();
}
mIsStopAnimator=true;
}
private int dip2px(int dip) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip, getResources().getDisplayMetrics());
}
}