深入探讨Android异步精髓Handler


站在源码的肩膀上全解Scroller工作机制


Android多分辨率适配框架(1)— 核心基础

Android多分辨率适配框架(2)— 原理剖析

Android多分辨率适配框架(3)— 使用指南


自定义View系列教程00–推翻自己和过往,重学自定义View

自定义View系列教程01–常用工具介绍

自定义View系列教程02–onMeasure源码详尽分析

自定义View系列教程03–onLayout源码详尽分析

自定义View系列教程04–Draw源码分析及其实践

自定义View系列教程05–示例分析

自定义View系列教程06–详解View的Touch事件处理

自定义View系列教程07–详解ViewGroup分发Touch事件

自定义View系列教程08–滑动冲突的产生及其处理


PS:如果觉得文章太长,那就直接看视频


在之前的几篇文章中,我们已经分析了View对于Touch的处理以及ViewGroup对于Touch事件的分发。

但在开发中时常遇到一个棘手的问题:Touch事件的滑动冲突。比如ListView嵌套ScrollView,ViewPager嵌套ScrollView,ListView嵌套ScrollView时常常发生。

这些滑动冲突的产生,一般而言都具有以下特点:

  1. 子View和父View都有滑动的需求
  2. 滑动事件不能准确地传递给合适的View

其实,Google官方不鼓励这种滑动嵌套的设计;但是在实际项目中却会碰到客户提出类似的要求。既然不太合理的东西已经存在了,开发人员再去抱怨设计或者客户都没有实际作用了,只有想办法完成对应的功能。

那么,有哪些方法可以解决滑动冲突呢?

  1. 子View禁止父View拦截Touch事件

    在分析ViewGroup的dispatchTouchEvent()源码时,我们知道:Touch事件是由父View分发的。如果一个Touch事件是子View需要的,但是被其父View拦截了,子View就无法处理该Touch事件了。在此情形下,子View可以调用requestDisallowInterceptTouchEvent( )禁止父View对Touch的拦截

  2. 在父View中准确地进行事件分发和拦截

    我们可以重写父View中与Touch事件分发相关的方法,比如onInterceptTouchEvent( )。这些方法中摒弃系统默认的流程,结合自身的业务逻辑重写该部分代码,从而使父View放行子View需要的Touch。

在此,通过一个示例展示解决滑动冲突的常用方法。

示例效果,请看下图:

它的布局文件如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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.stay4it.testtouch3.MainActivity"> <HorizontalScrollView
android:id="@+id/horizontalScrollView"
android:layout_height="450dp"
android:layout_width="match_parent"
android:scrollbars="horizontal"
android:fillViewport="true"> <android.support.v4.view.ViewPager
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent" /> </HorizontalScrollView> </RelativeLayout>

在该示例中,我们在HorizontalScrollView中嵌入ViewPager浏览图片。由于HorizontalScrollView和ViewPager都可以响应水平滑动,当我们用手指切换图片时发现ViewPager无法正常的滚动。这是因为Touch事件被HorizontalScrollView处理,根本没有传递给ViewPager。

嗯哼,滑动冲突的原因已经清楚了,我们现在来解决这个问题。

第一种解决方法

在ViewPager中禁止HorizontalScrollView拦截Touch事件

package com.stay4it.testtouch3;

import android.os.Bundle;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.view.MotionEvent;
import android.view.View;
/**
* 原创作者
* 谷哥的小弟
*
* 博客地址
* http://blog.csdn.net/lfdfhl
*/
public class MainActivity extends AppCompatActivity {
private ViewPager mViewPager;
private ViewPagerAdapter mViewPagerAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
} private void init(){
mViewPager = (ViewPager) findViewById(R.id.viewPager);
mViewPagerAdapter=new ViewPagerAdapter(this);
mViewPager.setAdapter(mViewPagerAdapter);
mViewPager.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
mViewPager.getParent().requestDisallowInterceptTouchEvent(true);
return false;
}
});
}
}

在此,请关注第32行代码

mViewPager.getParent().requestDisallowInterceptTouchEvent(true);

此处首先利用 mViewPager.getParent( )得到了ViewPager的父View即HorizontalScrollView;然后再执行requestDisallowInterceptTouchEvent( )方法从而禁止掉父View对于Touch事件的传递。

第二种解决方法

在自定义HorizontalScrollView中合理地处理Touch事件的拦截和分发

package com.stay4it.testtouch4;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.HorizontalScrollView;
/**
* 原创作者
* 谷哥的小弟
*
* 博客地址
* http://blog.csdn.net/lfdfhl
*/
public class HorizontalScrollViewSubclass extends HorizontalScrollView{
private float LastX;
private float LastY;
private float distanceX;
private float distanceY;
public HorizontalScrollViewSubclass(Context context, AttributeSet attrs) {
super(context, attrs);
} @Override
public boolean dispatchTouchEvent(MotionEvent ev) {
return super.dispatchTouchEvent(ev);
} @Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()){
case MotionEvent.ACTION_DOWN:
distanceX = 0f;
distanceY = 0f;
LastX = ev.getX();
LastY = ev.getY();
break;
case MotionEvent.ACTION_MOVE: final float currentX = ev.getX();
final float currentY = ev.getY(); distanceX += Math.abs(currentX - LastX);
distanceY += Math.abs(currentY - LastY); LastX = currentX;
LastY = currentY; if(distanceX > distanceY){
return false;
}
break;
case MotionEvent.ACTION_UP:
break;
}
return super.onInterceptTouchEvent(ev);
} @Override
public boolean onTouchEvent(MotionEvent ev) {
return super.onTouchEvent(ev);
}
}

从这段代码中,我们的主要操作是在自定义HorizontalScrollView中重写了onInterceptTouchEvent( )。

在该方法中如果判定Touch是水平的滑动:

if(distanceX > distanceY)

那么直接返回false不拦截该Touch。这样Touch事件就可以顺利传递到其子View即ViewPager中,从而正常地切换图片。

既然已经采用了自定义的HorizontalScrollView就不要忘记修改布局文件喔~

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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.stay4it.testtouch4.MainActivity"> <com.stay4it.testtouch4.HorizontalScrollViewSubclass
android:id="@+id/horizontalScrollView"
android:layout_height="450dp"
android:layout_width="match_parent"
android:scrollbars="horizontal"
android:fillViewport="true"
> <android.support.v4.view.ViewPager
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent" /> </com.stay4it.testtouch4.HorizontalScrollViewSubclass> </RelativeLayout>

嗯哼,在此通过一个完整的示例展示了事件滑动冲突的常用解决方式。

在实际的项目开发中所遇到的滑动冲突可能比这要复杂,但是处理冲突的基本原理和方式是相同的。


至此,自定义View系列教程就全部结束了

多谢大家的指正和鼓励

Thank you very much


PS:如果觉得文章太长,那就直接看视频

自定义View系列教程08--滑动冲突的产生及其处理的更多相关文章

  1. 自定义View系列教程01--常用工具介绍

    站在源码的肩膀上全解Scroller工作机制 Android多分辨率适配框架(1)- 核心基础 Android多分辨率适配框架(2)- 原理剖析 Android多分辨率适配框架(3)- 使用指南 自定 ...

  2. 自定义View系列教程07--详解ViewGroup分发Touch事件

    深入探讨Android异步精髓Handler 站在源码的肩膀上全解Scroller工作机制 Android多分辨率适配框架(1)- 核心基础 Android多分辨率适配框架(2)- 原理剖析 Andr ...

  3. 自定义View系列教程06--详解View的Touch事件处理

    深入探讨Android异步精髓Handler 站在源码的肩膀上全解Scroller工作机制 Android多分辨率适配框架(1)- 核心基础 Android多分辨率适配框架(2)- 原理剖析 Andr ...

  4. 自定义View系列教程05--示例分析

    站在源码的肩膀上全解Scroller工作机制 Android多分辨率适配框架(1)- 核心基础 Android多分辨率适配框架(2)- 原理剖析 Android多分辨率适配框架(3)- 使用指南 自定 ...

  5. 自定义View系列教程04--Draw源码分析及其实践

    深入探讨Android异步精髓Handler 站在源码的肩膀上全解Scroller工作机制 Android多分辨率适配框架(1)- 核心基础 Android多分辨率适配框架(2)- 原理剖析 Andr ...

  6. 自定义View系列教程03--onLayout源码详尽分析

    深入探讨Android异步精髓Handler 站在源码的肩膀上全解Scroller工作机制 Android多分辨率适配框架(1)- 核心基础 Android多分辨率适配框架(2)- 原理剖析 Andr ...

  7. 自定义View系列教程02--onMeasure源码详尽分析

    深入探讨Android异步精髓Handler 站在源码的肩膀上全解Scroller工作机制 Android多分辨率适配框架(1)- 核心基础 Android多分辨率适配框架(2)- 原理剖析 Andr ...

  8. wing带你玩转自定义view系列(3)模仿微信下拉眼睛

    发现了爱神的自定义view系列,我只想说一个字:凸(艹皿艹 ) !!相见恨晚啊,早看到就不会走这么多弯路了 另外相比之下我这完全是小儿科..所以不说了,这篇是本系列完结篇....我要从零开始跟随爱哥脚 ...

  9. wing带你玩转自定义view系列(2) 简单模仿qq未读消息去除效果

    上一篇介绍了贝塞尔曲线的简单应用 仿360内存清理效果 这一篇带来一个  两条贝塞尔曲线的应用 : 仿qq未读消息去除效果. 转载请注明出处:http://blog.csdn.net/wingicho ...

随机推荐

  1. promise的实现方式和运行机制

    promise的规范其实种类很多,我们最常用的是promise/A+ 这篇文章会先将一个类似于promise的构造函数怎么写,网上很多教程并没有实现A+规范,只是看起来像而已 然后我们深入探究如何一步 ...

  2. 笔记本最小安装centos7 连接WiFi的方法

    1.首先下载iw工具. yum -y install iw 2.获取无线网卡的名称 执行iw dev,假设获得名称为 wlp3s0(示例) 3.激活无线网络接口 执行ip link set wlp3s ...

  3. 常见的HTML标签的嵌套规则

    众所周知,HTML标签有两类: 块级元素div.h1~h6.address.blockquote.center.dir.dl.dt.dd.fieldset.form.hr.isindex.menu.n ...

  4. flask的基本操作

    常用的SQLAlchemy字段类型 # coding:utf-8 from flask import Flask from flask_sqlalchemy import SQLAlchemy app ...

  5. Leetcode22.Generate Parentheses括号生成

    给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合. 例如,给出 n = 3,生成结果为: [ "((()))", "(()())& ...

  6. Leetcode622.Design Circular Queue设计循环队列

    设计你的循环队列实现. 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环.它也被称为"环形缓冲器". 循环队列的一个好处是 ...

  7. Linux下安装配置git

    参考博客: https://www.cnblogs.com/luhouxiang/p/5801853.html但执行git --version命令会出现 git version 1.8.3.1 不是最 ...

  8. Day2-转自金角大王

    本节内容 列表.元组操作 字符串操作 字典操作 集合操作 文件操作 字符编码与转码 1. 列表.元组操作 列表是我们最以后最常用的数据类型之一,通过列表可以对数据实现最方便的存储.修改等操作 定义列表 ...

  9. 第一周<导学>

    导学 欧氏距离 平方 曼哈顿距离 一次方 马氏距离 协方差(先标准化再计算距离)\(d(x_{i},x_{j})=\sqrt{(x_{i}-x_{j})^{T}s^{-1}(x_{i}-x{j})}\ ...

  10. JSP Web第四章整理复习 JSP技术基础

    P104 JSP简介 (1)基本概念:jsp技术.jsp.jsp网页组成 JSP技术基础java servlet和整个java体系的Web服务器端开发技术. JSP表示它是用java写的Web服务页面 ...