首頁 > Java > java教程 > Android使用ViewDragHelper實作仿QQ6.0側滑介面(一)

Android使用ViewDragHelper實作仿QQ6.0側滑介面(一)

高洛峰
發布: 2017-01-13 10:16:41
原創
1199 人瀏覽過

QQ是大家離不開的聊天工具,方便既實用,自從qq更新至6.0之後,側滑由原來的劃出後主面板縮小變成了左右平滑,在外觀上有了很大的提升,於是我就是嘗試理解裡面的各種邏輯,結合相關資料,研究研究。

知道這裡面的一個主要類是ViewDragHelper,那麼首先我們要先來了解一下這個ViewDragHelper類,正所謂打蛇打七寸,我們就先來看看官方文檔怎麼介紹的,有什麼奇特的功能。

首先繼承:

java.lang.Object 
android.support.v4.widget.ViewDragHelper 
直接父類別是Object。

類概述

ViewDragHelper is a utility class for writing custom ViewGroups. It offers a number of useful operations and state tracking for allowing a user to dView and reposition viewsful operations and state tracking for allowing a user to dView工具類,本省提供了許多有用的方法和狀態允許使用者去拖曳和繪製他們在父ViewGroup中的軌跡和位置。


Nested Classes(巢狀類別)

ViewDragHelper.Callback

A Callback is used as a communication channel with the ViewDragHelper back to the parent view communication channel with the ViewDragHelper back to the parent view using it.ragview通訊的介面



一個公開靜態方法:


我們可以知道,ViewDragHelper是透過create()方法建構出來。這個在後面會有詳細介紹。

讓我們在來看下需要用到的裡面的幾個方法:Android使用ViewDragHelper實作仿QQ6.0側滑介面(一)

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) {}
登入後複製

上面的幾個方法,會在程式碼中有詳細的註釋,在這裡只是看下我們需要重寫的方法

好了哈,說了這麼多,我們就先來個簡單的,就是可以實現拖曳(相信當你的兩個view可以拖曳的時候,你會發現,哦這麼簡單幾步麼):

第一步實現拖曳功能(簡單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;
}
};
登入後複製

好了,第一個效果圖可以出來了,就是可以拖曳了,是不是很簡單的就實現了呢:

但是,你要是做成這樣提交任務,是不是不想幹活了哈,好了下面我們就來控制一下拖曳位置,不能讓他亂拖曳了哈。 、

第二步,控制拖曳範圍Android使用ViewDragHelper實作仿QQ6.0側滑介面(一)

我們想要控制拖曳範圍,首先我們得需要拿到這兩個控件,取到有關這兩個控件的屬性,我們才能去操作。於是我們重寫了一下的方法:

/**
* 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);
}
登入後複製

好了,有關我們需要的寬、高、拖曳距離我們已經獲取到了,那麼我們接下來就要來限制了。

我們只需要在clampViewPositionHorizo​​ntal()方法中加入這個,就能限制主面板不能往左移,左面板只能移動到右側的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我只能右滑mRange的距離這個時候我們就要查看方法了,哪個方法可以拿到變化的position的值,然後去改變:

/**
* 当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();
}
登入後複製

好了,這時候我們的大致效果已經出來了,看下效果圖。 (這裡的中間出來的白到屬於錄製問題,親測沒問題)

到這裡,大致的拖曳已經可以實現了,當然了哈,我的現在佈局就是下面的簡單的實現(要先加一些控件,這個自己在兩個LinearLayout中加入即可)

<?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側滑選單(二),希望本文分享對大家有幫助。

更多Android使用ViewDragHelper實作仿QQ6.0側滑介面(一)相關文章請關注PHP中文網!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板