ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

一文学懂 Android View

2022-06-30 13:34:28  阅读:197  来源: 互联网

标签:MotionEvent event onTouchEvent 文学 事件 Android public View



前言

View是所有可视化空间的父类,系统提供了很多基础控件,比如Button,TextView等,但是仅仅使用他们是完全不能满足需求的,因此我们就需要自定义控件,而自定义控件,就需要对Android的View体系有充分的了解。有一个经典场景就是屏幕的滑动,当处于不同层级的View都响应用户滑动,就会导致滑动冲突。为了正常的响应滑动事件,我们就要对View的事件分发机制有充分的了解。

View基础知识

我们先从实践出发,了解View的一些功能。再深入去了解他在复杂场景的下的使用方法。

View的子类

View是Android中所有控件的父类,除了View以外,还有一个View的子类叫做ViewGroup,从名字上看,表示控件组,这意味着View不单单指一个,他也可以是一组控件。

所以Button是一个View,不是ViewGroup,而LinearLayout既是View又是ViewGroup。并且ViewGroup的内部,既可以有View,也可以有ViewGroup。

View的位置

View的位置由四个顶点决定,分别是bottom,top,left,right。这些坐标都是相对于View的父容器而言,因此它是相对坐标。

我们可以使用getLeft(),getRight(),getTop(),getBottom()来获得View的位置。

Android3额外增加了几个参数:x、y、translationX、translationY。换算关系为 x = left + translationX。(需要实践)

View 在平移的过程中,top 和 left 表示的是原始左上角的位置信息,其值并不会发生改变,此时发生改变的是x、y、translationX和 translationY这四个参数。

View的触碰事件

1、MotionEvent

ACTION_DOWN--手指刚解除屏幕

ACTION_MOVE--手指在屏幕上移动

ACTIONUP -- 手指松开一瞬间

一般有手机点击和手机滑动松开的两种情况。对应的为down-up , down-move-up。

视图类中重写onTouchEvent方法

查看代码
@Override
	public boolean onTouchEvent(MotionEvent event) {
		Log.d("Action",""+event.getAction());
		float x = event.getX();//带event才是触摸点坐标,不带为view坐标,并且X是相对view的坐标,view的左上角为0,0。只有rawX才是整个屏幕的
		float y = event.getY();
		Log.d("public button",x+" "+y);
		return true;
	}

2、 TouchSlop

TouchSlop是系统所能识别为滑动的最小距离,不同设备不同。是一个常量

ViewConfiguration.get(getContextO).getScaledTouchSlop()

3、VelocityTracker

速度追踪,能够识别在一段时间内,手指滑动的速度

视图类中重写onTouchEvent方法

查看代码
@Override
public boolean onTouchEvent(MotionEvent event) {
   VelocityTracker velocityTracker= VelocityTracker.obtain();
   velocityTracker.addMovement (event);
   velocityTracker.computeCurrentVelocity (1000);
   int xVelocity =(int) velocityTracker.getXVelocity();
   int yVelocity =(int) velocityTracker.getYVelocity();
   Log.d("speed",xVelocity+" "+yVelocity);
   return true;
}

4、GestureDetector

手势检测。可以检测长按,轻触,单击,双击等行为。需要先创建一个监听器对象GestureDetector.OnGestureListener,然后创建GestureDetector时传入监听器,再为视图设置TouchEvent监听器,在onTouch事件中使用GestureDetector接管即可

实例
GestureDetector.OnGestureListener listener = new GestureDetector.OnGestureListener() {
   @Override
   public boolean onDown(MotionEvent e) {
      Log.d("down","down");
      return false;
   }

   @Override
   public void onShowPress(MotionEvent e) {

   }

   @Override
   public boolean onSingleTapUp(MotionEvent e) {
      return false;
   }

   @Override
   public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
      return false;
   }

   @Override
   public void onLongPress(MotionEvent e) {

   }

   @Override
   public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
      return false;
   }
};
LinearLayout ll = findViewById(R.id.MA_ll);
GestureDetector gestureDetector= new GestureDetector(this,listener);
ll.setOnTouchListener(new View.OnTouchListener() {
   @Override
   public boolean onTouch(View v, MotionEvent event) {
      return gestureDetector.onTouchEvent(event);
   }
});

5、Scroller

弹性滑动,实现组件的缓慢移动

View的滑动

视图手指滑动

查看代码

@Override
	public boolean onTouchEvent(MotionEvent event) {
		//每次回调onTouchEvent的时候,我们获取触摸点的代码
		int x = (int) event.getX();
		int y = (int) event.getY();
		switch (event.getAction()) {
			case MotionEvent.ACTION_DOWN:
				// 记录触摸点坐标
				lastX = x;
				lastY = y;
				break;
			case MotionEvent.ACTION_MOVE:
				// 计算偏移量
				int offsetX = x - lastX;
				int offsetY = y - lastY;
				// 在当前left、top、right、bottom的基础上加上偏移量
				layout(getLeft() + offsetX,
						getTop() + offsetY,
						getRight() + offsetX,
						getBottom() + offsetY);
				break;
		}
		return true;
	}

Scroll滑动

被谁捕获就移动谁

查看代码

	public PublicButton1(Context context, AttributeSet attrs) {
		super(context, attrs);
		LayoutInflater.from(context).inflate(R.layout.button1,this);//加载某个布局,并为他添加父布局
		Button qwq = findViewById(R.id.publicButton);
		LinearLayout linearLayout = findViewById(R.id.linearlayout);
		linearLayout.setBackgroundColor(getResources().getColor(R.color.design_default_color_secondary));
		qwq.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				scrollBy(-10,-10);
			}
		});
		scrollBy(-100,-100);
	}

动画滑动

待定

弹性滑动

Scroller实现,需要重写computeScroll方法

查看代码

	private void smoothScrollTo(int destX,int destY) {
		int scrollX = getScrollX();
		int deltaX = destX - scrollX;
		scroller.startScroll(scrollX, 0, deltaX, 0, 1000);
		invalidate();
	}

	@Override
	public void computeScroll() {
		if(scroller.computeScrollOffset())
		{
			scrollTo(scroller.getCurrX(),scroller.getCurrY());
			postInvalidate();
		}
	}

View的事件分发机制

点击事件的传递规则

分析的对象是MotionEvent,所谓对点击事件的分发,就是对MotionEvent的分发,系统需要把这个事件发给具体的一个View。

分发过程由三个方法共同完成:dispatchTouchEvent、onlnterceptTouchEvent和 onTouchEvent

public boolean dispatchTouchEvent(MotionEvent ev)

用来进行事件的分发。如果事件能够传递给当前View,那么此方法一定会被调用,返回结果受当前View 的 onTouchEvent 和下级 View 的 dispatchTouchEvent 方法的影响,表示是否消耗当前事件。

public boolean onInterceptTouchEvent(MotionEvent event)

在上述方法内部调用,用来判断是否拦截某个事件,如果当前View拦截了某个事件,那么在同一个事件序列当中,此方法不会被再次调用,返回结果表示是否拦截当前事件。

public boolean onTouchEvent(MotionEvent event)

在 dispatchTouchEvent 方法中调用,用来处理点击事件,返回结果表示是否消耗当前事件,如果不消耗,则在同一个事件序列中,当前View 无法再次接收到事件。

他们的关系可以用以下伪代码表示

查看代码
public boolean dispatchTouchEvent(MotionEvent ev) {
		boolean consume = false;
		if (onInterceptTouchEvent(ev)) {
			consume = onTouchEvent(ev);
		} else {
			consume = child.dispatchTouchEvent(ev);
		}
		return consume;
	}

 对于一个根ViewGroup来说,点击事件产生后,首先会传递给它,这时它的 dispatchTouchEvent就会被调用,

如果这个ViewGroup 的 onInterceptTouchEvent方法返回 true 就表示它要拦截当前事件,接着事件就会交给这个ViewGroup处理,即它的onTouchEvent方法就会被调用;

如果这个ViewGroup 的onInterceptTouchEvent方法返回 false就表示它不拦截当前事件,这时当前事件就会继续传递给它的子元素,

接着子元素的dispatchTouchEvent 方法就会被调用,如此反复直到事件被最终处理。

当一个View 需要处理事件时,

如果它设置了 OnTouchListener,那么OnTouchListener中的 onTouch方法会被回调。

这时事件如何处理还要看 onTouch 的返回值,

如果返回 false,则当前View的 onTouchEvent 方法会被调用;

如果返回 true,那么 onTouchEvent 方法将不会被调用。

可以把OnTouchListener理解为外部监听器,而onTouchEvent理解为内部监听器。onTouchListener在外部用set绑定,而onTouchEvent是重写组件方法实现的。

在 onTouchEvent 方法中,如果当前设置的有OnClickListener,那么它的 onClick 方法会被调用。可以看出,平时我们常用的 OnClickListener,其优先级最低,即处于事件传递的尾端。

当一个点击事件产生后,它的传递过程遵循如下顺序∶Activity->Window->View,顶级 View 接收到事件后,就会按照事件分发机制去分发事件。

从上到下(点击事件),再从下到上(onTouchEvent)

标签:MotionEvent,event,onTouchEvent,文学,事件,Android,public,View
来源: https://www.cnblogs.com/MiraculousB/p/16425373.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有