原文:

http://www.cnblogs.com/punkisnotdead/p/5179115.html#3358859

1.View的坐标参数 主要有哪些?分别有什么注意的要点?

答:Left,Right,top,Bottom 注意这4个值其实就是 view 和 他的父控件的 相对坐标值。 并非是距离屏幕左上角的绝对值,这点要注意。

  此外,X和Y 其实也是相对于父控件的坐标值。 TranslationX,TranslationY 这2个值 默认都为0,是相对于父控件的左上角的偏移量。

  换算关系:

  x=left+tranX,y=top+tranY.

    很多人不理解,为什么事这样,其实就是View 如果有移动的话,比如平移这种,你们就要注意了,top和left 这种值 是不会变化的。

无论你把view怎么拖动,但是 x,y,tranX,tranY 的值是随着拖动平移 而变化的。想明白这点 就行了。

2.onTouchEvent和GestureDetector 在什么时候用哪个比较好?

答:只有滑动需求的时候 就用前者,如果有双击等这种行为的时候 就用后者。

3.Scroller 用来解决什么问题?

答:view的scrollTo和scrollBy 滑动效果太差了,是瞬间完成。而scroller可以配合view的computeScroll 来完成 渐变的滑动效果。体验更好。

4.ScrollTo和ScrollBy 有什么需要注意的?

答:前者是绝对滑动,后者是相对滑动。滑动的是view的内容 而不是view本身。这很重要。比如textview 调用这2个方法  滑动的就是显示出来的字的内容。

一般而言 我们用scrollBy会比较多一些。传值的话 其实 记住几个法则就可以了。 右-左 x为正 否则x为负  上-下 y为负,否则y为正。

可以稍微看一下 这2个的源码:

 1 public void scrollTo(int x, int y) {
2 if (mScrollX != x || mScrollY != y) {
3 int oldX = mScrollX;
4 int oldY = mScrollY;
5 mScrollX = x;
6 mScrollY = y;
7 invalidateParentCaches();
8 onScrollChanged(mScrollX, mScrollY, oldX, oldY);
9 if (!awakenScrollBars()) {
10 postInvalidateOnAnimation();
11 }
12 }
13 }
14
15 public void scrollBy(int x, int y) {
16 scrollTo(mScrollX + x, mScrollY + y);
17 }

看到里面有2个变量 mScrollX 和mScrollY 这2个东西没,这2个单位的 值是像素,前者代表 view的左边缘和view内容左边缘的距离。 后者代表 view上边缘和view内容上边缘的距离。

5.使用动画来实现view的滑动 有什么后果?

答:实际上view动画 是对view的表面ui 也就是给用户呈现出的视觉效果 来做的移动,动画本身并不能移动view的真正位置。属性动画除外。动画播放结束以后,view最终还是会

回到自己的位置的,。当然了你可以设置fillafter 属性 来让动画播放结束以后 view表象停留在 变化以后的位置。所以这会带来一个很严重的后果。比如你的button在屏幕的左边,

你现在用个动画 并且设置了fillafter属性让他去了右边。你会发现 点击右边的button 没有click事件触发,但是点击左边的 却可以触发,原因就是右边的button 只是view的表象,

真正的button 还在左边没有动过。你一定要这么做的话 可以提前在右边button移动后的位置放一个新的button,当你动画执行结束以后  把右边的enable 左边的让他gone就可以了。

这么做就可以规避上述问题。

6.让view滑动总共有几种方式,分别要注意什么?都适用于那些场景?

答:总共有三种:

a:scrollto,scrollby。这种是最简单的,但是只能滑动view的内容 不可以滑动view本身。

b:动画。动画可以滑动view内容,但是注意非属性动画 就如我们问题5说的内容 会影响到交互,使用的时候要多注意。不过多数复杂的滑动效果都是属性动画来完成的,属于大杀器级别、

c:改变布局参数。这种最好理解了,无非是动态的通过java代码来修改 margin等view的参数罢了。不过用的比较少。我本人不怎么用这种方法。

7.Scroller是干嘛的?原理是什么?

答:Scroller就是用于 让view有滑动渐变效果的。用法如下:

 1 package com.example.administrator.motioneventtest;
2
3 import android.content.Context;
4 import android.util.AttributeSet;
5 import android.widget.Scroller;
6 import android.widget.TextView;
7
8 /**
9 * Created by Administrator on 2016/2/2.
10 */
11 public class CustomTextView extends TextView{
12
13 private Scroller mScroller;
14
15
16 public CustomTextView(Context context) {
17 super(context);
18 mScroller=new Scroller(context);
19 }
20
21 public CustomTextView(Context context, AttributeSet attrs) {
22 super(context, attrs);
23 mScroller=new Scroller(context);
24
25 }
26
27 public CustomTextView(Context context, AttributeSet attrs, int defStyleAttr) {
28 super(context, attrs, defStyleAttr);
29 mScroller=new Scroller(context);
30
31 }
32
33 //调用此方法滚动到目标位置
34 public void smoothScrollTo(int fx, int fy) {
35 int dx = fx - mScroller.getFinalX();
36 int dy = fy - mScroller.getFinalY();
37 smoothScrollBy(dx, dy);
38 }
39
40 //调用此方法设置滚动的相对偏移
41 public void smoothScrollBy(int dx, int dy) {
42
43 //设置mScroller的滚动偏移量
44 mScroller.startScroll(mScroller.getFinalX(), mScroller.getFinalY(), dx, dy,4000);
45 invalidate();//这里必须调用invalidate()才能保证computeScroll()会被调用,否则不一定会刷新界面,看不到滚动效果
46 }
47
48 //使用scroller最重要不要遗漏这个方法
49 @Override
50 public void computeScroll() {
51 if (mScroller.computeScrollOffset())
52 {
53 scrollTo(mScroller.getCurrX(),mScroller.getCurrY());
54 //这个方法不要忘记调用。
55 postInvalidate();
56 }
57 super.computeScroll();
58 }
59 }

其实上述代码 很多人应该都能搜到。我们这里主要讲一下 他的原理。

  1 //参数很好理解 前面滑动起始点 中间滑动距离 最后一个是 渐变时间
2 //而且我们看到startScroll 这个方法就是设置了一下参数 并没有什么滑动的代码在
3 //回到前面的demo能看到我们通常调用完这个方法以后 都会马上调用invalidate()方法
4 public void startScroll(int startX, int startY, int dx, int dy, int duration) {
5 mMode = SCROLL_MODE;
6 mFinished = false;
7 mDuration = duration;
8 mStartTime = AnimationUtils.currentAnimationTimeMillis();
9 mStartX = startX;
10 mStartY = startY;
11 mFinalX = startX + dx;
12 mFinalY = startY + dy;
13 mDeltaX = dx;
14 mDeltaY = dy;
15 mDurationReciprocal = 1.0f / (float) mDuration;
16 }
17
18
19 //我们都知道invalidate 会触发view的 draw方法
20 //我们跟进去看 会发现draw方法里 会调用下面的代码:
21 //也就是说会调用 computeScroll方法 而view本身这个方法
22 //是空的所以会留给我们自己实现
23 int sx = 0;
24 int sy = 0;
25 if (!drawingWithRenderNode) {
26 computeScroll();
27 sx = mScrollX;
28 sy = mScrollY;
29 }
30
31
32 //然后回到我们的customtextview 可以看到我们实现的 computeScroll方法如下:
33 //你看在这个方法里 我们调用了scrollTo方法 来实现滑动,滑动结束以后再次触发view的重绘
34 //然后又会再次触发computeScroll 实现一个循环。
35 public void computeScroll() {
36 if (mScroller.computeScrollOffset())
37 {
38 scrollTo(mScroller.getCurrX(),mScroller.getCurrY());
39 //这个方法不要忘记调用。
40 postInvalidate();
41 }
42 super.computeScroll();
43 }
44
45
46 //返回true就代表滑动还没结束 false就是结束了
47 //其实这个方法 就跟属性动画里的插值器一样 你在使用startScroll方法的时候 会传一个事件的值,
48 //这个方法就是根据这个事件的值来计算你每一次scrollx和scrolly的值
49 public boolean computeScrollOffset() {
50 if (mFinished) {
51 return false;
52 }
53
54 int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime);
55
56 if (timePassed < mDuration) {
57 switch (mMode) {
58 case SCROLL_MODE:
59 final float x = mInterpolator.getInterpolation(timePassed * mDurationReciprocal);
60 mCurrX = mStartX + Math.round(x * mDeltaX);
61 mCurrY = mStartY + Math.round(x * mDeltaY);
62 break;
63 case FLING_MODE:
64 final float t = (float) timePassed / mDuration;
65 final int index = (int) (NB_SAMPLES * t);
66 float distanceCoef = 1.f;
67 float velocityCoef = 0.f;
68 if (index < NB_SAMPLES) {
69 final float t_inf = (float) index / NB_SAMPLES;
70 final float t_sup = (float) (index + 1) / NB_SAMPLES;
71 final float d_inf = SPLINE_POSITION[index];
72 final float d_sup = SPLINE_POSITION[index + 1];
73 velocityCoef = (d_sup - d_inf) / (t_sup - t_inf);
74 distanceCoef = d_inf + (t - t_inf) * velocityCoef;
75 }
76
77 mCurrVelocity = velocityCoef * mDistance / mDuration * 1000.0f;
78
79 mCurrX = mStartX + Math.round(distanceCoef * (mFinalX - mStartX));
80 // Pin to mMinX <= mCurrX <= mMaxX
81 mCurrX = Math.min(mCurrX, mMaxX);
82 mCurrX = Math.max(mCurrX, mMinX);
83
84 mCurrY = mStartY + Math.round(distanceCoef * (mFinalY - mStartY));
85 // Pin to mMinY <= mCurrY <= mMaxY
86 mCurrY = Math.min(mCurrY, mMaxY);
87 mCurrY = Math.max(mCurrY, mMinY);
88
89 if (mCurrX == mFinalX && mCurrY == mFinalY) {
90 mFinished = true;
91 }
92
93 break;
94 }
95 }
96 else {
97 mCurrX = mFinalX;
98 mCurrY = mFinalY;
99 mFinished = true;
100 }
101 return true;
102 }
103

8.view的滑动渐变效果总共有几种方法?

答:三种,第一种是scroller 也是使用最多的。问题7里有解释。还有一种就是动画,动画我就不多说了,不属于本文范畴。最后一种也是我们经常使用的就是用handler ,每隔一个时间间隔 来更新view的状态。

代码不写了很简单。 自行体会。

9.view的事件传递机制 如何用伪代码来表示?

答:

 1 /**
2 * 对于一个root viewgroup来说,如果接受了一个点击事件,那么首先会调用他的dispatchTouchEvent方法。
3 * 如果这个viewgroup的onInterceptTouchEvent 返回true,那就代表要拦截这个事件。接下来这个事件就
4 * 给viewgroup自己处理了,从而viewgroup的onTouchEvent方法就会被调用。如果如果这个viewgroup的onInterceptTouchEvent
5 * 返回false就代表我不拦截这个事件,然后就把这个事件传递给自己的子元素,然后子元素的dispatchTouchEvent
6 * 就会被调用,就是这样一个循环直到 事件被处理。
7 *
8 */
9 public boolean dispatchTouchEvent(MotionEvent ev)
10 {
11 boolean consume=false;
12 if (onInterceptTouchEvent(ev)) {
13 consume=onTouchEvent(ev);
14 }else
15 {
16 consume=child.dispatchTouchEvent(ev);
17 }
18 return consume;
19 }

10.view的onTouchEvent,OnClickListerner和OnTouchListener的onTouch方法 三者优先级如何?

答:onTouchListener优先级最高,如果onTouch方法返回 false ,那onTouchEvent就被调用了,返回true 就不会被调用。至于onClick 优先级最低。

11.点击事件的传递顺序如何?

答:Activity-Window-View。从上到下依次传递,当然了如果你最低的那个view onTouchEvent返回false 那就说明他不想处理 那就再往上抛,都不处理的话

最终就还是让Activity自己处理了。举个例子,pm下发一个任务给leader,leader自己不做 给架构师a,小a也不做 给程序员b,b如果做了那就结束了这个任务。

b如果发现自己搞不定,那就找a做,a要是也搞不定 就会不断向上发起请求,最终可能还是pm做。

 1
2 //activity的dispatchTouchEvent 方法 一开始就是交给window去处理的
3 //win的superDispatchTouchEvent 返回true 那就直接结束了 这个函数了。返回false就意味
4 //这事件没人处理,最终还是给activity的onTouchEvent 自己处理 这里的getwindow 其实就是phonewindow
5 public boolean dispatchTouchEvent(MotionEvent ev) {
6 if (ev.getAction() == MotionEvent.ACTION_DOWN) {
7 onUserInteraction();
8 }
9 if (getWindow().superDispatchTouchEvent(ev)) {
10 return true;
11 }
12 return onTouchEvent(ev);
13 }
14
15
16 //来看phonewindow的这个函数 直接把事件传递给了mDecor
17
18 @Override
19 public boolean superDispatchTouchEvent(MotionEvent event) {
20 return mDecor.superDispatchTouchEvent(event);
21 }
22
23 //devorview就是 我们的rootview了 就是那个framelayout 我们的setContentView里面传递的那个layout
24 //就是这个decorview的 子view了
25 @Override
26 public final View getDecorView() {
27 if (mDecor == null) {
28 installDecor();
29 }
30 return mDecor;
31 }

12.事件分为几个步骤?

答:down事件开头,up事件结尾,中间可能会有数目不定的move事件。

13.ViewGroup如何对点击事件分发?

答:

 1 viewgroup就是在actionMasked == MotionEvent.ACTION_DOWN 和 mFirstTouchTarget != null 这两种情况来判断是否会进入拦截事件的流程
2
3 看代码可以知道 如果是ACTION_DOWN事件 那就肯定进入 是否要拦截事件的流程
4
5 如果不是ACTION_DOWN事件 那就要看mFirstTouchTarget != null 这个条件是否成立
6
7 这个地方有点绕但是也好理解,其实就是 对于一个事件序列来说 down是事件的开头 所以肯定进入了这个事件是否拦截的流程 也就是if 括号内。
8
9
10 mFirstTouchTarget其实是一个单链表结构他指向的是 成功处理事件的子元素。
11
12 也就是说 如果有子元素成功处理了 事件,那这个值就不为NULL。反过来说
13
14 只要viewgroup拦截了事件,mFirstTouchTarget就不为NULL,所以括号内就不会执行,也就侧面说明了一个结论:
15
16 某个view 一旦决定拦截事件,那么这个事件所属的事件序列 都只能由他来执行。并且onInterceptTouchEvent 这个方法不会被调用了
17
18 final boolean intercepted;
19 if (actionMasked == MotionEvent.ACTION_DOWN
20 || mFirstTouchTarget != null) {
21 final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
22 if (!disallowIntercept) {
23 intercepted = onInterceptTouchEvent(ev);
24 ev.setAction(action); // restore action in case it was changed
25 } else {
26 intercepted = false;
27 }
28 } else {
29 // There are no touch targets and this action is not an initial down
30 // so this view group continues to intercept touches.
31 intercepted = true;
32 }

14.如果某个view 处理事件的时候 没有消耗down事件 会有什么结果?

答:假如一个view,在down事件来的时候 他的onTouchEvent返回false, 那么这个down事件 所属的事件序列 就是他后续的move 和up 都不会给他处理了,全部都给他的父view处理。

15.如果view 不消耗move或者up事件 会有什么结果?

答:那这个事件所属的事件序列就消失了,父view也不会处理的,最终都给activity 去处理了。

16.ViewGroup 默认拦截事件吗?

答:默认不拦截任何事件,onInterceptTouchEvent返回的是false。

17.一旦有事件传递给view,view的onTouchEvent一定会被调用吗?

答:是的,因为view 本身没有onInterceptTouchEvent方法,所以只要事件来到view这里 就一定会走onTouchEvent方法。

并且默认都是消耗掉,返回true的。除非这个view是不可点击的,所谓不可点击就是clickable和longgclikable同时为fale

Button的clickable就是true 但是textview是false。

18.enable是否影响view的onTouchEvent返回值?

答:不影响,只要clickable和longClickable有一个为真,那么onTouchEvent就返回true。

19.requestDisallowInterceptTouchEvent 可以在子元素中干扰父元素的事件分发吗?如果可以,是全部都可以干扰吗?

答:肯定可以,但是down事件干扰不了。

20.dispatchTouchEvent每次都会被调用吗?

答:是的,onInterceptTouchEvent则不会。

21.滑动冲突问题如何解决 思路是什么?

答。要解决滑动冲突 其实最主要的就是有一个核心思想。你到底想在一个事件序列中,让哪个view 来响应你的滑动?比如 从上到下滑,是哪个view来处理这个事件,从左到右呢?

用业务需求 来想明白以后 剩下的 其实就很好做了。核心的方法 就是2个 外部拦截也就是父亲拦截,另外就是内部拦截,也就是子view拦截法。 学会这2种 基本上所有的滑动冲突

都是这2种的变种,而且核心代码思想都一样。

外部拦截法:思路就是重写父容器的onInterceptTouchEvent即可。子元素一般不需要管。可以很容易理解,因为这和android自身的事件处理机制 逻辑是一模一样的

Android View事件机制 21问21答的更多相关文章

  1. Android View事件机制一些事

    本文主要讲述: 自己对View事件机制的一些理解 在项目中遇到的一些坑,解决方案 收集了一些View的事件机制问题 事件的分发原理图 对于一个root viewgroup来说,如果接受了一个点击事件, ...

  2. Android View 事件分发机制 源码解析 (上)

    一直想写事件分发机制的文章,不管咋样,也得自己研究下事件分发的源码,写出心得~ 首先我们先写个简单的例子来测试View的事件转发的流程~ 1.案例 为了更好的研究View的事件转发,我们自定以一个My ...

  3. android view事件分发机制

    首先我们先写个简单的例子来测试View的事件转发的流程~ 1.案例 为了更好的研究View的事件转发,我们自定以一个MyButton继承Button,然后把跟事件传播有关的方法进行复写,然后添加上日志 ...

  4. Android View 事件分发机制 源代码解析 (上)

    一直想写事件分发机制的文章,无论咋样,也得自己研究下事件分发的源代码.写出心得~ 首先我们先写个简单的样例来測试View的事件转发的流程~ 1.案例 为了更好的研究View的事件转发,我们自定以一个M ...

  5. android View事件分发机制结论

    原始博客有对源码的分析:http://blog.csdn.net/lmj623565791/article/details/39102591 结论:1.view事件的分发流程: dispatchTou ...

  6. Android View事件传递机制

    ViewGroup dispatchTouchEvent onInterceptTouchEvent onTouch View dispatchTouchEvent onTouch 假设View的层级 ...

  7. Android View事件分发-从源码分析

    View事件分发-从源码分析 学习自 <Android开发艺术探索> https://blog.csdn.net/qian520ao/article/details/78555397?lo ...

  8. 谈谈我对Android View事件分发的理解

    写这篇博客的缘由.近期因为项目中用到相似一个LinearLayout中水平布局中,有一个TextView和Button,然后对该LinearLayout布局设置点击事件.点击TextView能够触发该 ...

  9. Android View事件分发与传递

    在Android中,人们主要通过手指与系统交互.Android把所有的touch事件都被封装成MotionEvent来进行处理,其中包括了手指点击的位置,时间等信息.其事件类型主要包括:ACTION_ ...

随机推荐

  1. AFNetworking使用方法

    官网下载2.5版本:http://afnetworking.com/ 此文章是基于AFNetworking2.5版本的,需要看AFNetworking2.0版本的请看上一篇文章:AFNetworkin ...

  2. sublime text 3 如何安装 package control

    sublime text3 是个很好的编辑工具,前端程序员觉得她很好,我是在一次视频中看到她能帮助自动完成很多快捷的操作. 为什么安装? 如果想要给sublime text 中安装别的插件(这里称呼为 ...

  3. Effective Java 67 Avoid excessive synchronization

    Principle To avoid liveness and safety failures, never cede control to the client within a synchroni ...

  4. SQL 报错信息整理及解决方案(持续更新)

    整理一下自己遇见过的 SQL 各种报错信息及相应解决方法,方便以后查阅,主要平台为 Oracle: ORA-01461: 仅能绑定要插入 LONG 列的 LONG 值: 原因:插入操作时,数据大于字段 ...

  5. Android 开发之 Android 开发的起步

    前言  Android 开发的起步 我们可以先来看看百科上面怎么说? 百度百科上 Android的介绍 一.Windows环境下在线搭建Android环境. 1. 下载 Android开发工具. JD ...

  6. MyEclipse下创建的项目导入到Eclipse中详细的图文配置方法

    一.情景再现. 有些人比较喜欢用Myeclipse开发,有些人却比较喜欢用eclipse开发.但是其中有一个问题,Myeclipse里面的项目导入的时候出现了一个小小的问题. 如下: 二.说明问题 导 ...

  7. 烂泥:kickstart无人值守安装CentOS6.5

    本文由秀依林枫提供友情赞助,首发于烂泥行天下. 在本次实验进行之前,首先我们要把公司的网络环境进行介绍. 注意这个网络拓扑图,也是生产环境的一个实例.同时服务器192.168.1.214已关闭ipta ...

  8. CI 框架中的自定义路由规则

    在 CI 框架中,一个 URL 和它对应的控制器中的类以及类中的方法是一一对应的,如: www.test.com/user/info/zhaoyingnan 其中 user 对应的就是控制器中的 us ...

  9. redis 五种数据结构详解(string,list,set,zset,hash)

    redis 五种数据结构详解(string,list,set,zset,hash) Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存 ...

  10. SOS: gnuplot fdtd的一个问题求助 perl vs python

    我用perl和python写了相同功能的一段程序,计算一维fdtd,用gnuplot动态显示,可是python的数据没有显示出来,看横纵坐标的变化数据是正确收到了的,如最后的图片,求大神指点,谢谢. ...