Android 사용자 정의 View: 체크 작은 애니메이션에 대한 생각 재구성
14771 단어 모바일 개발
먼저 효과도를 올려라, 그렇지 않으면 읽을 수 없다,right?
그림
그림을 그리다.gif
정적 그림
1. 회고
[안드로이드 사용자 정의 View: 정교한 갈고리 애니메이션] 지난 글에서 우리는 기본적으로 컨트롤의 효과를 실현했지만...그런데...사나흘이 지난 후에 자신이 쓴 코드를 자세히 보았는데 생각은 아직 있지만 일부 코드는 단번에 알아볼 수 없었다.
오 마이 갓, 이거 바로 재구성해야죠~ 마침 어떤 네티즌 ChangQin 패러디가 이 컨트롤을 썼는데 저도 보고 이렇게 실현할 수 있을 것 같아요.
2.깊이 생각하다
컨트롤 그리기에 대한 사고방식은 지난 글을 보면 더 이상 분석하지 않을 수 있다.여기에 먼저 지난 글에서 컨트롤 안의 일부 완고한 부분, 어떤 부분을 개선해야 하는지를 분석해 봅시다.
동그라미 진도를 그리는 걸로 볼게요.
//
private int ringCounter = 0;
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (!isChecked) {
...
return;
}
// , 12 , 12
// 12 ,
ringCounter += 12;
if (ringCounter >= 360) {
ringCounter = 360;
}
canvas.drawArc(mRectF, 90, ringCounter, false, mPaintRing);
...
//
postInvalidate();
}
여기에 우리는 계수기
ringCounter
를 정의했는데 그릴 때 12개 단위에 따라 360까지 증가하여 진도의 변화를 시뮬레이션한다.곰곰이 생각하다
3. 고치다
그렇다면 위에서 말한 문제를 어떻게 개선할 것인가. 답은 사용자 정의 속성 애니메이션으로 해결한 것이다. 그래서 이 글에서 주로 다루는 부분은 속성 애니메이션으로 손으로 쓴 계수기를 교체하고 가능한 한 코드 논리의 명확성을 확보하는 것이다. 특히
onDraw()
방법의 코드.속성 애니메이션을 사용하는 장점 중 하나는 수치의 범위를 정하면 당신이 원하는 수치를 만들 수 있고 플러그인에 맞추면 예상치 못한 효과를 얻을 수 있다는 것이다. 다음 부분은 애니메이션이 실행하는 부분을 한 걸음 한 걸음 재구성한다.
3.1 링 진행률 막대 그리기
먼저 사용자 정의
ObjectAnimator
를 사용하여 진행 상황을 시뮬레이션합니다.//ringProgress , 0 - 360,
ObjectAnimator mRingAnimator = ObjectAnimator.ofInt(this, "ringProgress", 0, 360);
// ,
mRingAnimator.setDuration(mRingAnimatorDuration);
//
mRingAnimator.setInterpolator(null);
사용자 정의 속성 애니메이션은 상응하는
setter
와 getter
를 설정해야 한다. 왜냐하면 애니메이션을 실행할 때 상응하는 setter
를 찾아 상응하는 값을 바꾸기 때문이다.private int getRingProgress() {
return ringProgress;
}
private void setRingProgress(int ringProgress) {
// , setter
// , , ondraw
this.ringProgress = ringProgress;
//
postInvalidate();
}
마지막으로
onDraw()
에서 그림을 그립니다.//
canvas.drawArc(mRectF, 90, ringProgress, false, mPaintRing);
3.2 중심점으로 축소하는 애니메이션 그리기
같은 이치로 속성 애니메이션을 만들기도 한다
//
ObjectAnimator mCircleAnimator = ObjectAnimator.ofInt(this, "circleRadius", radius - 5, 0);
//
mCircleAnimator.setInterpolator(new DecelerateInterpolator());
mCircleAnimator.setDuration(mCircleAnimatorDuration);
setter/getter도 비슷해서 말 안 할게요.
마지막
onDraw()
에서 그리기//
mPaintCircle.setColor(checkBaseColor);
canvas.drawCircle(centerX, centerY, ringProgress == 360 ? radius : 0, mPaintCircle);
// ,
if (ringProgress == 360) {
mPaintCircle.setColor(checkTickColor);
canvas.drawCircle(centerX, centerY, circleRadius, mPaintCircle);
}
3.3 갈고리 그리기와 확대 리턴 효과
이것은 두 개의 독립된 효과인데, 여기서 동시에 집행하면, 나는 함께 말하겠다
우선 속성 애니메이션을 정의합니다.
//
ObjectAnimator mAlphaAnimator = ObjectAnimator.ofInt(this, "tickAlpha", 0, 255);
mAlphaAnimator.setDuration(200);
// ,
// ,
// , n ,
ObjectAnimator mScaleAnimator = ObjectAnimator.ofFloat(this, "ringStrokeWidth", mPaintRing.getStrokeWidth(), mPaintRing.getStrokeWidth() * SCALE_TIMES, mPaintRing.getStrokeWidth() / SCALE_TIMES);
mScaleAnimator.setInterpolator(null);
mScaleAnimator.setDuration(mScaleAnimatorDuration);
//
AnimatorSet mAlphaScaleAnimatorSet = new AnimatorSet();
mAlphaScaleAnimatorSet.playTogether(mAlphaAnimator, mScaleAnimator);
getter/setter
private int getTickAlpha() {
return 0;
}
private void setTickAlpha(int tickAlpha) {
// ,
//
mPaintTick.setAlpha(tickAlpha);
postInvalidate();
}
private float getRingStrokeWidth() {
return mPaintRing.getStrokeWidth();
}
private void setRingStrokeWidth(float strokeWidth) {
// ,
//
mPaintRing.setStrokeWidth(strokeWidth);
postInvalidate();
}
마지막으로
onDraw()
에서 그리면 됩니다.if (circleRadius == 0) {
canvas.drawLines(mPoints, mPaintTick);
canvas.drawArc(mRectF, 0, 360, false, mPaintRing);
}
3.4 순서대로 애니메이션 실행
여러 개의 애니메이션을 실행하면
AnimatorSet
에 사용할 수 있습니다. 그 중에서 playTogether()
는 함께 실행하고 playSequentially()
는 하나씩 step by step에서 실행합니다.mFinalAnimatorSet = new AnimatorSet();
mFinalAnimatorSet.playSequentially(mRingAnimator, mCircleAnimator, mAlphaScaleAnimatorSet);
마지막으로
onDraw()
에서 애니메이션을 실행합니다.// , ,
if (!isAnimationRunning) {
isAnimationRunning = true;
//
mFinalAnimatorSet.start();
}
3.5 각 방법마다 단일한 직책이 있는 것이 가장 좋다
만약에 속성 애니메이션을 정의하는 방법을
onDraw()
에 두면 저는 개인적으로 매우 혼란스러워요. 그리고 다시 자세히 보면 이 몇 개의 속성 애니메이션은 동적 변화가 필요 없어요. 왜 처음부터 초기화하지 않았어요?so, 우리는 속성 애니메이션을 정의하는 코드를 추출하여 구조 함수에 초기화할 것이다
public TickView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
...
initAnimatorCounter();
}
/**
* ObjectAnimator
*/
private void initAnimatorCounter() {
//
ObjectAnimator mRingAnimator = ObjectAnimator.ofInt(this, "ringProgress", 0, 360);
...
//
ObjectAnimator mCircleAnimator = ObjectAnimator.ofInt(this, "circleRadius", radius - 5, 0);
...
//
ObjectAnimator mAlphaAnimator = ObjectAnimator.ofInt(this, "tickAlpha", 0, 255);
...
// ,
ObjectAnimator mScaleAnimator = ObjectAnimator.ofFloat(this, "ringStrokeWidth", mPaintRing.getStrokeWidth(), mPaintRing.getStrokeWidth() * SCALE_TIMES, mPaintRing.getStrokeWidth() / SCALE_TIMES);
...
//
AnimatorSet mAlphaScaleAnimatorSet = new AnimatorSet();
mAlphaScaleAnimatorSet.playTogether(mAlphaAnimator, mScaleAnimator);
mFinalAnimatorSet = new AnimatorSet();
mFinalAnimatorSet.playSequentially(mRingAnimator, mCircleAnimator, mAlphaScaleAnimatorSet);
}
마지막으로
onDraw()
방법에서는 간단한 그림만 책임지고 아무것도 상관하지 않는다@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (!isChecked) {
canvas.drawArc(mRectF, 90, 360, false, mPaintRing);
canvas.drawLines(mPoints, mPaintTick);
return;
}
//
canvas.drawArc(mRectF, 90, ringProgress, false, mPaintRing);
//
mPaintCircle.setColor(checkBaseColor);
canvas.drawCircle(centerX, centerY, ringProgress == 360 ? radius : 0, mPaintCircle);
//
if (ringProgress == 360) {
mPaintCircle.setColor(checkTickColor);
canvas.drawCircle(centerX, centerY, circleRadius, mPaintCircle);
}
// ,
if (circleRadius == 0) {
canvas.drawLines(mPoints, mPaintTick);
canvas.drawArc(mRectF, 0, 360, false, mPaintRing);
}
//ObjectAnimator
if (!isAnimationRunning) {
isAnimationRunning = true;
mFinalAnimatorSet.start();
}
}
최종 효과는 똑같다. 코드 논리가 한눈에 최종 효과를 알 수 있다.gif
그래서 개인적으로 개발 과정에서 정해진 시간에 리뷰를 해서 자신의 코드를 보는 것이 자신에게나 향후 유지보수에 도움이 된다고 생각합니다.
That's all~ 읽어주셔서 감사합니다. 마지막으로 프로젝트의 github 주소를 틀어드릴게요.
Github 주소: TickView, 정교한 갈고리 작은 애니메이션github.com/ChengangFen…
전재 대상:https://juejin.im/post/59f5609851882534af2538c0
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
3D 게임 엔진 학습 2 (HelloWorld 소스 분석)프로젝트 구조 box에서.gpb 마운트 장면 장면 카메라의 화면 비율 설정 마운트된 장면에서 방향광 노드 발견 라이트 객체 확보 불러오는 장면에서box라는 모델 노드 가져오기 노드 모델 대상 획득 설정 모형의 재질은...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.