Android 에서 Scroller 의 스크롤 원 리 를 깊이 이해 하 다.
View 의 부 드 러 운 스크롤 효 과 를 실현 하 는 것 은 무엇 입 니까?간단 한 예 를 들 어 하나의 View 는 우리 가 지정 한 시간 내 에 한 위치 에서 다른 위치 로 굴 러 갑 니 다.우 리 는 Scroller 류 를 이용 하여 등 속 스크롤 을 실현 할 수 있 습 니 다.먼저 가속 한 후에 속 도 를 줄 일 수 있 고 먼저 속 도 를 줄 인 후에 속 도 를 올 릴 수 있 습 니 다.순간 적 인 이동 효과 가 아 닙 니 다.그래서 Scroller 는 우리 가 많은 미끄럼 효 과 를 실현 하 는 데 도움 을 줄 수 있다.
먼저 Scroller 의 용법 을 살 펴 보 겠 습 니 다.기본적으로'3 부작'으로 요약 할 수 있 습 니 다.
1.Scroller 대상 을 만 듭 니 다.보통 View 의 구조 기 에서 만 듭 니 다.
public ScrollViewGroup(Context context) {
this(context, null);
}
public ScrollViewGroup(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ScrollViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mScroller = new Scroller(context);
}
2.View 의 coptute Scroll()방법 을 다시 쓰 면 다음 코드 는 기본적으로 변 하지 않 습 니 다.
@Override
public void computeScroll() {
super.computeScroll();
if (mScroller.computeScrollOffset()) {
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
postInvalidate();
}
}
3.startScroll()방법 을 호출 합 니 다.startX 와 startY 는 스크롤 을 시작 하 는 좌표 점 이 고 dx 와 dy 는 대응 하 는 오프셋 입 니 다.
mScroller.startScroll (int startX, int startY, int dx, int dy);
invalidate();
위의 세 단 계 는 바로 Scroller 의 기본 적 인 용법 이다.그럼 다음 임 무 는 Scroller 의 스크롤 원 리 를 분석 하 는 것 입 니 다.
그 전에 우 리 는 또 한 가지 해 야 할 일이 있다.그것 은 바로
scrollTo()
과 scrollBy()
의 원 리 를 밝 히 는 것 이다.scrollTo()
과 scrollBy()
의 차 이 는 중복 서술 하지 않 겠 습 니 다.모 르 는 것 은 스스로 구 글 이나 바 이 두 를 할 수 있 습 니 다.아래 에
scrollTo()
의 소스 코드 를 붙 입 니 다.
public void scrollTo(int x, int y) {
if (mScrollX != x || mScrollY != y) {
int oldX = mScrollX;
int oldY = mScrollY;
mScrollX = x;
mScrollY = y;
invalidateParentCaches();
onScrollChanged(mScrollX, mScrollY, oldX, oldY);
if (!awakenScrollBars()) {
postInvalidateOnAnimation();
}
}
}
mScrollX
과 mScrollY
을 설정 한 후 onScrollChanged(mScrollX, mScrollY, oldX, oldY);
을 호출 하면 View 가 다시 그 려 집 니 다.이렇게 해서 미끄럼 효과 에 이 르 렀 다.다음은
scrollBy()
을 살 펴 보 겠 습 니 다. :
public void scrollBy(int x, int y) {
scrollTo(mScrollX + x, mScrollY + y);
}
이렇게 짧 은 코드 는 모두 가 알 고 있 을 것 이 라 고 믿 습 니 다.원래 scrollBy()
내 부 는 scrollTo()
을 호출 했 습 니 다.그러나 scrollTo()
/scrollBy()
의 스크롤 은 모두 순간 에 완 성 된 것 입 니 다.어떻게 해야만 부 드 러 운 스크롤 을 실현 할 수 있 습 니까?여러분 들 은 이런 생각 을 가지 고 있 는 지 모 르 겠 습 니 다.만약 에 우리 가 구 를 오프셋 을 몇 개의 작은 오프셋 으로 나 누 면 당연히 이 분량 이 커 야 합 니 다.그리고
scrollTo()
/scrollBy()
으로 매번 작은 오프셋 을 굴 립 니 다.일정한 시간 안에 부 드 럽 게 구 르 는 것 이 되 지 않 습 니까?맞 아,Scroller 는 바로 이 원 리 를 빌려 부 드 러 운 스크롤 을 실현 하 는 거 야.다음은 소스 코드 를 살 펴 보 겠 습 니 다!
'3 부작'중 1 부 에 따 르 면 먼저 Scroller 의 구조 기 를 살 펴 보 자.
public Scroller(Context context, Interpolator interpolator, boolean flywheel) {
mFinished = true;
if (interpolator == null) {
mInterpolator = new ViscousFluidInterpolator();
} else {
mInterpolator = interpolator;
}
mPpi = context.getResources().getDisplayMetrics().density * 160.0f;
mDeceleration = computeDeceleration(ViewConfiguration.getScrollFriction());
mFlywheel = flywheel;
mPhysicalCoeff = computeDeceleration(0.84f); // look and feel tuning
}
구조 기 에서 주로 플러그 인 을 지정 하 는데 플러그 인 이 지정 되 지 않 으 면 기본 ViscousFluidInterpolator
을 사용 합 니 다.Scroller 의
startScroll()
을 다시 보 겠 습 니 다.
public void startScroll(int startX, int startY, int dx, int dy, int duration) {
mMode = SCROLL_MODE;
mFinished = false;
mDuration = duration;
mStartTime = AnimationUtils.currentAnimationTimeMillis();
mStartX = startX;
mStartY = startY;
mFinalX = startX + dx;
mFinalY = startY + dy;
mDeltaX = dx;
mDeltaY = dy;
mDurationReciprocal = 1.0f / (float) mDuration;
}
startScroll()
에서 스크롤 을 시작 하지 않 고 변수의 초기 값 을 설정 한 것 을 발 견 했 습 니 다.그러면 도대체 무엇이 View 를 스크롤 하기 시 작 했 습 니까?우 리 는 반드시 목 표를 startScroll()
의 다음 문장 invalidate();
에 집중 해 야 한다.우 리 는 이렇게 이해 할 수 있다.먼저 startScroll()
에 초기 값 을 설정 한 다음 에 invalidate();
을 사용 하여 View 를 다시 그립 니 다.여기 서 또 하나의 중요 한 점 이 있 습 니 다.draw()
에서 computeScroll()
이라는 방법 을 사용 할 것 입 니 다!소스 코드 가 너무 길 어서 여기에 붙 이지 않 겠 습 니 다.보고 싶 은 동 화 는 뷰 클래스 에서
boolean draw(Canvas canvas, ViewGroup parent, long drawingTime)
을 찾 아 보면 알 수 있 습 니 다.ViewGroup.drawChild()
방법 을 통 해 서브 뷰 의 draw()
방법 을 호출 할 것 이다.그리고 View 류 에 있 는 computeScroll()
은 빈 방법 이 므 로 우리 가 실현 해 야 한다.
/**
* Called by a parent to request that a child update its values for mScrollX
* and mScrollY if necessary. This will typically be done if the child is
* animating a scroll using a {@link android.widget.Scroller Scroller}
* object.
*/
public void computeScroll() {
}
위의'3 부작'의 2 부 에서 우 리 는 이미 computeScroll()
을 실현 했다. 。먼저 computeScrollOffset()
을 판 단 했 습 니 다.관련 소스 코드 를 살 펴 보 겠 습 니 다.
/**
* Call this when you want to know the new location. If it returns true,
* the animation is not yet finished.
*/
public boolean computeScrollOffset() {
if (mFinished) {
return false;
}
int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime);
if (timePassed < mDuration) {
switch (mMode) {
case SCROLL_MODE:
final float x = mInterpolator.getInterpolation(timePassed * mDurationReciprocal);
mCurrX = mStartX + Math.round(x * mDeltaX);
mCurrY = mStartY + Math.round(x * mDeltaY);
break;
case FLING_MODE:
final float t = (float) timePassed / mDuration;
final int index = (int) (NB_SAMPLES * t);
float distanceCoef = 1.f;
float velocityCoef = 0.f;
if (index < NB_SAMPLES) {
final float t_inf = (float) index / NB_SAMPLES;
final float t_sup = (float) (index + 1) / NB_SAMPLES;
final float d_inf = SPLINE_POSITION[index];
final float d_sup = SPLINE_POSITION[index + 1];
velocityCoef = (d_sup - d_inf) / (t_sup - t_inf);
distanceCoef = d_inf + (t - t_inf) * velocityCoef;
}
mCurrVelocity = velocityCoef * mDistance / mDuration * 1000.0f;
mCurrX = mStartX + Math.round(distanceCoef * (mFinalX - mStartX));
// Pin to mMinX <= mCurrX <= mMaxX
mCurrX = Math.min(mCurrX, mMaxX);
mCurrX = Math.max(mCurrX, mMinX);
mCurrY = mStartY + Math.round(distanceCoef * (mFinalY - mStartY));
// Pin to mMinY <= mCurrY <= mMaxY
mCurrY = Math.min(mCurrY, mMaxY);
mCurrY = Math.max(mCurrY, mMinY);
if (mCurrX == mFinalX && mCurrY == mFinalY) {
mFinished = true;
}
break;
}
}
else {
mCurrX = mFinalX;
mCurrY = mFinalY;
mFinished = true;
}
return true;
}
이 방법의 반환 값 은 중요 합 니 다.true 로 돌아 가면 Scroller 의 미끄럼 이 끝나 지 않 았 음 을 설명 합 니 다.false 로 돌아 가면 Scroller 의 미끄럼 이 끝 났 음 을 설명 합 니 다.다시 내부 코드 를 보십시오.먼저 미 끄 러 진 시간 을 계 산 했 습 니 다.미 끄 러 진 시간 이 전체 미 끄 러 진 시간 보다 적 으 면 미 끄 러 진 시간 이 끝나 지 않 았 음 을 설명 합 니 다.그렇지 않 으 면 미끄럼 이 끝났다 는 뜻 이 고 표시 mFinished = true;
을 설정 합 니 다.미끄럼 이 끝나 지 않 았 을 때 두 개의 mode 로 나 뉘 었 지만 이 두 mode 는 차이 가 많 지 않 은 일 을 했다.대체적으로 아까 의 시간 에 따라 timePassed 와 플러그 인 에 따라 이 시간 에 굴 러 가 는 거 리 를 계산 한 것 이다.mCurrX
과 mCurrY
이다.바로 위의'3 부작'중 2 부의 mScroller.getCurrX()
,mScroller.getCurrY()
의 값 이다.그 다음 에 2 부 곡 에서
scrollTo()
방법 으로 지정 점(즉 위의 mCurrX
,mCurrY
)으로 스크롤 합 니 다.이후 postInvalidate();
을 호출 하여 View 를 다시 그리고 computeScroll()
을 다시 호출 하여 View 가 지 정 된 위치 로 굴 러 갈 때 까지 순환 시 켰 습 니 다.이로써 Scroller 스크롤 이 끝 났 습 니 다.사실 Scroller 의 원 리 는 비교적 통속 적 이 고 이해 하기 쉽다.오늘 의 Scroller 해석 을 그림 으로 끝 내 겠 습 니 다.
총결산
자,안 드 로 이 드 에서 Scroller 의 스크롤 원리 에 대한 내용 은 여기까지 입 니 다.질문 이 있 으 면 아래 에 메 시 지 를 남 겨 주세요.이 글 의 내용 이 여러분 의 안 드 로 이 드 개발 에 도움 이 되 기 를 바 랍 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Kotlin의 기초 - 2부지난 글에서는 Kotlin이 무엇인지, Kotlin의 특징, Kotlin에서 변수 및 데이터 유형을 선언하는 방법과 같은 Kotlin의 기본 개념에 대해 배웠습니다. 유형 변환은 데이터 변수의 한 유형을 다른 데이터...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.