안 드 로 이 드 의 Nested Scrolling 메커니즘 을 자세히 설명 합 니 다.

개술
Android 는 슈퍼 port.v4 패키지 에서 두 가지 신기 한 종 류 를 제공 합 니 다.
  • NestedScrollingParent
  • NestedScrollingChild
  • 만약 네가 이 두 가 지 를 들 어 본 적 이 없다 면,괜찮아,내 가 천천히 소개 하 는 것 을 들 어 봐,너 는 이 두 가지 가 무엇 에 쓸 수 있 는 지 알 게 될 것 이다.다 들 보 셨 거나 Coordinator Layout 를 사용 해 보 셨 을 거 라 고 믿 습 니 다.이 종 류 를 통 해 저희 가 눈 부신 효 과 를 완성 하 는 데 편리 하 게 도움 을 줄 수 있 습 니 다.예 를 들 어 다음 과 같은 것 입 니 다.

    이러한 효 과 는 Nested Scrolling 체 제 를 사용 하여 완성 하기에 매우 적합 하 다.또한 Coordinator Layout 뒤에 도 사실은 이 체 제 를 이용 하고 있다.그래서 나 는 네가 이 체 제 를 무엇 에 사용 할 수 있 는 지 이미 알 고 있다 고 믿는다.
    하지만,나 는 네가 또 문제 가 있다 고 믿는다.
  • 이 메커니즘 은 전통 적 인 사용자 정의 View Group 사건 배포 처리 에 비해 어떤 좋 은 점 이 있 습 니까?
  • 음..간단하게 분석 해 보 자.
    위의 그림 에 따 르 면:
    만약 에 우리 가 전통 적 인 사건 에 따라 나 누 어 이해한다 면 먼저 우리 가 미 끄 러 진 것 은 아래 의 내용 구역 이 고 이동 은 외부의 View Group 이 이동 하고 있 기 때문에 전통 적 인 방식 으로 외부의 Parent 가 내부 의 Child 사건 을 차단 한 것 이 틀림없다.그러나 상기 효과 도 는 Parent 가 어느 정도 미 끄 러 졌 을 때 Child 가 다시 미 끄 러 지기 시 작 했 고 중간 전체 과정 이 중단 되 지 않 았 다.정상 적 인 사건 배포(수 동 으로 배포 사건 을 호출 하지 않 고 수 동 으로 사건 을 보 내지 않 음)측면 에서 하 는 것 은 불가능 하 다.왜냐하면 Parent 가 차단 한 후에 사건 을 Child 에 게 맡 길 수 없 기 때문이다.사건 을 배포 하 는 것 은 차단 에 있어 한 번 의 매매 에 해당 하기 때문에 차단 하면 현재 제스처 의 다음 사건 은 모두 Parent(차단 자)에 게 맡 길 것 이다.
    그러나 Nested Scrolling 메커니즘 은 이 일 을 처리 하기 가 매우 쉽 기 때문에 이 메커니즘 에 대해 깊이 있 게 학습 하면 우리 가 플러그 인 슬라이딩 을 작성 할 때 특수 한 효과 에 도움 이 된다.둘 째 는 제 가 Coordinator Layout 를 분석 하기 위 한 쿠션 입 니 다.
    ps:구체 적 으로 어떤 v4 버 전에 추 가 된 것 인지 깊이 연구 하지 않 겠 습 니 다.만약 에 v4 에 상기 두 가지 종류 가 없다 면 v4 버 전 을 업그레이드 하 십시오.Nested Scrolling 메커니즘 이라는 단 어 는 개인 적 인 호칭 으로 공식 적 으로 이렇게 부 르 는 지 잘 모 르 겠 으 니 깊이 연구 하지 마 세 요.
    2.기대 효과
    물론 이 두 가 지 를 설명 하려 면 반드시 사례 의 뒷받침 이 있어 야 한다.그렇지 않 으 면 너무 공허 하 다.다행히 저 에 게 아주 좋 은 사례 가 있 습 니 다.
    아주 오래 전에 나 는 이런 글 을 쓴 적 이 있다.
    Android 는 사용자 정의 컨트롤 을 통 해 360 소프트웨어 상세 페이지 효 과 를 실현 합 니 다.
    완전히 전통 적 인 방식 으로 작 성 된 것 이 고 연속 적 으로 미 끄 러 지기 위해 매우 특수 한 처 리 를 했 습 니 다.예 를 들 어 DOWN 이벤트 류 를 수 동 으로 나 누 어 주 는 것 입 니 다.관심 이 있 으 면 읽 어 보 세 요.
    효과 도 는 다음 과 같 습 니 다:

    오늘 우 리 는 이 효 과 를 이용 하여 Nested Srill 체제 의 사례 로 서 마지막 으로 우 리 는 소스 코드 를 간단하게 분석 할 것 입 니 다.사실은 소스 코드 는 비교적 간단 합 니 다~
    ps:Coordinator Layout 는 이 효 과 를 편리 하 게 실현 할 수 있 고 후속 적 인 글 도 Coordinator Layout 에 대해 분석 할 것 입 니 다.
    실현
    상기 효과 도 는 3 부분 으로 나 뉜 다.상단 레이아웃;가운데 ViewPager 표시 기;그리고 밑 에 있 는 RecyclerView;
    RecyclerView 는 사실 Nested Srilling Child 의 실현 류 이기 때문에 본 사례 의 주요 역할 은 Nested Scrolling Parent 를 실현 하 는 것 이다.
    (1)레이아웃 파일
    먼저 레이아웃 파일 을 미리 봅 니 다.머 릿 속 에 대체적인 레이아웃 이 있 습 니 다.
    
    <com.zhy.view.StickyNavLayout xmlns:tools="http://schemas.android.com/tools"
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:orientation="vertical" >
     <RelativeLayout
     android:id="@id/id_stickynavlayout_topview"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:background="#4400ff00" >
     <TextView
      android:layout_width="match_parent"
      android:layout_height="256dp"
      android:gravity="center"
      android:text="    "
      android:textSize="30sp"
      android:textStyle="bold" />
     </RelativeLayout>
    
     <com.zhy.view.SimpleViewPagerIndicator
     android:id="@id/id_stickynavlayout_indicator"
     android:layout_width="match_parent"
     android:layout_height="50dp"
     android:background="#ffffffff" >
     </com.zhy.view.SimpleViewPagerIndicator>
    
     <android.support.v4.view.ViewPager
     android:id="@id/id_stickynavlayout_viewpager"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
      >
     </android.support.v4.view.ViewPager>
    
    </com.zhy.view.StickyNavLayout>
    Sticky NavLayout 는 LinearLayout 에서 직접 계승 하고 orientation='vertical'을 설정 하기 때문에 직관 적 인 것 은 컨트롤 이 순서대로 세로 로 배열 되 고 측정 에 대해 특별한 처 리 를 해 야 한다.본 고의 중점 이 아니 기 때문에 소스 코드 나 위 에서 언급 한 글 을 스스로 볼 수 있다.
    (2)NestedScrollingParent 실현
    Nested Scrolling Parent 는 하나의 인터페이스 로 다음 과 같은 방법 이 필요 합 니 다.
    
    public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes);
    
    public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes);
    
    public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
      int dxUnconsumed, int dyUnconsumed);
    
    public void onNestedPreScroll(View target, int dx, int dy, int[] consumed);
    
    public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed);
    
    public boolean onNestedPreFling(View target, float velocityX, float velocityY);
    
    public int getNestedScrollAxes();
    구체 적 인 실현 을 쓰기 전에 먼저 필요 한 상술 한 방법 에 대해 간단 한 소 개 를 한다.
  • onStartNested Scroll 이 방법 은 반드시 자신의 요구 에 따라 true 로 돌아 가 야 합 니 다.이 방법 은 현재 컨트롤 이 내부 View(직접 하위 View 가 아 닌)가 미 끄 러 질 때의 인 자 를 받 아들 일 수 있 는 지 여 부 를 결정 합 니 다.수직 미끄럼 만 언급 된다 고 가정 하면 nested Scrollaxes 라 는 매개 변수 에 따라 수직 으로 판단 할 수 있 습 니 다.
  • onNested PreScroll 이 방법 은 내부 View 가 이동 하 는 dx,dy 로 전 송 됩 니 다.만약 에 일정한 dx,dy 를 소모 해 야 한다 면 마지막 매개 변수 consumed 를 통 해 지정 합 니 다.예 를 들 어 제 가 절반 의 dy 를 소모 하려 면 consumed[1]=D/2
  • 를 쓸 수 있 습 니 다.
  • onNested Fling 은 내부 View 에 대한 fling 사건 을 포착 할 수 있 으 며,return true 는 내부 View 를 차단 하 는 사건 을 표시 합 니 다.
  • 주 된 관심 사 는 이 세 가지 방법~
    여기 서 내부 뷰 는 반드시 직접 서브 뷰 가 아니 라 내부 뷰 만 있 으 면 된다 는 뜻 이다.
    다음은 우리 의 구체 적 인 실현 을 살 펴 보 자.
    
    public class StickyNavLayout extends LinearLayout implements NestedScrollingParent
    {
     @Override
     public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes)
     {
     return (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;
     }
     @Override
     public void onNestedPreScroll(View target, int dx, int dy, int[] consumed)
     {
     boolean hiddenTop = dy > 0 && getScrollY() < mTopViewHeight;
     boolean showTop = dy < 0 && getScrollY() > 0 && !ViewCompat.canScrollVertically(target, -1);
    
     if (hiddenTop || showTop)
     {
      scrollBy(0, dy);
      consumed[1] = dy;
     }
     }
     @Override
     public boolean onNestedPreFling(View target, float velocityX, float velocityY)
     {
     if (getScrollY() >= mTopViewHeight) return false;
     fling((int) velocityY);
     return true;
     }
    }
  • onStartNested Scroll 에서 우 리 는 true 로 세로 로 돌아 가 려 면 보통 내부 View 가 들 어 와 야 한다 고 판단 했다.확실 하지 않 거나 내부 View 가 작 성 된 규범 에 맞지 않 을 까 봐 걱정 되면 return true 를 직접 사용 할 수 있다.
  • onNested PreScroll 에서 우 리 는 위 에서 미 끄 러 지고 상단 컨트롤 이 완전히 숨 어 있 지 않 으 면 dy,즉 consumed[1]=dy 를 소모 할 것 이 라 고 판단 합 니 다.만약 에 하락 하고 내부 View 가 계속 내 려 갈 수 없다 면 dy,즉 consumed[1]=dy 를 소모 하고 소모 된다 는 뜻 은 스스로 scrollBy 를 실행 하 는 것 이다.사실은 우리 의 StickNavLayout 가 미 끄 러 지 는 것 이다.
  • 이 밖 에 플 링 도 처 리 했 습 니 다.onNested PreFling 방법 을 통 해 자신의 수요 에 따라 정할 수 있 습 니 다.상단 컨트롤 이 표 시 될 때 플 링 은 상단 컨트롤 을 숨 기거 나 표시 할 수 있 습 니 다.
  • 상기 코드 는 아래 의 효 과 를 실현 할 수 있 습 니 다:

    fling 방법 에 대해 우 리 는 OverScroll 의 fling 방법 을 이용 하여 경계 검 측 에 대해 scrollTo 방법 을 다시 썼 습 니 다.
    
    public void fling(int velocityY)
    {
     mScroller.fling(0, getScrollY(), 0, velocityY, 0, 0, 0, mTopViewHeight);
     invalidate();
    }
    
    @Override
    public void scrollTo(int x, int y)
    {
     if (y < 0)
     {
      y = 0;
     }
     if (y > mTopViewHeight)
     {
      y = mTopViewHeight;
     }
     if (y != getScrollY())
     {
      super.scrollTo(x, y);
     }
    }
    상세 한 설명 은 위 에서 언급 한 문장 을 볼 수 있 는데,여 기 는 중복 되 지 않 는 다.
    여기까지 입 니 다.Nested Scrolling 메커니즘 을 볼 수 있 습 니 다.아주 간단 합 니 다.
    바로 Nested Scrolling Parent 내부 의 View 입 니 다.미 끄 러 질 때 먼저 dx,dy 를 Nested Scrolling Parent 에 전달 합 니 다.Nested Scrolling Parent 는 이 를 소모 할 지 여 부 를 결정 할 수 있 습 니 다.보통 수요 에 따라 소모 부분 이나 전 부 를 소모 할 수 있 습 니 다.(그러나 여 기 는 실제 적 인 제약 이 없 기 때문에 얼마 가 소모 되 는 지 마음대로 쓸 수 있 고 내부 View 에 어느 정도 영향 을 줄 수 있 습 니 다).
    백화 와 원래 의 사건 분배 기 제작 을 비교 해 보면 이렇다(정상 적 인 절차 에 대한 다음 제스처).
  • 사건 의 배 포 는 이 렇 습 니 다.자 뷰 는 먼저 사건 처리 권 을 얻 었 습 니 다.처리 과정 에서 아버지 View 는 이 를 차단 할 수 있 지만 차단 한 후에 자 뷰(이번 제스처 에서)에 게 돌려 줄 수 없습니다.
  • Nested Scrolling 메커니즘 은 다음 과 같다.내부 View 가 굴 러 갈 때 먼저 dx,dy 를 Nested Scrolling Parent 에 건 네 주 고 Nested Scrolling Parent 는 이 를 일부 소모 할 수 있 으 며 나머지 부분 은 내부 View 에 돌려 준다.
  • 구체 적 인 소스 코드 는 본 박문 보다 복잡 할 것 이다.비 내부 View 구역 을 만 지 는 상호작용 과 관련 되 기 때문에 본 박문 의 중점 이 아니 라 소스 코드 를 참고 할 수 있다.
    원리
    원 리 는 내부 View 가 언제 Nested Scrolling Parent 로 되 돌아 가 는 지 보 는 것 입 니 다.내부 View 의 onTouch Event 로 직접 위 치 를 정 하 는 것 입 니 다.
    
    @Override
    public boolean onTouchEvent(MotionEvent e) {
     switch (action) {
      case MotionEvent.ACTION_DOWN: {
       int nestedScrollAxis = ViewCompat.SCROLL_AXIS_NONE;
       if (canScrollHorizontally) {
        nestedScrollAxis |= ViewCompat.SCROLL_AXIS_HORIZONTAL;
       }
       if (canScrollVertically) {
        nestedScrollAxis |= ViewCompat.SCROLL_AXIS_VERTICAL;
       }
       startNestedScroll(nestedScrollAxis);
      } break;
      case MotionEvent.ACTION_MOVE: {
       if (dispatchNestedPreScroll(dx, dy, mScrollConsumed, mScrollOffset)) {
        dx -= mScrollConsumed[0];
        dy -= mScrollConsumed[1];
        vtev.offsetLocation(mScrollOffset[0], mScrollOffset[1]);
       }
      } break;
      case MotionEvent.ACTION_UP: {
       fling((int) xvel, (int) yvel);
       resetTouch();
      } break;
    
      case MotionEvent.ACTION_CANCEL: {
       cancelTouch();
      } break;
     }
     return true;
    }
    볼 수 있 습 니 다:
    ACTION_DOWN 에서 startNested Scroll 을 호출 했 습 니 다.ACTION_MOVE 에서 dispatchNested PreScroll 을 호출 했 습 니 다.ACTION_UP 는 resetTouch 를 호출 하기 위해 fling 을 촉발 할 수 있 습 니 다.
    startNested 스크롤 내부 실제:
    
    #NestedScrollingChildHelper
    public boolean startNestedScroll(int axes) {
     if (hasNestedScrollingParent()) {
      // Already in progress
      return true;
     }
     if (isNestedScrollingEnabled()) {
      ViewParent p = mView.getParent();
      View child = mView;
      while (p != null) {
       if (ViewParentCompat.onStartNestedScroll(p, child, mView, axes)) {
        mNestedScrollingParent = p;
        ViewParentCompat.onNestedScrollAccepted(p, child, mView, axes);
        return true;
       }
       if (p instanceof View) {
        child = (View) p;
       }
       p = p.getParent();
      }
     }
     return false;
    }
    Nested Scrolling Parent 를 찾 아 onStart Nested Scroll 과 onNested Scroll Accepted 를 되 돌려 줍 니 다.
    dispatchNested PreScroll 에 서 는 onNested PreScroll 방법 을 되 돌려 주 고 내부 scrollByInternal 에 서 는 onNested Scroll 방법 을 되 돌려 줍 니 다.
    fling 에 서 는 onNested PreFling 과 onNested Fling 방법 을 되 돌려 줍 니 다.
    resetTouch 에 서 는 onStopNested Scroll 을 되 돌려 줍 니 다.
    코드 는 사실 붙 일 것 이 별로 없습니다.여러분 이 직접 onTouchEvent 를 찾 으 면 한눈 에 볼 수 있 습 니 다.호출 방법 명 은 모두 dispatchNestedXXX 방법 이 고 실제 내 부 는 Nested Scrolling ChildHelper 를 통 해 이 루어 집 니 다.
    따라서 Nested Scrolling Parent 와 합작 하 는 내부 View 를 실현 하려 면 Nested Scrolling Child 를 실현 한 다음 에 내부 에서 Nested Scrolling Child Helper 라 는 보조 류 를 빌려 핵심 적 인 방법 을 모두 봉 인 했 습 니 다.적당 한 실제 적 으로 매개 변수 호출 방법 을 전달 하면 됩 니 다.
    ok,이런 메커니즘 은 반드시 시험 해 봐 야 한다.많은 미끄럼 과 관련 된 효과 가 이 를 통 해 실 현 될 수 있다.
    원본 주소:
    github 주소:https://github.com/hongyangAndroid/Android-StickyNavLayout
    로 컬 다운로드:http://xiazai.jb51.net/201705/yuanma/Android-StickyNavLayout(jb51.net).rar
    총결산
    이상 은 이 글 의 전체 내용 입 니 다.본 논문 의 내용 이 여러분 의 학습 이나 업무 에 어느 정도 도움 이 되 기 를 바 랍 니 다.궁금 한 점 이 있 으 시 면 댓 글 을 남 겨 주 셔 서 저희 에 대한 지지 에 감 사 드 립 니 다.

    좋은 웹페이지 즐겨찾기