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

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
JVM如何在不同平台上管理垃圾收集?JVM如何在不同平台上管理垃圾收集?Apr 28, 2025 am 12:23 AM

JVMmanagesgarbagecollectionacrossplatformseffectivelybyusingagenerationalapproachandadaptingtoOSandhardwaredifferences.ItemploysvariouscollectorslikeSerial,Parallel,CMS,andG1,eachsuitedfordifferentscenarios.Performancecanbetunedwithflagslike-XX:NewRa

为什么Java代码可以在不同的操作系统上运行,而无需修改?为什么Java代码可以在不同的操作系统上运行,而无需修改?Apr 28, 2025 am 12:14 AM

Java代码可以在不同操作系统上无需修改即可运行,这是因为Java的“一次编写,到处运行”哲学,由Java虚拟机(JVM)实现。JVM作为编译后的Java字节码与操作系统之间的中介,将字节码翻译成特定机器指令,确保程序在任何安装了JVM的平台上都能独立运行。

描述编译和执行Java程序的过程,突出平台独立性。描述编译和执行Java程序的过程,突出平台独立性。Apr 28, 2025 am 12:08 AM

Java程序的编译和执行通过字节码和JVM实现平台独立性。1)编写Java源码并编译成字节码。2)使用JVM在任何平台上执行字节码,确保代码的跨平台运行。

基础硬件架构如何影响Java的性能?基础硬件架构如何影响Java的性能?Apr 28, 2025 am 12:05 AM

Java性能与硬件架构密切相关,理解这种关系可以显着提升编程能力。 1)JVM通过JIT编译将Java字节码转换为机器指令,受CPU架构影响。 2)内存管理和垃圾回收受RAM和内存总线速度影响。 3)缓存和分支预测优化Java代码执行。 4)多线程和并行处理在多核系统上提升性能。

解释为什么本地库可以破坏Java的平台独立性。解释为什么本地库可以破坏Java的平台独立性。Apr 28, 2025 am 12:02 AM

使用原生库会破坏Java的平台独立性,因为这些库需要为每个操作系统单独编译。1)原生库通过JNI与Java交互,提供Java无法直接实现的功能。2)使用原生库增加了项目复杂性,需要为不同平台管理库文件。3)虽然原生库能提高性能,但应谨慎使用并进行跨平台测试。

JVM如何处理操作系统API的差异?JVM如何处理操作系统API的差异?Apr 27, 2025 am 12:18 AM

JVM通过JavaNativeInterface(JNI)和Java标准库处理操作系统API差异:1.JNI允许Java代码调用本地代码,直接与操作系统API交互。2.Java标准库提供统一API,内部映射到不同操作系统API,确保代码跨平台运行。

Java 9影响平台独立性中引入的模块化如何?Java 9影响平台独立性中引入的模块化如何?Apr 27, 2025 am 12:15 AM

modularitydoesnotdirectlyaffectJava'splatformindependence.Java'splatformindependenceismaintainedbytheJVM,butmodularityinfluencesapplicationstructureandmanagement,indirectlyimpactingplatformindependence.1)Deploymentanddistributionbecomemoreefficientwi

什么是字节码,它与Java的平台独立性有何关系?什么是字节码,它与Java的平台独立性有何关系?Apr 27, 2025 am 12:06 AM

BytecodeinJavaistheintermediaterepresentationthatenablesplatformindependence.1)Javacodeiscompiledintobytecodestoredin.classfiles.2)TheJVMinterpretsorcompilesthisbytecodeintomachinecodeatruntime,allowingthesamebytecodetorunonanydevicewithaJVM,thusfulf

See all articles

热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

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

热工具

安全考试浏览器

安全考试浏览器

Safe Exam Browser是一个安全的浏览器环境,用于安全地进行在线考试。该软件将任何计算机变成一个安全的工作站。它控制对任何实用工具的访问,并防止学生使用未经授权的资源。

禅工作室 13.0.1

禅工作室 13.0.1

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

mPDF

mPDF

mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

Atom编辑器mac版下载

Atom编辑器mac版下载

最流行的的开源编辑器