Android CircleRefreshLayoutドロップダウン・リフレッシュ
53716 ワード
ドロップダウン・リフレッシュの実装、水滴効果.activity_main.xml
MainActivity
カスタムFrameLayout
アニメーションビュー
もちろん、第三者ライブラリを導入する方法で、自分が書いたコードをより明確にすることもできます.
<com.example.listviewrefresh.CircleRefreshLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
app:AniBackColor="#e8eae9"
app:AniForeColor="#ff8b90af"
app:CircleSmaller="6"
android:id="@+id/refresh_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
"@+id/listview"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
com.example.listviewrefresh.CircleRefreshLayout>
MainActivity
refresh_layout =(CircleRefreshLayout)findViewById(R.id.refresh_layout);
refresh_layout.setOnRefreshListener(new CircleRefreshLayout.OnCircleRefreshListener() {
@Override
public void completeRefresh() {
}
@Override
public void refreshing() {
new Handler().postDelayed(new Runnable(){
public void run() {
// dialog
refresh_layout.finishRefreshing();
}
}, 2000);
}
});
カスタムFrameLayout
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.support.annotation.NonNull;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.DecelerateInterpolator;
import android.widget.FrameLayout;
public class CircleRefreshLayout extends FrameLayout {
private static String TAG = "pullToRefresh";
private static final long BACK_TOP_DUR = 600;
private static final long REL_DRAG_DUR = 200;
private int mHeaderBackColor = 0xff8b90af;
private int mHeaderForeColor = 0xffffffff;
private int mHeaderCircleSmaller = 6;
private float mPullHeight;
private float mHeaderHeight;
private View mChildView;
private AnimationView mHeader;
private boolean mIsRefreshing;
private float mTouchStartY;
private float mTouchCurY;
private ValueAnimator mUpBackAnimator;
private ValueAnimator mUpTopAnimator;
private DecelerateInterpolator decelerateInterpolator = new DecelerateInterpolator(10);
public CircleRefreshLayout(Context context) {
this(context, null, 0);
}
public CircleRefreshLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CircleRefreshLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs, defStyleAttr);
}
private void init(Context context, AttributeSet attrs, int defStyleAttr) {
if (getChildCount() > 1) {
throw new RuntimeException("you can only attach one child");
}
setAttrs(attrs);
mPullHeight = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 150, context.getResources().getDisplayMetrics());
mHeaderHeight = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 100, context.getResources().getDisplayMetrics());
this.post(new Runnable() {
@Override
public void run() {
mChildView = getChildAt(0);
addHeaderView();
}
});
}
private void setAttrs(AttributeSet attrs) {
TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.CirCleRefreshLayout);
mHeaderBackColor = a.getColor(R.styleable.CirCleRefreshLayout_AniBackColor, mHeaderBackColor);
mHeaderForeColor = a.getColor(R.styleable.CirCleRefreshLayout_AniForeColor, mHeaderForeColor);
mHeaderCircleSmaller = a.getInt(R.styleable.CirCleRefreshLayout_CircleSmaller, mHeaderCircleSmaller);
a.recycle();
}
private void addHeaderView() {
mHeader = new AnimationView(getContext());
LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 0);
params.gravity = Gravity.TOP;
mHeader.setLayoutParams(params);
addViewInternal(mHeader);
mHeader.setAniBackColor(mHeaderBackColor);
mHeader.setAniForeColor(mHeaderForeColor);
mHeader.setRadius(mHeaderCircleSmaller);
setUpChildAnimation();
}
private void setUpChildAnimation() {
if (mChildView == null) {
return;
}
mUpBackAnimator = ValueAnimator.ofFloat(mPullHeight, mHeaderHeight);
mUpBackAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float val = (float) animation.getAnimatedValue();
if (mChildView != null) {
mChildView.setTranslationY(val);
}
}
});
mUpBackAnimator.setDuration(REL_DRAG_DUR);
mUpTopAnimator = ValueAnimator.ofFloat(mHeaderHeight, 0);
mUpTopAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float val = (float) animation.getAnimatedValue();
val = decelerateInterpolator.getInterpolation(val / mHeaderHeight) * val;
if (mChildView != null) {
mChildView.setTranslationY(val);
}
mHeader.getLayoutParams().height = (int) val;
mHeader.requestLayout();
}
});
mUpTopAnimator.setDuration(BACK_TOP_DUR);
mHeader.setOnViewAniDone(new AnimationView.OnViewAniDone() {
@Override
public void viewAniDone() {
// Log.i(TAG, "should invoke");
mUpTopAnimator.start();
}
});
}
private void addViewInternal(@NonNull View child) {
super.addView(child);
}
@Override
public void addView(View child) {
if (getChildCount() >= 1) {
throw new RuntimeException("you can only attach one child");
}
mChildView = child;
super.addView(child);
setUpChildAnimation();
}
private boolean canChildScrollUp() {
if (mChildView == null) {
return false;
}
return ViewCompat.canScrollVertically(mChildView, -1);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (mIsRefreshing) {
return true;
}
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
mTouchStartY = ev.getY();
mTouchCurY = mTouchStartY;
break;
case MotionEvent.ACTION_MOVE:
float curY = ev.getY();
float dy = curY - mTouchStartY;
if (dy > 0 && !canChildScrollUp()) {
return true;
}
}
return super.onInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (mIsRefreshing) {
return super.onTouchEvent(event);
}
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
mTouchCurY = event.getY();
float dy = mTouchCurY - mTouchStartY;
dy = Math.min(mPullHeight * 2, dy);
dy = Math.max(0, dy);
if (mChildView != null) {
float offsetY = decelerateInterpolator.getInterpolation(dy / 2 / mPullHeight) * dy / 2;
mChildView.setTranslationY(offsetY);
mHeader.getLayoutParams().height = (int) offsetY;
mHeader.requestLayout();
}
return true;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
if (mChildView != null) {
if (mChildView.getTranslationY() >= mHeaderHeight) {
mUpBackAnimator.start();
mHeader.releaseDrag();
mIsRefreshing = true;
if (onCircleRefreshListener!=null) {
onCircleRefreshListener.refreshing();
}
} else {
float height = mChildView.getTranslationY();
ValueAnimator backTopAni = ValueAnimator.ofFloat(height, 0);
backTopAni.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float val = (float) animation.getAnimatedValue();
val = decelerateInterpolator.getInterpolation(val / mHeaderHeight) * val;
if (mChildView != null) {
mChildView.setTranslationY(val);
}
mHeader.getLayoutParams().height = (int) val;
mHeader.requestLayout();
}
});
backTopAni.setDuration((long) (height * BACK_TOP_DUR / mHeaderHeight));
backTopAni.start();
}
}
return true;
default:
return super.onTouchEvent(event);
}
}
public void finishRefreshing() {
if (onCircleRefreshListener != null) {
onCircleRefreshListener.completeRefresh();
}
mIsRefreshing = false;
mHeader.setRefreshing(false);
}
private OnCircleRefreshListener onCircleRefreshListener;
public void setOnRefreshListener(OnCircleRefreshListener onCircleRefreshListener) {
this.onCircleRefreshListener = onCircleRefreshListener;
}
public interface OnCircleRefreshListener {
void completeRefresh();
void refreshing();
}
}
アニメーションビュー
package com.example.listviewrefresh;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
/**
* Created by zhanglei on 15/7/18.
*/
public class AnimationView extends View {
private static final String TAG = "AnimationView";
private int PULL_HEIGHT;
private int PULL_DELTA;
private float mWidthOffset;
private AnimatorStatus mAniStatus = AnimatorStatus.PULL_DOWN;
enum AnimatorStatus {
PULL_DOWN,
DRAG_DOWN,
REL_DRAG,
SPRING_UP, // rebound to up, the position is less than PULL_HEIGHT
POP_BALL,
OUTER_CIR,
REFRESHING,
DONE,
STOP;
@Override
public String toString() {
switch (this) {
case PULL_DOWN:
return "pull down";
case DRAG_DOWN:
return "drag down";
case REL_DRAG:
return "release drag";
case SPRING_UP:
return "spring up";
case POP_BALL:
return "pop ball";
case OUTER_CIR:
return "outer circle";
case REFRESHING:
return "refreshing...";
case DONE:
return "done!";
case STOP:
return "stop";
default:
return "unknown state";
}
}
}
private Paint mBackPaint;
private Paint mBallPaint;
private Paint mOutPaint;
private Path mPath;
public AnimationView(Context context) {
this(context, null, 0);
}
public AnimationView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public AnimationView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView(context, attrs, defStyleAttr);
}
private void initView(Context context, AttributeSet attrs, int defStyleAttr) {
PULL_HEIGHT = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 100, context.getResources().getDisplayMetrics());
PULL_DELTA = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, context.getResources().getDisplayMetrics());
mWidthOffset = 0.5f;
mBackPaint = new Paint();
mBackPaint.setAntiAlias(true);
mBackPaint.setStyle(Paint.Style.FILL);
mBackPaint.setColor(0xff8b90af);
mBallPaint = new Paint();
mBallPaint.setAntiAlias(true);
mBallPaint.setColor(0xffffffff);
mBallPaint.setStyle(Paint.Style.FILL);
mOutPaint = new Paint();
mOutPaint.setAntiAlias(true);
mOutPaint.setColor(0xffffffff);
mOutPaint.setStyle(Paint.Style.STROKE);
mOutPaint.setStrokeWidth(5);
mPath = new Path();
}
private int mRadius;
private int mWidth;
private int mHeight;
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int height = MeasureSpec.getSize(heightMeasureSpec);
if (height > PULL_DELTA + PULL_HEIGHT) {
heightMeasureSpec = MeasureSpec.makeMeasureSpec(PULL_DELTA + PULL_HEIGHT, MeasureSpec.getMode(heightMeasureSpec));
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (changed) {
mRadius = getHeight() / 6;
mWidth = getWidth();
mHeight = getHeight();
if (mHeight < PULL_HEIGHT) {
mAniStatus = AnimatorStatus.PULL_DOWN;
}
switch (mAniStatus) {
case PULL_DOWN:
if (mHeight >= PULL_HEIGHT) {
mAniStatus = AnimatorStatus.DRAG_DOWN;
}
break;
case REL_DRAG:
break;
}
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
switch (mAniStatus) {
case PULL_DOWN:
canvas.drawRect(0, 0, mWidth, mHeight, mBackPaint);
break;
case REL_DRAG:
case DRAG_DOWN:
drawDrag(canvas);
break;
case SPRING_UP:
drawSpring(canvas, getSpringDelta());
invalidate();
break;
case POP_BALL:
drawPopBall(canvas);
invalidate();
break;
case OUTER_CIR:
drawOutCir(canvas);
invalidate();
break;
case REFRESHING:
drawRefreshing(canvas);
invalidate();
break;
case DONE:
drawDone(canvas);
invalidate();
break;
case STOP:
drawDone(canvas);
break;
}
if (mAniStatus == AnimatorStatus.REL_DRAG) {
ViewGroup.LayoutParams params = getLayoutParams();
int height;
// NOTICE: If the height equals mLastHeight, then the requestLayout() will not work correctly
do {
height = getRelHeight();
} while (height == mLastHeight && getRelRatio() != 1);
mLastHeight = height;
params.height = PULL_HEIGHT + height;
requestLayout();
}
}
private void drawDrag(Canvas canvas) {
canvas.drawRect(0, 0, mWidth, PULL_HEIGHT, mBackPaint);
mPath.reset();
mPath.moveTo(0, PULL_HEIGHT);
mPath.quadTo(mWidthOffset * mWidth, PULL_HEIGHT + (mHeight - PULL_HEIGHT) * 2,
mWidth, PULL_HEIGHT);
canvas.drawPath(mPath, mBackPaint);
}
private void drawSpring(Canvas canvas, int springDelta) {
mPath.reset();
mPath.moveTo(0, 0);
mPath.lineTo(0, PULL_HEIGHT);
mPath.quadTo(mWidth / 2, PULL_HEIGHT - springDelta,
mWidth, PULL_HEIGHT);
mPath.lineTo(mWidth, 0);
canvas.drawPath(mPath, mBackPaint);
int curH = PULL_HEIGHT - springDelta / 2;
if (curH > PULL_HEIGHT - PULL_DELTA / 2) {
int leftX = (int) (mWidth / 2 - 2 * mRadius + getSprRatio() * mRadius);
mPath.reset();
mPath.moveTo(leftX, curH);
mPath.quadTo(mWidth / 2, curH - mRadius * getSprRatio() * 2,
mWidth - leftX, curH);
canvas.drawPath(mPath, mBallPaint);
} else {
canvas.drawArc(new RectF(mWidth / 2 - mRadius, curH - mRadius, mWidth / 2 + mRadius, curH + mRadius),
180, 180, true, mBallPaint);
}
}
private void drawPopBall(Canvas canvas) {
mPath.reset();
mPath.moveTo(0, 0);
mPath.lineTo(0, PULL_HEIGHT);
mPath.quadTo(mWidth / 2, PULL_HEIGHT - PULL_DELTA,
mWidth, PULL_HEIGHT);
mPath.lineTo(mWidth, 0);
canvas.drawPath(mPath, mBackPaint);
int cirCentStart = PULL_HEIGHT - PULL_DELTA / 2;
int cirCenY = (int) (cirCentStart - mRadius * 2 * getPopRatio());
canvas.drawArc(new RectF(mWidth / 2 - mRadius, cirCenY - mRadius, mWidth / 2 + mRadius, cirCenY + mRadius),
180, 360, true, mBallPaint);
if (getPopRatio() < 1) {
drawTail(canvas, cirCenY, cirCentStart + 1, getPopRatio());
} else {
canvas.drawCircle(mWidth / 2, cirCenY, mRadius, mBallPaint);
}
}
private void drawTail(Canvas canvas, int centerY, int bottom, float fraction) {
int bezier1w = (int) (mWidth / 2 + (mRadius * 3 / 4) * (1 - fraction));
PointF start = new PointF(mWidth / 2 + mRadius, centerY);
PointF bezier1 = new PointF(bezier1w, bottom);
PointF bezier2 = new PointF(bezier1w + mRadius / 2, bottom);
mPath.reset();
mPath.moveTo(start.x, start.y);
mPath.quadTo(bezier1.x, bezier1.y,
bezier2.x, bezier2.y);
mPath.lineTo(mWidth - bezier2.x, bezier2.y);
mPath.quadTo(mWidth - bezier1.x, bezier1.y,
mWidth - start.x, start.y);
canvas.drawPath(mPath, mBallPaint);
}
private void drawOutCir(Canvas canvas) {
mPath.reset();
mPath.moveTo(0, 0);
mPath.lineTo(0, PULL_HEIGHT);
mPath.quadTo(mWidth / 2, PULL_HEIGHT - (1 - getOutRatio()) * PULL_DELTA,
mWidth, PULL_HEIGHT);
mPath.lineTo(mWidth, 0);
canvas.drawPath(mPath, mBackPaint);
int innerY = PULL_HEIGHT - PULL_DELTA / 2 - mRadius * 2;
canvas.drawCircle(mWidth / 2, innerY, mRadius, mBallPaint);
}
private int mRefreshStart = 90;
private int mRefreshStop = 90;
private int TARGET_DEGREE = 270;
private boolean mIsStart = true;
private boolean mIsRefreshing = true;
private void drawRefreshing(Canvas canvas) {
canvas.drawRect(0, 0, mWidth, mHeight, mBackPaint);
int innerY = PULL_HEIGHT - PULL_DELTA / 2 - mRadius * 2;
canvas.drawCircle(mWidth / 2, innerY, mRadius, mBallPaint);
int outerR = mRadius + 10;
mRefreshStart += mIsStart ? 3 : 10;
mRefreshStop += mIsStart ? 10 : 3;
mRefreshStart = mRefreshStart % 360;
mRefreshStop = mRefreshStop % 360;
int swipe = mRefreshStop - mRefreshStart;
swipe = swipe < 0 ? swipe + 360 : swipe;
canvas.drawArc(new RectF(mWidth / 2 - outerR, innerY - outerR, mWidth / 2 + outerR, innerY + outerR),
mRefreshStart, swipe, false, mOutPaint);
if (swipe >= TARGET_DEGREE) {
mIsStart = false;
} else if (swipe <= 10) {
mIsStart = true;
}
if (!mIsRefreshing) {
applyDone();
}
}
// stop refreshing
public void setRefreshing(boolean isFresh) {
mIsRefreshing = isFresh;
}
private void drawDone(Canvas canvas) {
int beforeColor = mOutPaint.getColor();
if (getDoneRatio() < 0.3) {
canvas.drawRect(0, 0, mWidth, mHeight, mBackPaint);
int innerY = PULL_HEIGHT - PULL_DELTA / 2 - mRadius * 2;
canvas.drawCircle(mWidth / 2, innerY, mRadius, mBallPaint);
int outerR = (int) (mRadius + 10 + 10 * getDoneRatio() / 0.3f);
int afterColor = Color.argb((int) (0xff * (1 - getDoneRatio() / 0.3f)), Color.red(beforeColor),
Color.green(beforeColor), Color.blue(beforeColor));
mOutPaint.setColor(afterColor);
canvas.drawArc(new RectF(mWidth / 2 - outerR, innerY - outerR, mWidth / 2 + outerR, innerY + outerR),
0, 360, false, mOutPaint);
}
mOutPaint.setColor(beforeColor);
if (getDoneRatio() >= 0.3 && getDoneRatio() < 0.7) {
canvas.drawRect(0, 0, mWidth, mHeight, mBackPaint);
float fraction = (getDoneRatio() - 0.3f) / 0.4f;
int startCentY = PULL_HEIGHT - PULL_DELTA / 2 - mRadius * 2;
int curCentY = (int) (startCentY + (PULL_DELTA / 2 + mRadius * 2) * fraction);
canvas.drawCircle(mWidth / 2, curCentY, mRadius, mBallPaint);
if (curCentY >= PULL_HEIGHT - mRadius * 2) {
drawTail(canvas, curCentY, PULL_HEIGHT, (1 - fraction));
}
}
if (getDoneRatio() >= 0.7 && getDoneRatio() <= 1) {
float fraction = (getDoneRatio() - 0.7f) / 0.3f;
canvas.drawRect(0, 0, mWidth, mHeight, mBackPaint);
int leftX = (int) (mWidth / 2 - mRadius - 2 * mRadius * fraction);
mPath.reset();
mPath.moveTo(leftX, PULL_HEIGHT);
mPath.quadTo(mWidth / 2, PULL_HEIGHT - (mRadius * (1 - fraction)),
mWidth - leftX, PULL_HEIGHT);
canvas.drawPath(mPath, mBallPaint);
}
}
private int mLastHeight;
private int getRelHeight() {
return (int) (mSpriDeta * (1 - getRelRatio()));
}
private int getSpringDelta() {
return (int) (PULL_DELTA * getSprRatio());
}
private static long REL_DRAG_DUR = 200;
private long mStart;
private long mStop;
private int mSpriDeta;
public void releaseDrag() {
mStart = System.currentTimeMillis();
mStop = mStart + REL_DRAG_DUR;
mAniStatus = AnimatorStatus.REL_DRAG;
mSpriDeta = mHeight - PULL_HEIGHT;
requestLayout();
}
private float getRelRatio() {
if (System.currentTimeMillis() >= mStop) {
springUp();
return 1;
}
float ratio = (System.currentTimeMillis() - mStart) / (float) REL_DRAG_DUR;
return Math.min(ratio, 1);
}
private static long SPRING_DUR = 200;
private long mSprStart;
private long mSprStop;
private void springUp() {
mSprStart = System.currentTimeMillis();
mSprStop = mSprStart + SPRING_DUR;
mAniStatus = AnimatorStatus.SPRING_UP;
invalidate();
}
private float getSprRatio() {
if (System.currentTimeMillis() >= mSprStop) {
popBall();
return 1;
}
float ratio = (System.currentTimeMillis() - mSprStart) / (float) SPRING_DUR;
return Math.min(1, ratio);
}
private static final long POP_BALL_DUR = 300;
private long mPopStart;
private long mPopStop;
private void popBall() {
mPopStart = System.currentTimeMillis();
mPopStop = mPopStart + POP_BALL_DUR;
mAniStatus = AnimatorStatus.POP_BALL;
invalidate();
}
private float getPopRatio() {
if (System.currentTimeMillis() >= mPopStop) {
startOutCir();
return 1;
}
float ratio = (System.currentTimeMillis() - mPopStart) / (float) POP_BALL_DUR;
return Math.min(ratio, 1);
}
private static final long OUTER_DUR = 200;
private long mOutStart;
private long mOutStop;
private void startOutCir() {
mOutStart = System.currentTimeMillis();
mOutStop = mOutStart + OUTER_DUR;
mAniStatus = AnimatorStatus.OUTER_CIR;
mRefreshStart = 90;
mRefreshStop = 90;
TARGET_DEGREE = 270;
mIsStart = true;
mIsRefreshing = true;
invalidate();
}
private float getOutRatio() {
if (System.currentTimeMillis() >= mOutStop) {
mAniStatus = AnimatorStatus.REFRESHING;
mIsRefreshing = true;
return 1;
}
float ratio = (System.currentTimeMillis() - mOutStart) / (float) OUTER_DUR;
return Math.min(ratio, 1);
}
private static final long DONE_DUR = 1000;
private long mDoneStart;
private long mDoneStop;
private void applyDone() {
mDoneStart = System.currentTimeMillis();
mDoneStop = mDoneStart + DONE_DUR;
mAniStatus = AnimatorStatus.DONE;
}
private float getDoneRatio() {
if (System.currentTimeMillis() >= mDoneStop) {
mAniStatus = AnimatorStatus.STOP;
if (onViewAniDone != null) {
onViewAniDone.viewAniDone();
}
return 1;
}
float ratio = (System.currentTimeMillis() - mDoneStart) / (float) DONE_DUR;
return Math.min(ratio, 1);
}
private OnViewAniDone onViewAniDone;
public void setOnViewAniDone(OnViewAniDone onViewAniDone) {
this.onViewAniDone = onViewAniDone;
}
interface OnViewAniDone {
void viewAniDone();
}
public void setAniBackColor(int color) {
mBackPaint.setColor(color);
}
public void setAniForeColor(int color) {
mBallPaint.setColor(color);
mOutPaint.setColor(color);
setBackgroundColor(color);
}
// the height of view is smallTimes times of circle radius
public void setRadius(int smallTimes) {
mRadius = mHeight / smallTimes;
}
}
もちろん、第三者ライブラリを導入する方法で、自分が書いたコードをより明確にすることもできます.