首页 Java java教程 Android使用ViewDragHelper实现仿QQ6.0侧滑界面(一)

Android使用ViewDragHelper实现仿QQ6.0侧滑界面(一)

Jan 13, 2017 am 10:16 AM

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 drag and reposition views within their parent ViewGroup.

他是一个编写自定义ViewGroup的工具类,本省提供了许多有用的方法和状态允许用户去拖拽和绘制他们在父ViewGroup中的轨迹和位置。

Nested Classes(嵌套类)

ViewDragHelper.Callback
A Callback is used as a communication channel with the ViewDragHelper back to the parent view using it.

一个回调是用作ViewDragHelper和他的父view的通信的接口

一个公开静态方法:

Android使用ViewDragHelper实现仿QQ6.0侧滑界面(一)

我们可以知道,ViewDragHelper是通过create()方法构造出来。这个在后面会有详细介绍。

让我们在来看下需要用到的里面的几个方法:

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);
}
登录后复制

好了,有关我们需要的宽、高、拖拽距离我们已经获取到了,那么我们接下来就要来限制了。

我们只需要在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我只能右滑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中文网!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

公司安全软件导致应用无法运行?如何排查和解决? 公司安全软件导致应用无法运行?如何排查和解决? Apr 19, 2025 pm 04:51 PM

公司安全软件导致部分应用无法正常运行的排查与解决方法许多公司为了保障内部网络安全,会部署安全软件。...

如何使用MapStruct简化系统对接中的字段映射问题? 如何使用MapStruct简化系统对接中的字段映射问题? Apr 19, 2025 pm 06:21 PM

系统对接中的字段映射处理在进行系统对接时,常常会遇到一个棘手的问题:如何将A系统的接口字段有效地映�...

如何优雅地获取实体类变量名构建数据库查询条件? 如何优雅地获取实体类变量名构建数据库查询条件? Apr 19, 2025 pm 11:42 PM

在使用MyBatis-Plus或其他ORM框架进行数据库操作时,经常需要根据实体类的属性名构造查询条件。如果每次都手动...

如何将姓名转换为数字以实现排序并保持群组中的一致性? 如何将姓名转换为数字以实现排序并保持群组中的一致性? Apr 19, 2025 pm 11:30 PM

将姓名转换为数字以实现排序的解决方案在许多应用场景中,用户可能需要在群组中进行排序,尤其是在一个用...

IntelliJ IDEA是如何在不输出日志的情况下识别Spring Boot项目的端口号的? IntelliJ IDEA是如何在不输出日志的情况下识别Spring Boot项目的端口号的? Apr 19, 2025 pm 11:45 PM

在使用IntelliJIDEAUltimate版本启动Spring...

Java对象如何安全地转换为数组? Java对象如何安全地转换为数组? Apr 19, 2025 pm 11:33 PM

Java对象与数组的转换:深入探讨强制类型转换的风险与正确方法很多Java初学者会遇到将一个对象转换成数组的�...

电商平台SKU和SPU数据库设计:如何兼顾用户自定义属性和无属性商品? 电商平台SKU和SPU数据库设计:如何兼顾用户自定义属性和无属性商品? Apr 19, 2025 pm 11:27 PM

电商平台SKU和SPU表设计详解本文将探讨电商平台中SKU和SPU的数据库设计问题,特别是如何处理用户自定义销售属...

使用TKMyBatis进行数据库查询时,如何优雅地获取实体类变量名构建查询条件? 使用TKMyBatis进行数据库查询时,如何优雅地获取实体类变量名构建查询条件? Apr 19, 2025 pm 09:51 PM

在使用TKMyBatis进行数据库查询时,如何优雅地获取实体类变量名以构建查询条件,是一个常见的难题。本文将针...

See all articles