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 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Service Configuration Error MessagesOccasionally, during bootup of Cisco hardware through Cisco IOS software, error messages similar to these are displayed:...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.