QQ는 편리함과 실용성을 겸비한 채팅 도구입니다. QQ가 6.0으로 업데이트된 이후 측면 슬라이딩의 메인 패널이 원래의 긁힌 부분에서 좌우로 줄어들었습니다. 외관이 크게 개선되었으므로 내부의 다양한 논리를 이해하고 관련 정보를 결합하려고 노력했습니다.
여기서 주요 클래스 중 하나가 ViewDragHelper라는 것을 알고 있으므로 먼저 이 ViewDragHelper 클래스를 이해해야 합니다. 속담처럼 7인치로 뱀을 때릴 것입니다. 공식 문서에는 어떤 이상한 기능이 있습니까?
첫 번째 상속:
java.lang.Object
android.support.v4.widget.ViewDragHelper
직접 상위 클래스는 Object입니다.
클래스 개요
ViewDragHelper는 사용자 정의 ViewGroup을 작성하기 위한 유틸리티 클래스로, 사용자가 상위 ViewGroup 내에서 뷰를 드래그하고 위치를 변경할 수 있도록 하는 여러 가지 유용한 작업 및 상태 추적을 제공합니다.
사용자 정의 ViewGroup을 작성하기 위한 도구 클래스입니다. 이 영역은 사용자가 상위 ViewGroup에서 궤적과 위치를 드래그하고 그릴 수 있도록 하는 많은 유용한 방법과 상태를 제공합니다.
중첩 클래스(nested class)
ViewDragHelper.Callback
콜백은 ViewDragHelper를 사용하여 상위 뷰로 돌아가는 통신 채널로 사용됩니다.
콜백은 ViewDragHelper와 해당 상위 뷰 간의 통신을 위한 인터페이스로 사용됩니다.
공개 정적 메서드:
create() 메소드를 통해 ViewDragHelper가 생성되었음을 알 수 있습니다. 이에 대해서는 나중에 자세히 소개하겠습니다.
사용해야 하는 몇 가지 메소드를 살펴보겠습니다.
public boolean tryCaptureView(View child, int pointerId) {} public int getViewHorizontalDragRange(View child) {} public int clampViewPositionHorizontal(View child, int left, int dx) {} public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {} public void onViewReleased(View releasedChild, float xvel, float yvel) {}
위 메소드에는 코드에 자세한 설명이 있습니다. 여기서는 필요한 메소드만 살펴보겠습니다. to be rewrite
좋아요, 말을 너무 많이 했으니 드래그를 실현할 수 있는 간단한 것부터 시작하겠습니다. (저는 두 개의 뷰를 드래그할 수 있다고 믿습니다. 몇 단계만 거치면 됩니다):
첫 번째 단계는 드래그 앤 드롭 기능을 구현하는 것입니다(구현하는 간단한 3단계)
//1、通过静态方法初始化操作 mDragHelper = ViewDragHelper.create(this, mCallback); /** * 2、传递触摸事件 * * @param ev * @return */ @Override public boolean onInterceptTouchEvent(MotionEvent ev) { //让自己的控件自行判断是否去拦截 return mDragHelper.shouldInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { try { //自己去处理触摸事件 mDragHelper.processTouchEvent(event); } catch (Exception e) { e.printStackTrace(); } //返回true,这样才能持续接收,要不然我们不会传递而是被拦截了 return true; } ViewDragHelper.Callback mCallback = new ViewDragHelper.Callback() { /** * 根据返回结果决定当前child是否可以拖拽 * 尝试捕获的时候调用,如果返回的是主面板,那么负面版是不能被调用的 * @param child 当前被拖拽的view * @param pointerId 区分多点触摸的id * @return 返回true 是都可以拖拽 * 返回child == mLeftContent 左侧可以移动 * 返回child == mMainContent 右侧可以移动 */ @Override public boolean tryCaptureView(View child, int pointerId) { //这里要返回true,要不然不能拖拽 return true; } /** * 根据建议值修正将要移动的位置 此时并没有发生真正的移动(左右) * * @param child 当前拖拽的view * @param left 新的位置的建议值 oldLeft + dx * @param dx 变化量 和变化之前位置的差值 * @return */ @Override public int clampViewPositionHorizontal(View child, int left, int dx) { //返回的拖拽的范围,不对拖拽进行真正的限制,仅仅决定了动画执行的速度 return left; } };
자, 첫 번째 렌더링이 준비되었습니다. 구현하기가 매우 간단하지 않나요?
하지만 이렇게 작업을 제출하면 더 이상 일하고 싶지 않을 것입니다. 무작위로 끌 수 없도록 끌기 위치를 지정합니다. ,
두 번째 단계는 드래그 범위를 제어하는 것입니다.
드래그 범위를 제어하려면 먼저 이 두 컨트롤을 가져와서 이 두 컨트롤의 속성을 가져와야 합니다. 우리는 운영합니다. 그래서 우리는 메소드를 다시 작성했습니다:
/** * Finalize inflating a view from XML. This is called as the last phase * of inflation, after all child views have been added. * 当xml填充完的时候去掉用,在这里我们可以找到我们要去操控的那两个布局 * <p>Even if the subclass overrides onFinishInflate, they should always be * sure to call the super method, so that we get called. */ @Override protected void onFinishInflate() { super.onFinishInflate(); /** * 根据索引来找 */ /** * 得到左边的布局 */ mLeftContent = (ViewGroup) getChildAt(0); /** * 得到主main布局 */ mMainContent = (ViewGroup) getChildAt(1); }
다음으로 너비와 높이를 가져와야 합니다. onMessure()에서 얻을 수 있다는 것을 알고 있지만 확인한 후에는 다음 메서드도 얻을 수 있습니다.
/** * 当尺寸变化的时候去调用 * This is called during layout when the size of this view has changed * @param w * @param h * @param oldw * @param oldh */ @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); /** * 屏幕的宽度和高度 */ mHeight = getMeasuredHeight(); mWidth = getMeasuredWidth(); /** * 自定义左侧view拖拽出来的距离 */ mRange = (int) (mWidth * 0.7); }
좋아, 필요한 너비, 높이, 드래그 거리를 얻었으므로 다음으로 제한하겠습니다.
메인 패널이 왼쪽으로 이동하는 것을 제한하려면 이를clampViewPositionHorizontal() 메서드에 추가하기만 하면 되고, 왼쪽 패널은 오른쪽의 mRange 위치로만 이동할 수 있습니다. (여기서 시도해 볼 수 있습니다)
if (child == mMainContent) { left = fixLeft(left); } /** * 修正方法 * 根据范围去修正左侧的view的可见 * * @param left * @return */ private int fixLeft(int left) { if (left < 0) { return 0; } else if (left > mRange) { return mRange; } return left; }
이때 기본적인 일반 프레임워크는 나왔지만 슬라이딩 효과를 구현했지만 여전히 문제가 있습니다(오른쪽은 고정되지만 LeftView를 밖으로 밀어내면 여전히 오른쪽으로 밀어 넣을 수 있습니다.) 이를 제한할 방법을 찾아야 합니다. 즉, 왼쪽의 뷰를 오른쪽으로만 거리만큼 밀어 넣을 수 있습니다. 이제 우리는 메소드를 확인해야 합니다. 어떤 메소드가 변경된 위치의 값을 가져온 다음 변경할 수 있는지:
/** * 当view位置改变的时候,处理要做的事情,更新状态,伴随动画,重绘界面 * * 此时view已经发生了位置的改变 * * @param changedView 改变的位置view * @param left 新的左边值 * @param top * @param dx 水平变化量 * @param dy */ @Override public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { super.onViewPositionChanged(changedView, left, top, dx, dy); int newLeft = left; //如果我们拖拽的是左面板 if (changedView == mLeftContent) { //新的左侧位置是我们的主面板的左侧加上水平变化量 newLeft = mMainContent.getLeft() + dx; } //进行修正(不能超出我们的规定的范围) newLeft = fixLeft(newLeft); if (changedView == mLeftContent) { //当左面板移动之后,在强制放回去 mLeftContent.layout(0, 0, 0 + mWidth, 0 + mHeight); mMainContent.layout(newLeft, 0, newLeft + mWidth, 0 + mHeight); } //兼容低版本 强制重绘 invalidate(); }
자, 이제 일반적인 효과가 나왔습니다. 렌더링을 살펴보세요. (여기 가운데 흰색은 녹음 문제이고 개인 테스트에는 문제 없습니다.)
이쯤 되면 대략적인 드래그 앤 드롭이 가능합니다. 물론 현재 레이아웃은 단순 구현입니다. 아래(먼저 몇 가지 컨트롤을 추가해야 합니다. 두 개의 LinearLayouts에 직접 추가하세요.)
<?xml version="1.0" encoding="utf-8"?> <com.example.qqsliding.DragLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.example.qqsliding.MainActivity"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:background="@mipmap/sidebar_bg"> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:background="#FFFFFF"> <RelativeLayout android:layout_width="match_parent" android:layout_height="50dp" android:background="#0CB8F6" android:gravity="center_vertical"> <ImageView android:layout_width="30dp" android:layout_height="30dp" android:layout_marginLeft="15dp" android:src="@mipmap/icon_avatar_white"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:text="Header"/> <ImageView android:layout_width="30dp" android:layout_height="30dp" android:layout_alignParentRight="true" android:layout_marginRight="15dp" android:src="@mipmap/icon_search"/> </RelativeLayout> </LinearLayout> </com.example.qqsliding.DragLayout>
하지만 조심하는 사람들은 드래그할 때 특히 뻣뻣하다는 것을 알 수 있습니다. 애니메이션 효과를 끌어서 애니메이션을 구체적으로 추가하고 콜백 효과를 정의하세요. Android 슬라이딩 최적화 QQ6.0 사이드 슬라이딩 메뉴(2)를 배우려면 이 글을 읽어보세요. 이 글을 공유하는 것이 모든 사람에게 도움이 되기를 바랍니다.
ViewDragHelper를 사용하여 QQ6.0과 유사한 측면 슬라이딩 인터페이스를 구현하는 Android에 대한 자세한 내용은 (1) PHP 중국어 웹사이트에서 관련 기사를 참고하세요!