自定义View系列教程08--滑动冲突的产生及其处理
来源:互联网 发布:librtmp 源码 编辑:程序博客网 时间:2024/05/18 18:15
探索Android软键盘的疑难杂症
深入探讨Android异步精髓Handler
详解Android主流框架不可或缺的基石
站在源码的肩膀上全解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时常常发生。
这些滑动冲突的产生,一般而言都具有以下特点:
- 子View和父View都有滑动的需求
- 滑动事件不能准确地传递给合适的View
其实,Google官方不鼓励这种滑动嵌套的设计;但是在实际项目中却会碰到客户提出类似的要求。既然不太合理的东西已经存在了,开发人员再去抱怨设计或者客户都没有实际作用了,只有想办法完成对应的功能。
那么,有哪些方法可以解决滑动冲突呢?
子View禁止父View拦截Touch事件
在分析ViewGroup的dispatchTouchEvent()源码时,我们知道:Touch事件是由父View分发的。如果一个Touch事件是子View需要的,但是被其父View拦截了,子View就无法处理该Touch事件了。在此情形下,子View可以调用requestDisallowInterceptTouchEvent( )禁止父View对Touch的拦截在父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--滑动冲突的产生及其处理
- 自定义View系列教程08--滑动冲突的产生及其处理
- 滑动冲突的产生及其处理-纯理论
- View滑动冲突的处理
- View的滑动冲突处理
- View滑动冲突处理
- View的滑动方式及冲突处理
- 自定义View---怎么解决View的滑动冲突
- 自定义View解决滑动冲突
- 自定义View解决滑动冲突
- View 滑动冲突处理方法
- view 的滑动冲突
- View的滑动冲突
- View的滑动冲突
- View的滑动冲突
- View的滑动冲突
- View 的滑动冲突
- View的滑动冲突
- java 计算引擎比较
- 一个http请求发送到后端的详细过程
- 用unicode十进制编码 查看字符串里的特殊字符是什么
- php关闭错误提示
- ArrayList实现冒泡排序
- 自定义View系列教程08--滑动冲突的产生及其处理
- gdfg
- RxJava操作符(04-过滤操作)
- DataGridView列的宽度、行的高度自动调整
- 切换全半角
- mysql常用命令
- 四-网络性能排查之TCP重传与重复ACK
- 怎么创建unity NGUI Atlas图集?
- python 函数