Android 를 사용 하여 롤러 컨트롤 바퀴 예 시 를 만 들 었 습 니 다.
효 과 는 다음 과 같 습 니 다.녹화 소프트웨어 가 약간 멈 출 수 있 습 니 다.구체 적 으로 소스 코드 를 다운로드 하여 실행 할 수 있 습 니 다.
사용자 정의 컨트롤 은 measure,draw,layot 세 가지 과정 이 아 닙 니 다.제스처 동작 을 지원 하려 면 touch 를 추가 하 십시오.
measure
측정 과정 은 비교적 간단 하 며 텍스트 크기 에 필요 한 사이즈 에 padding 을 더 합 니 다.
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int wantWith = getPaddingLeft() + getPaddingRight();
int wantHeight = getPaddingTop() + getPaddingBottom();
calculateTextSize();
wantWith += mTextRect.width();
// item
if (mVisibilityCount > 0) {
wantHeight += mTextRect.height() * mVisibilityCount;
} else {
wantHeight += mTextRect.height() * DEFALUT_VISIBILITY_COUNT;
}
setMeasuredDimension(
resolveSize(wantWith, widthMeasureSpec),
resolveSize(wantHeight, heightMeasureSpec)
);
mNeedCalculate = true;
}
draw그리 기 과정 은 canvas 의 위 치 를 통 해 서로 다른 위 젯 을 그립 니 다.텍스트 내용 과 선택 상자 등 을 포함 합 니 다.여기 서 주의해 야 할 부분 은 모든 텍스트 를 한꺼번에 그리 지 말고 보 이 는 텍스트 만 그리 면 됩 니 다.
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (hasDataSource()) {
//
// ,+2
final int drawCount = mContentRect.height() / mTextRect.height() + 2;
int invisibleCount = 0;
int dy = -mDistanceY;
//
// translate
for (int i = 0; (i < drawCount && mDataSources.size() > (invisibleCount + i));
i++) {
final int position = invisibleCount + i;
String text = mDataSources.get(position);
if (i > 0) {
canvas.translate(0, mTextRect.height());
}
final PointF pointF = calculateTextGravity(text);
mTextPaint.setTextSize(mTextSize);
if (position == selctPosition) {
mTextPaint.setColor(mSelectedTextColor);
} else {
mTextPaint.setColor(mNormalTextColor);
}
canvas.drawText(text, pointF.x, pointF.y, mTextPaint);
}
canvas.restoreToCount(saveCount);
}
//
int saveCount = canvas.save();
mDrawPaint.setColor(mSelectedLineColor);
canvas.translate(mContentRect.left, mContentRect.top);
canvas.drawLine(
mSelctedRect.left,
mSelctedRect.top,
mSelctedRect.right,
mSelctedRect.top,
mDrawPaint
);
canvas.drawLine(
mSelctedRect.left,
mSelctedRect.bottom,
mSelctedRect.right,
mSelctedRect.bottom,
mDrawPaint
);
canvas.restoreToCount(saveCount);
}
layout이 컨트롤 은 View 에 계승 되 기 때문에 onLayout 를 처리 할 필요 가 없습니다.
touch
터치 이벤트 배포 절차 에 익숙 하 다 면 많은 처 리 는 모델 코드 라 고 할 수 있 으 며,Nested ScrollView,ScrollView 를 참고 할 수 있 습 니 다.
onInterceptTouchEvent 에서 드래그 제스처 를 시작 할 지 여 부 를 판단 하여 변수(mIsBeingDragged)에 저장 합 니 다.
//
final int pointerIndex = ev.findPointerIndex(activePointerId);
if (pointerIndex == -1) {
Log.e(TAG, "Invalid pointerId=" + activePointerId
+ " in onInterceptTouchEvent");
break;
}
final int y = (int) ev.getY(pointerIndex);
final int yDiff = Math.abs(y - mLastMotionY);
if (yDiff > mTouchSlop && (getNestedScrollAxes() & SCROLL_AXIS_VERTICAL) == 0) {
//
mIsBeingDragged = true;
mLastMotionY = y;
initVelocityTrackerIfNotExists();
mVelocityTracker.addMovement(ev);
mNestedYOffset = 0;
if (mScrollStrictSpan == null) {
mScrollStrictSpan = StrictMode.enterCriticalSpan("ScrollView-scroll");
}
final ViewParent parent = getParent();
if (parent != null) {
//
parent.requestDisallowInterceptTouchEvent(true);
}
}
onTouchEvent 에서 ACTIONMOVR 은 드래그 처 리 를 하고 플러그 인 스크롤 을 지원 하면 플러그 인 스크롤 을 미리 배포 합 니 다.그림자 효과 가 지원 된다 면 EdgeEffect 를 사용 하 십시오.
// onInterceptTouchEvent
if (!mIsBeingDragged && Math.abs(deltaY) > mTouchSlop) {
final ViewParent parent = getParent();
if (parent != null) {
parent.requestDisallowInterceptTouchEvent(true);
}
mIsBeingDragged = true;
if (deltaY > 0) {
deltaY -= mTouchSlop;
} else {
deltaY += mTouchSlop;
}
}
if (mIsBeingDragged) {
//
// Scroll to follow the motion event
mLastMotionY = y - mScrollOffset[1];
final int oldY = mScrollY;
final int range = getScrollRange();
final int overscrollMode = getOverScrollMode();
boolean canOverscroll = overscrollMode == OVER_SCROLL_ALWAYS ||
(overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && range > 0);
// Calling overScrollBy will call onOverScrolled, which
// calls onScrollChanged if applicable.
// ,overScrollBy
if (overScrollBy(0, deltaY, 0, mScrollY, 0, range, 0, mOverscrollDistance, true)
&& !hasNestedScrollingParent()) {
// Break our velocity if we hit a scroll barrier.
mVelocityTracker.clear();
}
final int scrolledDeltaY = mScrollY - oldY;
final int unconsumedY = deltaY - scrolledDeltaY;
//
if (dispatchNestedScroll(0, scrolledDeltaY, 0, unconsumedY, mScrollOffset)) {
mLastMotionY -= mScrollOffset[1];
vtev.offsetLocation(0, mScrollOffset[1]);
mNestedYOffset += mScrollOffset[1];
} else if (canOverscroll) {
final int pulledToY = oldY + deltaY;
//
if (pulledToY < 0) {
mEdgeGlowTop.onPull((float) deltaY / getHeight(),
ev.getX(activePointerIndex) / getWidth());
if (!mEdgeGlowBottom.isFinished()) {
mEdgeGlowBottom.onRelease();
}
} else if (pulledToY > range) {
mEdgeGlowBottom.onPull((float) deltaY / getHeight(),
1.f - ev.getX(activePointerIndex) / getWidth());
if (!mEdgeGlowTop.isFinished()) {
mEdgeGlowTop.onRelease();
}
}
if (mEdgeGlowTop != null
&& (!mEdgeGlowTop.isFinished() || !mEdgeGlowBottom.isFinished())) {
postInvalidateOnAnimation();
}
}
}
스크롤 제스처 를 지원 하 는 컨트롤 은 일반적으로 플 링 제스처 를 지원 하 며 관성 스크롤 로 이해 할 수 있 습 니 다.이것 도 모드 코드 입 니 다.onTouch Event 에서 ACTIONUP 에서 드래그 속 도 를 분석 합 니 다.
case MotionEvent.ACTION_UP:
if (mIsBeingDragged) {
final VelocityTracker velocityTracker = mVelocityTracker;
velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
//
int initialVelocity = (int) velocityTracker.getYVelocity(mActivePointerId);
if ((Math.abs(initialVelocity) > mMinimumVelocity)) {
// fling
flingWithNestedDispatch(-initialVelocity);
} else if (mScroller.springBack(mScrollX, mScrollY, 0, 0, 0,
getScrollRange())) {
postInvalidateOnAnimation();
}
mActivePointerId = INVALID_POINTER;
endDrag();
}
break;
구체 적 인 코드 는 ScrollView 에서 읽 을 수 있 습 니 다.내 가 구현 한 사용자 정의 컨트롤 로 돌아 가면 터치 이벤트 에 대한 처리 코드 는 시스템 컨트롤 의 처리 와 다 르 지 않 습 니 다.드래그 거 리 를 가 져 온 후에 이 값 에 따라 서로 다른 위치의 보 이 는 영역 을 그립 니 다.여기 두 가지 처리 가 더 많아 졌 습 니 다.
첫 번 째 드래그 가 끝 난 후 리 셋 처 리 를 진행 합 니 다.드래그 가 끝 난 후 선택 상자 가 두 아 이 템 사이 에 머 물 렀 다 면 두 아 이 템 과 의 거리 에 따라 더 가 까 운 아 이 템 을 선택 하 십시오.
private void correctionDistanceY() {
if (mDistanceY % mTextRect.height() != 0) {
int position = mDistanceY / mTextRect.height();
int remainder = mDistanceY % mTextRect.height();
if (remainder >= mTextRect.height() / 2f) {
position++;
}
int newDistanceY = position * mTextRect.height();
animChangeDistanceY(newDistanceY);
}
}
두 번 째 는 사용 에서 발 견 된 문제 입 니 다.굴 러 갈 수 있 는 거리 가 너무 짧 고 끌 어 당 기 는 제스처 속도 가 빠 르 면 fling 처리 가 끝나 지 않 고 시각 적 으로 변 하지 않 으 며 스크롤 이 끝 난 후에 선택 한 리 셋 이 므 로 신체 검사 에 좋 지 않 지만 Scroller 는 set Duration 을 제공 하지 않 았 습 니 다.따라서 Scroller 에서 duration 을 계산 하 는 방법 을 복사 하고 나머지 스크롤 에 따라 적당 한 duration 을 계산 하여 Scroller 의 fling 처 리 를 수 동 으로 중단 합 니 다.
if ((SystemClock.elapsedRealtime() - mStartFlingTime) >= mFlingDuration || currY == mScroller.getFinalY()) {
//duration or current == final
if (DEBUG) {
Logger.d("abortAnimation");
}
mScroller.abortAnimation();
}
구체 적 인 코드 는 읽 을 수 있 습 니 다소스 코드이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Bitrise에서 배포 어플리케이션 설정 테스트하기이 글은 Bitrise 광고 달력의 23일째 글입니다. 자체 또는 당사 등에서 Bitrise 구축 서비스를 사용합니다. 그나저나 며칠 전 Bitrise User Group Meetup #3에서 아래 슬라이드를 발표했...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.