[FastDev4Android 프레임 워 크 개발] 신기 ViewDragHelper 완전 해석 의 상세 한 해석 으로 QQQ5. X 사 이 드 스 케 이 트 쿨 링 효과 실현 (34)

전재 출처 표시:http://blog.csdn.net/developer_jiangqq / article / details / 50043159 본 고 는 다음 과 같다. [강 청 의 블 로그]
(1). 머리말:   
          [좋 은 소식] 개인 사이트 가 이미 온라인 으로 운영 되 고 있 습 니 다. 뒤의 블 로그 와 기술 건어물 등 멋 진 글 이 동시에 업 데 이 트 될 것 입 니 다. 소장 에 관심 을 가 져 주 십시오.http://www.lcode.org
        요 며칠 동안 녹화 실전 프로젝트 를 업데이트 하고 있 으 며 전체 프레임 워 크 는 QQ5. X 사 이 드 스 케 이 트 효 과 를 모방 한 것 이다.그러면 Google 의 일반적인 방법 은 ViewGroup 을 사용자 정의 하거나 오픈 소스 프로젝트 인 MenuDrawer 나 Google 이 제공 하 는 컨트롤 DrawerLayout 등 을 사용 하 는 것 입 니 다.이러한 컨트롤 의 많은 효 과 는 기본적으로 onInterceptTouchEvent 와 onTouchEvent 를 실현 하 는 두 가지 방법 으로 이 루어 집 니 다. 또한 실현 하고 자 하 는 효과 에 따라 사용자 정의 처 리 를 합 니 다. 예 를 들 어 다 중 터치 처리, 가속도 측정 과 제어 등 입 니 다.일반적으로 이렇게 하 는 것 은 일반 개발 자 에 게 도 매우 강 한 프로그램 과 논리 개발 능력 이 필요 하 다. 다행히 안 드 로 이 드 개발 프레임 워 크 는 우리 에 게 구성 요소 인 View DragHelper 를 제공 해 주 었 다.지난 번 에 우 리 는 ViewGragHelper 의 기본 사용 에 대해 설명 (클릭 진입) 을 했 습 니 다. 오늘 은 QQQ5. X 사 이 드 스 케 이 트 효 과 를 실현 하 는 인 스 턴 스 (오픈 소스 프로젝트 주소 클릭 진입) 를 분석 합 니 다.
         구체 적 인 코드 는 아래 항목 에 올 라 왔 습 니 다. 스타 와 포크 에 오신 것 을 환영 합 니 다.
         https://github.com/jiangqqlmj/ViewDragHelperTest
         FastDev4Android 프레임 워 크 항목 주소:https://github.com/jiangqqlmj/FastDev4Android
(2). ViewDragHelper 의 기본 사용   
        앞에서 우 리 는 View DragHelper 의 기본 적 인 사용 방법 을 배 웠 고 안에 있 는 몇 가지 방법의 용도 도 알 게 되 었 습 니 다. 다음은 기본 적 인 사용 절 차 를 복습 하 겠 습 니 다.View DragHelper 를 사용 하여 하위 View 드래그 이동 을 실현 하 는 절 차 는 다음 과 같 습 니 다.
ViewDragHelper 인 스 턴 스 만 들 기 (Callback 에 전송) 이벤트 차단 처리 방법 onInterceptTouch 와 onTouch Event 재 작성 Callback 을 실현 하고 그 중의 관련 방법 try Capture View 와 수평 또는 수직 방향 으로 이동 하 는 거리 방법 을 실현 합 니 다.
       좀 더 구체 적 으로 분석 하면 앞의 블 로 그 를 보 거나 오늘 은 구체 적 인 사례 를 통 해 설명 하 겠 습 니 다.
(3). QQQ5. X 측면 미끄럼 효과 에 대한 분석:  
    본 격 버 전 QQ 의 사 이 드 스 케 이 트 효 과 는 다음 과 같 습 니 다.
【FastDev4Android框架开发】神器ViewDragHelper完全解析之详解实现QQ5.X侧滑酷炫效果(三十四)_第1张图片
            위 를 살 펴 보면 우 리 는 두 개의 View 로 이해 할 수 있 습 니 다. 하 나 는 바닥 이 왼쪽 기능 View 에 해당 하고 다른 하 나 는 상층 의 주요 기능 내용 View 입 니 다. 우리 가 위 에서 상층 View 를 끌 거나 좌우 로 미 끄 러 질 때 상층 과 하층부의 View 는 상응 하 게 미 끄 러 지고 View 의 큰 변 화 를 하 는 동시에 관련 애니메이션 도 추가 합 니 다.물론 상부 의 View 를 클릭 하면 사 이 드 메뉴 를 열거 나 닫 을 수 있 습 니 다.
(4). 측면 미끄럼 효과 사용자 정의 구성 요소 구현
          1. 우선 FrameLayout 에 통합 하여 사용자 정의 뷰 를 만 듭 니 다.  DragLayout。내부 에서 정 의 된 변 수 는 다음 과 같 습 니 다. (주로 설정 류, 제스처, ViewDragHelper 인 스 턴 스, 화면 너비, 끌 어 당 기 는 하위 보기 View 등 을 포함 합 니 다)
  //        
   private boolean isShowShadow = true;
    //     
    private GestureDetectorCompat gestureDetector;
    //         
    private ViewDragHelper dragHelper;
    //     
    private DragListener dragListener;
    //       
    private int range;
    //  
    private int width;
    //  
    private int height;
    //main     ViewGroup       
    private int mainLeft;
    private Context context;
    private ImageView iv_shadow;
    //    
    private RelativeLayout vg_left;
    //  (     )
    private CustomRelativeLayout vg_main;

    그 다음 에 내부 에서 리 셋 인터페이스 가 끌 어 당 기 는 과정 에서 일부 페이지 가 열 리 고 닫 히 며 미 끄 러 지 는 이벤트 리 셋 을 처리 하 는 것 을 정의 했다. 
/**
     *         
     */
    public interface DragListener {
        //    
        public void onOpen();
        //    
        public void onClose();
        //       
        public void onDrag(float percent);
    }

  2. ViewDragHelper 인 스 턴 스 를 만 들 기 시 작 했 습 니 다. 사용자 정의 View DragLayout 를 초기 화 할 때 만 들 고 ViewDragHelper 의 정적 방법 을 사용 합 니 다.
public DragLayout(Context context,AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        gestureDetector = new GestureDetectorCompat(context, new YScrollDetector());
        dragHelper =ViewDragHelper.create(this, dragHelperCallback);
    }

      그 중에서 create () 방법 을 만 들 때 dragHelperCallBack 리 셋 클래스 가 들 어 왔 습 니 다. 네 번 째 시 에 말씀 드 리 겠 습 니 다.
   3. 이어서 ViewGroup 의 이벤트 방법 을 다시 쓰 고 터치 이 벤트 를 차단 하여 ViewDragHelper 내부 에 처리 하여 이동 서브 View 보 기 를 끌 어 당 기 는 목적 을 달성 해 야 합 니 다.
/**
     *       
     * @param ev
     * @return
     */
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return dragHelper.shouldInterceptTouchEvent(ev) &&gestureDetector.onTouchEvent(ev);
    }
    /**
     *         ViewDragHelper    
     * @param e
     * @return
     */
    @Override
    public boolean onTouchEvent(MotionEvent e){
        try {
            dragHelper.processTouchEvent(e);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return false;
    }

    여기 서 우 리 는 onInterceptTouchEvent 에서 이 벤트 를 부모 컨트롤 에서 하위 View 로 이동 시 킨 다음 에 onTouchEvent 방법 에서 ViewDragHelper 가 소비 처 리 를 하도록 차단 합 니 다.
     4. View DragHelper. Callback 을 만 드 는 인 스 턴 스 를 사용자 정의 하기 시작 합 니 다. dragHelper Callback 은 추상 적 인 방법 try Capture View 를 실현 하고 다음 과 같은 몇 가지 방법 을 다시 써 서 사 이 드 스 케 이 트 기능 을 실현 합 니 다. 다음은 하나씩 살 펴 보 겠 습 니 다.  
      /**
         *       View
         * @param child Child the user isattempting to capture
         * @param pointerId ID of the pointerattempting the capture
         * @return
         */
        @Override
        public boolean tryCaptureView(View child, int pointerId) {
            return true;
        }

       뷰 그룹 (이 예: DragLayout) 의 모든 하위 뷰 를 차단 하고 트 루 로 돌아 가 모든 하위 뷰 를 드래그 하여 이동 할 수 있 음 을 표시 합 니 다.
  /**
         *       
         * @param child Child view beingdragged
         * @param left Attempted motion alongthe X axis
         * @param dx Proposed change inposition for left
         * @return
         */
        @Override
        public int clampViewPositionHorizontal(View child, int left, int dx) {
            if (mainLeft + dx < 0) {
                return 0;
            } else if (mainLeft + dx >range) {
                return range;
            } else {
                return left;
            }
        }

       이 방법 을 실현 하 는 것 은 수평 방향 이 미 끄 러 지 는 것 을 나타 내 는 동시에 방법 에서 경계 값 을 판단 할 것 이다. 예 를 들 어 위의 main view 가 왼쪽 으로 경 계 를 이동 한 것 을 제외 하고 바로 0 으로 돌아 가 왼쪽 가장 왼쪽 에 x = 0 만 있 음 을 나타 낸다.그리고 오른쪽으로 이동 하면 오른쪽으로 가장 먼 거리 range 를 판단 하고 range 의 초기 화 뒤에 설명 합 니 다.이 두 가지 상황 을 제외 하고 바로 left 로 돌아 가면 된다.
   /**
         *              
         * @param child Child view tocheck      
         * @return
         */
        @Override
        public int getViewHorizontalDragRange(View child) {
            return width;
        }

      이 방법 은 Callback 내부 에서 기본적으로 0 으로 되 돌아 가기 때문에 이 방법 이 필요 합 니 다. 즉, view 의 click 이벤트 가 true 라면 전체 하위 View 가 끌 어 당 겨 이동 할 수 없 는 상황 이 발생 할 수 있 습 니 다.그러면 여 기 는 left view 너비 로 바로 돌아 가 수평 방향 으로 미 끄 러 지 는 가장 먼 거 리 를 나타 낸다.
/**
         *      View,            ,                        
         * @param releasedChild
         * @param xvel
         * @param yvel
         */
        @Override
        public void onViewReleased(View releasedChild, float xvel, float yvel) {
            super.onViewReleased(releasedChild,xvel, yvel);
            if (xvel > 0) {
                open();
            } else if (xvel < 0) {
                close();
            } else if (releasedChild == vg_main&& mainLeft > range * 0.3) {
                open();
            } else if (releasedChild == vg_left&& mainLeft > range * 0.7) {
                open();
            } else {
                close();
            }
        }

      이 방법 은 드래그 자 View 가 손가락 을 움 직 여 놓 을 때 호출 됩 니 다. 이것 은 왼쪽으로 이동 하고 오른쪽으로 이동 하 는 의 도 를 판단 하여 man view (상부 보기) 를 열거 나 닫 습 니 다.다음은 실현 의 마지막 방법: onView Position Changed
/**
         *  View              
         * @param changedView View whoseposition changed
         * @param left New X coordinate of theleft edge of the view
         * @param top New Y coordinate of thetop edge of the view
         * @param dx Change in X position fromthe last call
         * @param dy Change in Y position fromthe last call
         */
        @Override
        public void onViewPositionChanged(View changedView, int left, int top,
                int dx, int dy) {
            if (changedView == vg_main) {
                mainLeft = left;
            } else {
                mainLeft = mainLeft + left;
            }
            if (mainLeft < 0) {
                mainLeft = 0;
            } else if (mainLeft > range) {
                mainLeft = range;
            }
 
            if (isShowShadow) {
                iv_shadow.layout(mainLeft, 0,mainLeft + width, height);
            }
            if (changedView == vg_left) {
                vg_left.layout(0, 0, width,height);
                vg_main.layout(mainLeft, 0,mainLeft + width, height);
            }
            dispatchDragEvent(mainLeft);
        }
    };

       이 방법 은 이동 서브 뷰 를 끌 어 당 기 는 과정 에서 리 셋 을 하고 이동 좌표 위치 에 따라 left view 와 main view 를 다시 정의 하 는 것 입 니 다.dispathDragEvent () 방법 을 동시에 호출 하여 드래그 이벤트 관련 처 리 를 하고 배포 하 는 동시에 상태 에 따라 인 터 페 이 스 를 되 돌려 줍 니 다.
 /**
     *         
     * @param mainLeft
     */
    private void dispatchDragEvent(intmainLeft) {
        if (dragListener == null) {
            return;
        }
        float percent = mainLeft / (float)range;
        //          ,            View
        animateView(percent);
        //          
        dragListener.onDrag(percent);
        Status lastStatus = status;
        if (lastStatus != getStatus()&& status == Status.Close) {
            dragListener.onClose();
        } else if (lastStatus != getStatus()&& status == Status.Open) {
            dragListener.onOpen();
        }
    }

    이 방법 에는 float percent = mainLeft / (float) range 코드 가 있 습 니 다.1 퍼센트 까지 계산 해서 나중에 쓸 게 요.
   5. 하위 View 레이아웃 의 초기 화 및 너비 와 수평 미끄럼 거리의 크기 설정 방법:
/**
     *         
     *          
     */
    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        if (isShowShadow) {
            iv_shadow = new ImageView(context);
           iv_shadow.setImageResource(R.mipmap.shadow);
            LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
            addView(iv_shadow, 1, lp);
        }
        //    
        vg_left = (RelativeLayout)getChildAt(0);
        //  ( )  
        vg_main = (CustomRelativeLayout)getChildAt(isShowShadow ? 2 : 1);
        vg_main.setDragLayout(this);
        vg_left.setClickable(true);
        vg_main.setClickable(true);
    }

   그리고 컨트롤 크기 가 바 뀌 는 방법:
 @Override
    protected void onSizeChanged(int w, int h,int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        width = vg_left.getMeasuredWidth();
        height = vg_left.getMeasuredHeight();
        //                    60%
        range = (int) (width * 0.6f);
    }

    이 방법 에서 우 리 는 실시 간 으로 너비 와 높이, 그리고 수평 거 리 를 끌 어 당 길 수 있다.
    6. 위의 모든 핵심 코드 는 View DragHelper 를 사용 하여 하위 컨트롤 View 드래그 이동 을 실현 하 는 방법 입 니 다. 그러나 우리 의 측면 미끄럼 효과 에 따라 애니메이션 과 미끄럼 과정 에서 View 의 크기 조정 효 과 를 실현 해 야 하기 때문에 우 리 는 애니메이션 오픈 소스 라 이브 러 리 를 도 입 했 습 니 다. 이 라 이브 러 리 는 Github 에서 다운로드 하여 사용 할 수 있 습 니 다.물론 뒤에 나 는 이 라 이브 러 리 의 사용 을 단독으로 꺼 내 서 문장 한 편 을 써 서 설명 할 것 이다.기대 해 주세요 ~
   
      그리고 앞 에 계 산 된 백분율 에 따라 View 보기 크기 를 조정 합 니 다.
 /**
     *           ,            View
     * @param percent
     */
    private void animateView(float percent) {
        float f1 = 1 - percent * 0.3f;
        //vg_main            
        ViewHelper.setScaleX(vg_main, f1);
        //vg_main    ,       
        ViewHelper.setScaleY(vg_main, f1);
        //    X   
        ViewHelper.setTranslationX(vg_left,-vg_left.getWidth() / 2.3f + vg_left.getWidth() / 2.3f * percent);
        //vg_left            
        ViewHelper.setScaleX(vg_left, 0.5f +0.5f * percent);
        //vg_left            
        ViewHelper.setScaleY(vg_left, 0.5f +0.5f * percent);
        //vg_left            
        ViewHelper.setAlpha(vg_left, percent);
        if (isShowShadow) {
            //            
            ViewHelper.setScaleX(iv_shadow, f1* 1.4f * (1 - percent * 0.12f));
            ViewHelper.setScaleY(iv_shadow, f1* 1.85f * (1 - percent * 0.12f));
        }
       getBackground().setColorFilter(evaluate(percent, Color.BLACK,Color.TRANSPARENT), Mode.SRC_OVER);
    }
 
    private Integer evaluate(float fraction,Object startValue, Integer endValue) {
        int startInt = (Integer) startValue;
        int startA = (startInt >> 24)& 0xff;
        int startR = (startInt >> 16)& 0xff;
        int startG = (startInt >> 8)& 0xff;
        int startB = startInt & 0xff;
        int endInt = (Integer) endValue;
        int endA = (endInt >> 24) &0xff;
        int endR = (endInt >> 16) &0xff;
        int endG = (endInt >> 8) &0xff;
        int endB = endInt & 0xff;
        return (int) ((startA + (int) (fraction* (endA - startA))) << 24)
                | (int) ((startR + (int)(fraction * (endR - startR))) << 16)
                | (int) ((startG + (int)(fraction * (endG - startG))) << 8)
                | (int) ((startB + (int)(fraction * (endB - startB))));
    }

     7. 물론 위 에 있 는 것 외 에 한 가지 효과 가 부족 하 다. 우리 가 미 끄 러 지 는 과정 에서 손가락 이 풀 리 면 상식 적 으로 view 는 이동 하지 않 을 것 이다. 그러면 여기 서 우 리 는 가속도 가 필요 하 다. 우리 가 풀 린 후에 도 일정한 속 도 를 유지 할 수 있다. 어떻게 실현 해 야 할 까?정 답 은 컴퓨터 스크롤 () 을 실현 하 는 방법 이다.    
 /**
     *     ,          ,           
     */
    @Override
    public void computeScroll() {
        if (dragHelper.continueSettling(true)){
           ViewCompat.postInvalidateOnAnimation(this);
        }
    }

     OK 위 에 있 는 DragLayout 에 대한 핵심 코드 는 많 지 않 습 니 다. 다음은 DragLayout 류 를 사용 하여 사 이 드 스 케 이 트 효 과 를 실현 합 니 다!
(5). 측면 미끄럼 효과 구성 요소 사용     
        1. 먼저 사용 한 레이아웃 파일 은 다음 과 같 습 니 다.
<com.chinaztt.widget.DragLayoutxmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/dl"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:background="@mipmap/ic_main_left_bg"
    >
    <RelativeLayout
       android:layout_width="match_parent"
       android:layout_height="match_parent"
        android:paddingBottom="30dp"
        android:paddingLeft="30dp"
        android:paddingTop="50dp"
      >
        <LinearLayout
            android:id="@+id/ll1"
           android:layout_width="match_parent"
           android:layout_height="wrap_content"
           android:orientation="horizontal" >
            <ImageView
               android:id="@+id/iv_bottom"
               android:layout_width="70dp"
               android:layout_height="70dp"
               android:src="@mipmap/ic_launcher" />
            <LinearLayout
               android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:gravity="center_vertical"
               android:layout_gravity="center_vertical"
               android:orientation="vertical">
                <TextView
                   android:layout_width="wrap_content"
                   android:layout_height="wrap_content"
                   android:layout_gravity="center_vertical"
                   android:layout_marginLeft="20dp"
                   android:text="  :jiangqqlmj"
                   android:textColor="#ffffff"
                   android:textSize="18sp" />
                <TextView
                   android:layout_width="wrap_content"
                   android:layout_height="wrap_content"
                   android:layout_gravity="center_vertical"
                   android:layout_marginLeft="20dp"
                   android:text="QQ:781931404"
                   android:textColor="#ffffff"
                   android:textSize="16sp" />
            </LinearLayout>
 
        </LinearLayout>
 
        <TextView
            android:id="@+id/tv_mail"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:layout_alignParentBottom="true"
           android:text="[email protected]"
           android:textColor="#ffffff"
            android:textSize="15sp"/>
 
        <!--    -->
        <ListView
            android:id="@+id/lv"
           android:layout_width="match_parent"
           android:layout_height="wrap_content"
           android:layout_above="@id/tv_mail"
           android:layout_below="@id/ll1"
           android:layout_marginBottom="30dp"
           android:layout_marginTop="20dp"
           android:cacheColorHint="#00000000"
           android:listSelector="@null"
            android:divider="@null"
            android:scrollbars="none"
           android:textColor="#ffffff" />
    </RelativeLayout>
 
   <com.chinaztt.widget.CustomRelativeLayout
       android:layout_width="match_parent"
       android:layout_height="match_parent"
        android:background="#FFFFFF"
        >
        <LinearLayout
           android:layout_width="fill_parent"
           android:layout_height="fill_parent"
           android:orientation="vertical"
            >
        <RelativeLayout
           android:id="@+id/rl_title"
           android:layout_width="match_parent"
           android:layout_height="49dp"
           android:background="#e7abff"
            android:gravity="bottom"
             >
            <RelativeLayout
               android:layout_width="fill_parent"
               android:layout_height="49dp"
                >
            <ImageView
               android:id="@+id/iv_icon"
               android:layout_width="40dp"
               android:layout_height="40dp"
               android:layout_centerVertical="true"
               android:layout_marginLeft="10dp"
               android:scaleType="fitXY"
               android:src="@mipmap/ic_launcher"
                />
            <TextView
               android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:text="ViewDragHelper  "
               android:layout_centerInParent="true"
               android:textColor="#ffffff"
               android:textSize="20sp"
                 />
            </RelativeLayout>
        </RelativeLayout>
        <!--        Fragment-->
        <FrameLayout
           android:layout_width="fill_parent"
           android:layout_height="fill_parent"
            >
            <TextView
               android:id="@+id/iv_noimg"
               android:layout_gravity="center"
               android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:text="      ..."
                />
        </FrameLayout>
        </LinearLayout>
   </com.chinaztt.widget.CustomRelativeLayout>
</com.chinaztt.widget.DragLayout>

         이 레이아웃 파일 의 부모 층 View 는 바로 DragLayout 입 니 다. 그 다음 에 내부 에 두 개의 RelativeLayout 레이아웃 이 있 는데 각각 왼쪽 View (왼쪽 기능) 와 주 Main View 를 충당 합 니 다.마지막 으로 Activity 에서 DragLayout 컨트롤 을 가 져 오고 이벤트 모니터 (DragListener) 의 구체 적 인 코드 를 다음 과 같이 추가 합 니 다.
public class MainActivity extends BaseActivity {
privateDragLayout dl;
privateListView lv;
privateTextView tv_noimg;
privateImageView iv_icon, iv_bottom;
 
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setStatusBar();
initDragLayout();
initView();
 
}
private void initDragLayout() {
dl= (DragLayout) findViewById(R.id.dl);
dl.setDragListener(new DragLayout.DragListener() {
//       
@Override
public void onOpen() {
}
//       
@Override
public void onClose() {
}
 
//       
@Override
public void onDrag(float percent) {
ViewHelper.setAlpha(iv_icon,1 - percent);
}
});
}
 
private void initView() {
iv_icon= (ImageView) findViewById(R.id.iv_icon);
iv_bottom= (ImageView) findViewById(R.id.iv_bottom);
tv_noimg= (TextView) findViewById(R.id.iv_noimg);
 
lv= (ListView) findViewById(R.id.lv);
lv.setAdapter(new ArrayAdapter<String>(MainActivity.this,
R.layout.item_text,new String[] { "item 01", "item 01",
"item01", "item 01", "item 01", "item 01",
"item01", "item 01", "item 01", "item 01",
"item01", "item 01", "item 01", "item 01",
"item01", "item 01", "item 01",
"item01", "item 01", "item 01", "item 01"}));
lv.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> arg0, View arg1,
intposition, long arg3) {
Toast.makeText(MainActivity.this,"ClickItem "+position,Toast.LENGTH_SHORT).show();
}
});
iv_icon.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
dl.open();
}
});
}
@Override
protectedvoid onResume() {
super.onResume();
}
}

최종 실행 효 과 는 다음 과 같 습 니 다.
여기 밑 에 View DragHelper 류 가 필요 하기 때문에 여러분 이 사용 할 때 V4 패 키 지 를 가 져 와 야 합 니 다. 그런데 저 는 View DragHelper 류 의 소스 코드 를 프로젝트 에 직접 복사 합 니 다.
【FastDev4Android框架开发】神器ViewDragHelper完全解析之详解实现QQ5.X侧滑酷炫效果(三十四)_第2张图片
(6). dragLayout 소스 코드 설명   
       위 에 서 는 주로 DragLayout 의 구체 적 인 실현 을 분 석 했 습 니 다. 하지만 저도 DragLayout 에 주석 이 있 는 모든 소스 코드 를 붙 여서 DragLayout 의 구체 적 인 실현 코드 를 잘 알 수 있 도록 하 겠 습 니 다.
/**
 *   ViewRragHelper        
 */
public class DragLayout extends FrameLayout {
    private boolean isShowShadow = true;
    //     
    private GestureDetectorCompat gestureDetector;
    //         
    private ViewDragHelper dragHelper;
    //     
    private DragListener dragListener;
    //       
    private int range;
    //  
    private int width;
    //  
    private int height;
    //main     ViewGroup       
    private int mainLeft;
    private Context context;
    private ImageView iv_shadow;
    //    
    private RelativeLayout vg_left;
    //  (     )
    private CustomRelativeLayout vg_main;
    //          
    private Status status = Status.Close;
 
    public DragLayout(Context context) {
        this(context, null);
    }
 
    public DragLayout(Context context,AttributeSet attrs) {
        this(context, attrs, 0);
        this.context = context;
    }
 
    public DragLayout(Context context,AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        gestureDetector = new GestureDetectorCompat(context, new YScrollDetector());
        dragHelper =ViewDragHelper.create(this, dragHelperCallback);
    }
 
    class YScrollDetector extends SimpleOnGestureListener {
        @Override
        public boolean onScroll(MotionEvent e1,MotionEvent e2, float dx, float dy) {
            return Math.abs(dy) <=Math.abs(dx);
        }
    }
 
    /**
     *    View     ,  Callback       
     */
    private ViewDragHelper.CallbackdragHelperCallback = new ViewDragHelper.Callback() {
        /**
         *       
         * @param child Child view beingdragged
         * @param left Attempted motion alongthe X axis
         * @param dx Proposed change inposition for left
         * @return
         */
        @Override
        public int clampViewPositionHorizontal(View child, int left, int dx) {
            if (mainLeft + dx < 0) {
                return 0;
            } else if (mainLeft + dx >range) {
                return range;
            } else {
                return left;
            }
        }
 
        /**
         *       View
         * @param child Child the user isattempting to capture
         * @param pointerId ID of the pointerattempting the capture
         * @return
         */
        @Override
        public boolean tryCaptureView(View child, int pointerId) {
            return true;
        }
        /**
         *              
         * @param child Child view tocheck      
         * @return
         */
        @Override
        public int getViewHorizontalDragRange(View child) {
            return width;
        }
 
        /**
         *      View,            ,                        
         * @param releasedChild
         * @param xvel
         * @param yvel
         */
        @Override
        public void onViewReleased(View releasedChild, float xvel, float yvel) {
            super.onViewReleased(releasedChild,xvel, yvel);
            if (xvel > 0) {
                open();
            } else if (xvel < 0) {
                close();
            } else if (releasedChild == vg_main&& mainLeft > range * 0.3) {
                open();
            } else if (releasedChild == vg_left&& mainLeft > range * 0.7) {
                open();
            } else {
                close();
            }
        }
 
        /**
         *  View              
         * @param changedView View whoseposition changed
         * @param left New X coordinate of theleft edge of the view
         * @param top New Y coordinate of thetop edge of the view
         * @param dx Change in X position fromthe last call
         * @param dy Change in Y position fromthe last call
         */
        @Override
        public void onViewPositionChanged(View changedView, int left, int top,
                int dx, int dy) {
            if (changedView == vg_main) {
                mainLeft = left;
            } else {
                mainLeft = mainLeft + left;
            }
            if (mainLeft < 0) {
                mainLeft = 0;
            } else if (mainLeft > range) {
                mainLeft = range;
            }
 
            if (isShowShadow) {
                iv_shadow.layout(mainLeft, 0,mainLeft + width, height);
            }
            if (changedView == vg_left) {
                vg_left.layout(0, 0, width,height);
                vg_main.layout(mainLeft, 0,mainLeft + width, height);
            }
 
            dispatchDragEvent(mainLeft);
        }
    };
 
    /**
     *         
     */
    public interface DragListener {
        //    
        public void onOpen();
        //    
        public void onClose();
        //       
        public void onDrag(float percent);
    }
    public void setDragListener(DragListener dragListener) {
        this.dragListener = dragListener;
    }
 
    /**
     *         
     *          
     */
    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        if (isShowShadow) {
            iv_shadow = new ImageView(context);
           iv_shadow.setImageResource(R.mipmap.shadow);
            LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
            addView(iv_shadow, 1, lp);
        }
        //    
        vg_left = (RelativeLayout)getChildAt(0);
        //  ( )  
        vg_main = (CustomRelativeLayout)getChildAt(isShowShadow ? 2 : 1);
        vg_main.setDragLayout(this);
        vg_left.setClickable(true);
        vg_main.setClickable(true);
    }
 
    public ViewGroup getVg_main() {
        return vg_main;
    }
 
    public ViewGroup getVg_left() {
        return vg_left;
    }
 
    @Override
    protected void onSizeChanged(int w, int h,int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        width = vg_left.getMeasuredWidth();
        height = vg_left.getMeasuredHeight();
        //                    60%
        range = (int) (width * 0.6f);
    }
 
    /**
     *     left main         
     * @param changed
     * @param left
     * @param top
     * @param right
     * @param bottom
     */
    @Override
    protected void onLayout(boolean changed,int left, int top, int right, int bottom) {
        vg_left.layout(0, 0, width, height);
        vg_main.layout(mainLeft, 0, mainLeft +width, height);
    }
 
    /**
     *       
     * @param ev
     * @return
     */
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        returndragHelper.shouldInterceptTouchEvent(ev) &&gestureDetector.onTouchEvent(ev);
    }
 
    /**
     *         ViewDragHelper    
     * @param e
     * @return
     */
    @Override
    public boolean onTouchEvent(MotionEvent e){
        try {
            dragHelper.processTouchEvent(e);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return false;
    }
 
    /**
     *         
     * @param mainLeft
     */
    private void dispatchDragEvent(int mainLeft) {
        if (dragListener == null) {
            return;
        }
        float percent = mainLeft / (float)range;
        //          ,            View
        animateView(percent);
        //          
        dragListener.onDrag(percent);
        Status lastStatus = status;
        if (lastStatus != getStatus()&& status == Status.Close) {
            dragListener.onClose();
        } else if (lastStatus != getStatus()&& status == Status.Open) {
            dragListener.onOpen();
        }
    }
 
    /**
     *           ,            View
     * @param percent
     */
    private void animateView(float percent) {
        float f1 = 1 - percent * 0.3f;
        //vg_main            
        ViewHelper.setScaleX(vg_main, f1);
        //vg_main    ,       
        ViewHelper.setScaleY(vg_main, f1);
        //    X   
        ViewHelper.setTranslationX(vg_left,-vg_left.getWidth() / 2.3f + vg_left.getWidth() / 2.3f * percent);
        //vg_left            
        ViewHelper.setScaleX(vg_left, 0.5f +0.5f * percent);
        //vg_left            
        ViewHelper.setScaleY(vg_left, 0.5f +0.5f * percent);
        //vg_left            
        ViewHelper.setAlpha(vg_left, percent);
        if (isShowShadow) {
            //            
            ViewHelper.setScaleX(iv_shadow, f1* 1.4f * (1 - percent * 0.12f));
            ViewHelper.setScaleY(iv_shadow, f1* 1.85f * (1 - percent * 0.12f));
        }
       getBackground().setColorFilter(evaluate(percent, Color.BLACK,Color.TRANSPARENT), Mode.SRC_OVER);
    }
 
    private Integer evaluate(float fraction,Object startValue, Integer endValue) {
        int startInt = (Integer) startValue;
        int startA = (startInt >> 24)& 0xff;
        int startR = (startInt >> 16)& 0xff;
        int startG = (startInt >> 8)& 0xff;
        int startB = startInt & 0xff;
        int endInt = (Integer) endValue;
        int endA = (endInt >> 24) &0xff;
        int endR = (endInt >> 16) &0xff;
        int endG = (endInt >> 8) &0xff;
        int endB = endInt & 0xff;
        return (int) ((startA + (int) (fraction* (endA - startA))) << 24)
                | (int) ((startR + (int)(fraction * (endR - startR))) << 16)
                | (int) ((startG + (int)(fraction * (endG - startG))) << 8)
                | (int) ((startB + (int)(fraction * (endB - startB))));
    }
 
    /**
     *     ,          ,           
     */
    @Override
    public void computeScroll() {
        if (dragHelper.continueSettling(true)){
           ViewCompat.postInvalidateOnAnimation(this);
        }
    }
 
    /**
     *     (  ,  ,  )
     */
    public enum Status {
        Drag, Open, Close
    }
 
    /**
     *       
     * @return
     */
    public Status getStatus() {
        if (mainLeft == 0) {
            status = Status.Close;
        } else if (mainLeft == range) {
            status = Status.Open;
        } else {
            status = Status.Drag;
        }
        return status;
    }
 
    public void open() {
        open(true);
    }
 
    public void open(boolean animate) {
        if (animate) {
            //    
            if(dragHelper.smoothSlideViewTo(vg_main, range, 0)) {
               ViewCompat.postInvalidateOnAnimation(this);
            }
        } else {
            vg_main.layout(range, 0, range * 2,height);
            dispatchDragEvent(range);
        }
    }
 
    public void close() {
        close(true);
    }
 
    public void close(boolean animate) {
        if (animate) {
            //    
            if(dragHelper.smoothSlideViewTo(vg_main, 0, 0)) {
               ViewCompat.postInvalidateOnAnimation(this);
            }
        } else {
            vg_main.layout(0, 0, width,height);
            dispatchDragEvent(0);
        }
    }
}

(7). 최종 총화
           오늘 우 리 는 View DragHelper 를 통 해 QQ5. x 사 이 드 스 케 이 트 효과 와 유사 한 구성 요소 의 효 과 를 설명 합 니 다. 또한 이 항목 에서 도 몰입 식 상태의 효 과 를 사 용 했 습 니 다.이 효과 의 구체 적 인 실현 에 대해 서 는 제 다른 글 을 보 실 수 있 습 니 다.
           이번 구체 적 인 실례 주석 을 달 았 던 모든 코드 가 Github 프로젝트 에 업로드 되 었 습 니 다.또한 Github 사이트 에 가서 클론 이나 다운로드 탐색 을 하 는 것 을 환영 합 니 다.
https://github.com/jiangqqlmj/ViewDragHelperTest
스타 와 포크 의 전체 오픈 소스 빠 른 개발 프레임 워 크 프로젝트 를 환영 합 니 다 ~
동시에 감사 드 립 니 다.https://github.com/BlueMor/DragLayout
오리지널 을 존중 하고 전재 하 시 려 면: From Sky 주 청 (http://blog.csdn.net/developer_jiangqq) 권리 침 해 는 반드시 추궁 해 야 한다!
나의 구독 번 호 를 주목 하고 매일 모 바 일 개발 기술 (Android / IOS), 프로젝트 관리 와 블 로그 글 을 공유 합 니 다!
【FastDev4Android框架开发】神器ViewDragHelper完全解析之详解实现QQ5.X侧滑酷炫效果(三十四)_第3张图片
나의 웨 이 보 를 주목 하면 더 많은 멋 진 내용 을 얻 을 수 있다.
【FastDev4Android框架开发】神器ViewDragHelper完全解析之详解实现QQ5.X侧滑酷炫效果(三十四)_第4张图片

좋은 웹페이지 즐겨찾기