Android 가 뛰 는 작은 공 에 애니메이션 효 과 를 불 러 옵 니 다.
뛰 는 작은 공 을 이 애니메이션 으로 만 들 려 면 파악 해 야 합 니 다.
1.속성 애니메이션
2.Path 류,Canvas 류
3.베 세 르 곡선
4.Surface View 사용법
5.사용자 정의 attr 속성
6.구조:상태 모드,컨트롤 러
7.자유 낙하,포물선 등 개념
더 이상 말 하지 않 고 바로 코드 를 올리다.
1.DancingView.java
public class DancingView extends SurfaceView implements SurfaceHolder.Callback {
public static final int STATE_DOWN = 1;//
public static final int STATE_UP = 2;//
public static final int DEFAULT_POINT_RADIUS = 10;
public static final int DEFAULT_BALL_RADIUS = 13;
public static final int DEFAULT_LINE_WIDTH = 200;
public static final int DEFAULT_LINE_HEIGHT = 2;
public static final int DEFAULT_LINE_COLOR = Color.parseColor("#FF9800");
public static final int DEFAULT_POINT_COLOR = Color.parseColor("#9C27B0");
public static final int DEFAULT_BALL_COLOR = Color.parseColor("#FF4081");
public static final int DEFAULT_DOWN_DURATION = 600;//ms
public static final int DEFAULT_UP_DURATION = 600;//ms
public static final int DEFAULT_FREEDOWN_DURATION = 1000;//ms
public static final int MAX_OFFSET_Y = 50;//
public int PONIT_RADIUS = DEFAULT_POINT_RADIUS;//
public int BALL_RADIUS = DEFAULT_BALL_RADIUS;//
private Paint mPaint;
private Path mPath;
private int mLineColor;
private int mPonitColor;
private int mBallColor;
private int mLineWidth;
private int mLineHeight;
private float mDownDistance;
private float mUpDistance;
private float freeBallDistance;
private ValueAnimator mDownController;//
private ValueAnimator mUpController;//
private ValueAnimator mFreeDownController;//
private AnimatorSet animatorSet;
private int state;
private boolean ismUpControllerDied = false;
private boolean isAnimationShowing = false;
private boolean isBounced = false;
private boolean isBallFreeUp = false;
public DancingView(Context context) {
super(context);
init(context, null);
}
public DancingView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public DancingView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
initAttributes(context, attrs);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setStrokeWidth(mLineHeight);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPath = new Path();
getHolder().addCallback(this);
initController();
}
private void initAttributes(Context context, AttributeSet attrs) {
TypedArray typeArray = context.obtainStyledAttributes(attrs, R.styleable.DancingView);
mLineColor = typeArray.getColor(R.styleable.DancingView_lineColor, DEFAULT_LINE_COLOR);
mLineWidth = typeArray.getDimensionPixelOffset(R.styleable.DancingView_lineWidth, DEFAULT_LINE_WIDTH);
mLineHeight = typeArray.getDimensionPixelOffset(R.styleable.DancingView_lineHeight, DEFAULT_LINE_HEIGHT);
mPonitColor = typeArray.getColor(R.styleable.DancingView_pointColor, DEFAULT_POINT_COLOR);
mBallColor = typeArray.getColor(R.styleable.DancingView_ballColor, DEFAULT_BALL_COLOR);
typeArray.recycle();
}
private void initController() {
mDownController = ValueAnimator.ofFloat(0, 1);
mDownController.setDuration(DEFAULT_DOWN_DURATION);
mDownController.setInterpolator(new DecelerateInterpolator());
mDownController.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mDownDistance = MAX_OFFSET_Y * (float) animation.getAnimatedValue();
postInvalidate();
}
});
mDownController.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
state = STATE_DOWN;
}
@Override
public void onAnimationEnd(Animator animation) {
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
mUpController = ValueAnimator.ofFloat(0, 1);
mUpController.setDuration(DEFAULT_UP_DURATION);
mUpController.setInterpolator(new DancingInterpolator());
mUpController.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mUpDistance = MAX_OFFSET_Y * (float) animation.getAnimatedValue();
if (mUpDistance >= MAX_OFFSET_Y) {
//
isBounced = true;
if (!mFreeDownController.isRunning() && !mFreeDownController.isStarted() && !isBallFreeUp) {
mFreeDownController.start();
}
}
postInvalidate();
}
});
mUpController.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
state = STATE_UP;
}
@Override
public void onAnimationEnd(Animator animation) {
ismUpControllerDied = true;
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
mFreeDownController = ValueAnimator.ofFloat(0, 8f);
mFreeDownController.setDuration(DEFAULT_FREEDOWN_DURATION);
mFreeDownController.setInterpolator(new DecelerateInterpolator());
mFreeDownController.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//
float t = (float) animation.getAnimatedValue();
freeBallDistance = 40 * t - 5 * t * t;
if (ismUpControllerDied) {// ,
postInvalidate();
}
}
});
mFreeDownController.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
isBallFreeUp = true;
}
@Override
public void onAnimationEnd(Animator animation) {
isAnimationShowing = false;
//
startAnimations();
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
animatorSet = new AnimatorSet();
animatorSet.play(mDownController).before(mUpController);
animatorSet.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
isAnimationShowing = true;
}
@Override
public void onAnimationEnd(Animator animation) {
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
}
/**
* ,
*/
public void startAnimations() {
if (isAnimationShowing) {
return;
}
if (animatorSet.isRunning()) {
animatorSet.end();
animatorSet.cancel();
}
isBounced = false;
isBallFreeUp = false;
ismUpControllerDied = false;
animatorSet.start();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//
mPaint.setColor(mLineColor);
mPath.reset();
//
mPath.moveTo(getWidth() / 2 - mLineWidth / 2, getHeight() / 2);
if (state == STATE_DOWN) {//
/************** *************/
//
mPath.quadTo((float) (getWidth() / 2 - mLineWidth / 2 + mLineWidth * 0.375), getHeight() / 2 + mDownDistance,
getWidth() / 2, getHeight() / 2 + mDownDistance);
//
mPath.quadTo((float) (getWidth() / 2 + mLineWidth / 2 - mLineWidth * 0.375), getHeight() / 2 + mDownDistance,
getWidth() / 2 + mLineWidth / 2, getHeight() / 2);
mPaint.setStyle(Paint.Style.STROKE);
canvas.drawPath(mPath, mPaint);
/************** *************/
/************** *************/
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(mBallColor);
canvas.drawCircle(getWidth() / 2, getHeight() / 2 + mDownDistance - BALL_RADIUS, BALL_RADIUS, mPaint);
/************** *************/
} else if (state == STATE_UP) { //
/************** *************/
//
mPath.quadTo((float) (getWidth() / 2 - mLineWidth / 2 + mLineWidth * 0.375), getHeight() / 2 + 50 - mUpDistance,
getWidth() / 2,
getHeight() / 2 + (50 - mUpDistance));
//
mPath.quadTo((float) (getWidth() / 2 + mLineWidth / 2 - mLineWidth * 0.375), getHeight() / 2 + 50 - mUpDistance,
getWidth() / 2 + mLineWidth / 2,
getHeight() / 2);
mPaint.setStyle(Paint.Style.STROKE);
canvas.drawPath(mPath, mPaint);
/************** *************/
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(mBallColor);
// ,
if (!isBounced) {
//
canvas.drawCircle(getWidth() / 2, getHeight() / 2 + (MAX_OFFSET_Y - mUpDistance) - BALL_RADIUS, BALL_RADIUS, mPaint);
} else {
//
canvas.drawCircle(getWidth() / 2, getHeight() / 2 - freeBallDistance - BALL_RADIUS, BALL_RADIUS, mPaint);
}
}
mPaint.setColor(mPonitColor);
mPaint.setStyle(Paint.Style.FILL);
canvas.drawCircle(getWidth() / 2 - mLineWidth / 2, getHeight() / 2, PONIT_RADIUS, mPaint);
canvas.drawCircle(getWidth() / 2 + mLineWidth / 2, getHeight() / 2, PONIT_RADIUS, mPaint);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
Canvas canvas = holder.lockCanvas();// SurfaceView , Surface Canvas.
draw(canvas);
holder.unlockCanvasAndPost(canvas);// ,
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
}
2.DancingInterpolator.java
public class DancingInterpolator implements Interpolator {
@Override
public float getInterpolation(float input) {
return (float) (1 - Math.exp(-3 * input) * Math.cos(10 * input));
}
}
3.사용자 정의 속성 styles.xml
<declare-styleable name="DancingView">
<attr name="lineWidth" format="dimension" />
<attr name="lineHeight" format="dimension" />
<attr name="pointColor" format="reference|color" />
<attr name="lineColor" format="reference|color" />
<attr name="ballColor" format="reference|color" />
</declare-styleable>
메모:색상,사이즈,파 라 메 터 는 스스로 테스트 하고 조정 할 수 있 습 니 다.이상 은 본 고의 모든 내용 입 니 다.여러분 의 학습 과 업무 에 도움 이 되 기 를 바 랍 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Kotlin의 기초 - 2부지난 글에서는 Kotlin이 무엇인지, Kotlin의 특징, Kotlin에서 변수 및 데이터 유형을 선언하는 방법과 같은 Kotlin의 기본 개념에 대해 배웠습니다. 유형 변환은 데이터 변수의 한 유형을 다른 데이터...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.