Android 를 사용 하여 롤러 컨트롤 바퀴 예 시 를 만 들 었 습 니 다.

10239 단어 Android롤러컨트롤
안 드 로 이 드 가 iOS 의 롤러 선택 효 과 를 실현 하 는 컨트롤 에 대해 github 에서 한 무더기 의 바퀴 를 찾 아 보 세 요.이 바퀴 를 만 드 는 이 유 는 사용자 정의 컨트롤 을 더욱 잘 배우 기 위해 서 입 니 다.이 컨트롤 은 몇 달 전에 쓴 것 입 니 다.한 동안 의 보완 을 거 쳐 현재 시작 되 었 습 니 다.그리고 이 간단 한 소개 글 도 쓰 겠 습 니 다.
효 과 는 다음 과 같 습 니 다.녹화 소프트웨어 가 약간 멈 출 수 있 습 니 다.구체 적 으로 소스 코드 를 다운로드 하여 실행 할 수 있 습 니 다.

사용자 정의 컨트롤 은 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();
     }
구체 적 인 코드 는 읽 을 수 있 습 니 다소스 코드
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

좋은 웹페이지 즐겨찾기