相信大家也都是用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的通信的接口

一个公开静态方法:

我们可以知道,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*/@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {//让自己的控件自行判断是否去拦截return mDragHelper.shouldInterceptTouchEvent(ev);}@Overridepublic 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   右侧可以移动*/@Overridepublic boolean tryCaptureView(View child, int pointerId) {//这里要返回true,要不然不能拖拽return true;}/*** 根据建议值修正将要移动的位置   此时并没有发生真正的移动(左右)** @param child    当前拖拽的view* @param left     新的位置的建议值  oldLeft + dx* @param dx       变化量   和变化之前位置的差值* @return*/@Overridepublic int clampViewPositionHorizontal(View child, int left, int dx) {//返回值该child现在的位置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.*/@Overrideprotected 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*/@Overrideprotected 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*/@Overridepublic 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>

但是细心的可能会发现,我们拖拽的时候,特别生硬,那是因为我们没有加上动画效果,只是生生的给拖拽出来了,具体的加入动画,定义回调效果,我会在稍后的仿QQ6.0侧滑优化中介绍:http://blog.csdn.net/wuyinlei/article/details/50617408,本人小白一枚,希望自己的知识总结能够帮助到他人,如有交流,请QQ:1069584784.鄙人会不胜感激。

仿QQ6.0侧滑之ViewDragHelper的使用(一)相关推荐

  1. 仿QQ6 0侧滑之ViewDragHelper的使用(一)

    title : 仿QQ6.0侧滑之ViewDragHelper的使用(一) 相信大家也都是用QQ,自从QQ更新至6.0后,侧滑由原先的划出后主面板缩小变成了左右平滑,个人觉得这样还是听美观的(个人观点 ...

  2. 仿QQ5.0侧滑菜单

    一.概述 侧滑菜单现在已经非常流行了,目前大概有这么几种:最普通的侧滑,抽屉侧滑,QQ侧滑 注:本文来自慕课网 二.最普通的侧滑 先上图 代码如下: 1 public class MainActivi ...

  3. Android 高仿 QQ5.0 侧滑菜单效果 自定义控件来袭

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/39257409,本文出自[张鸿洋的博客] 上一篇博客带大家实现了:Android ...

  4. Android仿QQ5.0侧滑菜单ResideMenu的使用和源码分析

    本文出自Cym的博客(http://blog.csdn.net/cym492224103) ResideMenu github:https://github.com/SpecialCyCi/Andro ...

  5. 打造华丽QQ5.0侧滑效果

    已经好久没写过Android开发的技术博客,只因最近项目比较急.耽误了.今天带来的QQ5.0侧滑效果.我们都对QQ5.0侧滑效果很熟悉了,就不多做介绍,就一个字"炫".正好这次在项 ...

  6. Android之高仿QQ6.6.0侧滑效果(背景动画、透明+沉浸式状态栏、渐变效果)

    根据需求实现类似QQ侧滑效果,之前看到过很多实现方式通过SlidingMenu,但是既然官方推出了自己的专属控件,那么使用DrawerLayout就是不二选择.且看下文. 一.先来看看官方文档解释 D ...

  7. android 缩放透明动画,Android之高仿QQ6.6.0侧滑效果(背景动画、透明+沉浸式状态栏、渐变效果)...

    根据需求实现类似QQ侧滑效果,之前看到过很多实现方式通过SlidingMenu,但是既然官方推出了自己的专属控件,那么使用DrawerLayout就是不二选择.且看下文. 一.先来看看官方文档解释 D ...

  8. Flutter | 超简单仿微信QQ侧滑菜单组件(改)

    文章目录 一.明确需求 二.实现需求 1. 滑动菜单实现使用`SingleChildScrollView`: 2. 列表滑动不够距离则菜单再次隐藏,距离足够则完全展示菜单. 3. 菜单支持事件处理. ...

  9. wekan 看板系统(仿trello)0.49 虚拟机文件(virtualbox vmware images)

    2019独角兽企业重金招聘Python工程师标准>>> wekan 看板系统(仿trello)0.49 虚拟机文件(virtualbox vmware images) https:/ ...

最新文章

  1. leetCode:twoSum 两数之和 【JAVA实现】
  2. 实现自己的连接池(一)
  3. python映射类型-python笔记-映射类型(字典)
  4. python软件安装步骤-Linux中Python 环境软件包安装步骤
  5. Nginx+tomcat负载均衡session问题解决
  6. chrome浏览器插件开发
  7. python 类方法调用一次自增1_Python+selenium自动化脚本如何使数字每次执行自增1
  8. 【成都站参会指南】神策 2020 数据驱动用户大会,邀您面基!
  9. 一文看懂谷歌 NYC 算法与优化业务全景:三大项目组12个子领域详解(附重点论文下载)
  10. 大数据中常见的端口号 总结汇总大全(最新)
  11. 算法高级(13)-常见负载均衡算法Java代码实现
  12. 爬取校园网新闻首页的新闻 使用正则表达式,函数抽离
  13. string wstring
  14. Java中的try/catch/finally
  15. 如何在Win7 x64上的配置32位的PostgreSQL ODBC数据源
  16. coap 返回版本信息_CoAP协议学习笔记——CoAP格式详解
  17. 微信小程序之组件的四种传值方式
  18. 实习总结与收获(2021.6.7-2021.8.27)
  19. rancher部署安装好后,无法部署pod
  20. 敏捷物联——引领生产和服务创新

热门文章

  1. 十一黄金周明日开启.外出旅游要注意些什么?
  2. vuecli脚手架的搭建
  3. python数字形式转换_python将字母转化为数字实例方法
  4. lol服务器维护多久,LOL服务器炸了?说好的12点,硬生生维护了一天?建议补偿二十层...
  5. Word 2007 中如何在论文正文处设置页码,以及删除空白页。
  6. js encodeuri转码和解码
  7. Retrofit网络加载库二次封装支持RxJava与Flow-HttpUtils
  8. 有一种感情叫无缘,有一种放弃叫成全
  9. 机器人 郭启寅_宁波股票开户 GQY视讯董事长郭启寅简介
  10. 记录一个 uniapp-checkbox 如何动态改变勾选状态