為什么需要要學(xué)習(xí)View事件?
- 實現(xiàn)涉及滑動的需求
- 滑動沖突
本文從以幾個方面講View事件
View的位置參數(shù)
一 View的位置參數(shù)
View的位置由它的四個頂點決定圈盔,View當(dāng)中有四個屬性與之對應(yīng)top蔓姚、left卓囚、buttom簿盅、right.這四個參數(shù)事相對于父容器的位置轧拄。
在代碼中如何獲取這四個位置呢揽祥?
private void initView(Context context) {
//left左上角橫坐標(biāo)
int left = getLeft();
//右下角橫坐標(biāo)
int right = getRight();
//左上角縱坐標(biāo)
int top=getTop();
//右下角縱坐標(biāo)
int button=getBottom();
}
Android 3.0 增加了 x、y檩电、translationX拄丰、translationY.
看看代碼中是如何獲取的
private void intActionTwo() {
//左上角橫坐標(biāo)
float x=getX();
//左上角縱坐標(biāo)
float y=getY();
//左上角相對于父容器橫向偏移量
float translationX=getTranslationX();
//左上角相對于父容器縱向偏移量
float translationY=getTranslationY();
}
注意:
1.translationY府树、translation默認(rèn)值是0
2.換算關(guān)系
x=left+translationX;
y=top+translationY;
二 View的事件分法機制
在講事件的分發(fā)機制之前,先來看看MotionEvent料按、TouchSlop奄侠、VelocityTracker、GestDetector
MotionEvent
觸摸事件對應(yīng)MotionEvent類载矿,指手指觸摸屏幕產(chǎn)生的一系列事件垄潮,常用的有以下幾種:
ActionDown:手指按下的操作,代表觸摸的開始
ActionMove:手指移動超過一定的值會觸發(fā)這個動作
ActionUp:手指離開屏幕的操作闷盔,代表觸摸的結(jié)束
TouchSlop
在滑動的過程中如果小于一定的值弯洗,它就不認(rèn)為是滑動。
這個值用來干么的呢逢勾?
防止誤滑動
注意:這個值不是固定的牡整,不同機型這個值是不同的。
這個值獲取方式:
int touchSlop = ViewConfiguration.get(this).getScaledTouchSlop();
Log.e("=======","getScaledTouchSlop:"+touchSlop);
我的手機打印結(jié)果是24
05-26 13:40:16.665 3071-3071/com.myanimation.chen.myviewdemo E/=======: getScaledTouchSlop:24
VelocityTracker
速度追蹤溺拱,追蹤手指在水平或垂直方向上滑動的速度果正。
使用方法
@Override
public boolean onTouchEvent(MotionEvent event) {
VelocityTracker velocityTracker = VelocityTracker.obtain();
velocityTracker.addMovement(event);
velocityTracker.computeCurrentVelocity(1000);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_MOVE:
int xVeloctiyTracker = (int) velocityTracker.getXVelocity();
int yVelocityTracker = (int) velocityTracker.getYVelocity();
Log.e("========vx","xVeloctiyTracker:"+xVeloctiyTracker);
Log.e("========vy","yVelocityTracker:"+yVelocityTracker);
break;
case MotionEvent.ACTION_UP:
break;
default:
break;
}
return super.onTouchEvent(event);
}
第一步 實例化對象,創(chuàng)建VelocityTracker對象
第二步 調(diào)用computCurrentVelocity() 方法計算速度
第三步 獲取水平或垂直方向上的速度
注意:不使用時要回收它
velocityTracker.clear();
velocityTracker.recycle();
GestDetector
手勢檢測盟迟,常用的手勢檢測有:
onSingleTapUp(單擊)
onFling(塊速滑動)
onScroll(拖動)
onLongPress(長按)
onDoubleTap(雙擊)
使用方法:
第一步 實例化對象GestDetector
第二步 解決長按屏幕無法拖動的現(xiàn)象
第三步 接管onTouchEvent()方法
看看Demo
package com.myanimation.chen.myviewdemo;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
public class MainAty extends AppCompatActivity implements GestureDetector.OnGestureListener {
private String state = "MainAty";
private GestureDetector mGestureDetector;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.aty_main);
mGestureDetector=new GestureDetector(this);
//解決長按屏幕無法拖動的現(xiàn)象
mGestureDetector.setIsLongpressEnabled(false);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
boolean consume=mGestureDetector.onTouchEvent(event);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
break;
default:
break;
}
return consume;
}
@Override
public boolean onDown(MotionEvent e) {
Log.e("==========a1","onDown");
return false;
}
@Override
public void onShowPress(MotionEvent e) {
Log.e("==========a2","onShowPress");
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
Log.e("==========a3","onSingleTapUp");
return false;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
Log.e("==========a4","onScroll");
return false;
}
@Override
public void onLongPress(MotionEvent e) {
Log.e("==========a5","onLongPress");
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
Log.e("==========a6","onFling");
return false;
}
}
點擊事件的分發(fā)規(guī)則由三個方法組成
- onTouchEvent
- dispatchTouchEvent
- onInterceptTouchEvent
public boolean dispatchTouchEvent(MotionEvent ev)
用來進(jìn)行事件分發(fā)秋泳,如果事件能夠傳遞給當(dāng)前的View,此方法一定會運行,下層的dispatchTouchEvent和本層的onTouchEvent受此方法的影響攒菠。
返回true表示當(dāng)前層級消費事件迫皱,false或super.dispatchTouchEvent繼續(xù)往下分發(fā)。
public boolean onInterceptTouchEvent(MotionEvent ev)
用來進(jìn)行事件的攔截辖众,返回true表示攔截事件卓起,false或super.dispatchTouchEveent不攔截繼續(xù)往下分發(fā)。
追蹤手機水平或垂直方向上的速度
public boolean onTouchEvent(MotionEvent e)
消費事件凹炸,返true表示當(dāng)前層級可以消費事件戏阅,不需要往上傳遞。
Android中擁有事件傳遞能力的組件有三種:
Activity:擁有dispatchTouchEvent啤它、onTouchEvent
ViewGroup:擁有dispatchTouchEvent奕筐、onInterceptTouchEvent、onTouchEvent
View:擁有dispatchTouchEvent变骡、onTouchEvent
三.View的滑動沖突
界面中內(nèi)外兩層同時滑動就會產(chǎn)生滑動沖突
常見常景
常見的滑動沖突可以分為三種
- 外部滑動方向和內(nèi)部滑動方向不一致
- 外部滑動方向和內(nèi)部滑動方向一致
- 上面兩種情況的嵌套
處理規(guī)則
- 外部滑動方向和內(nèi)部滑動方向不一致
當(dāng)用戶左右滑動時离赫,需要讓內(nèi)部的View攔截點擊事件,當(dāng)用戶上下滑動時塌碌,需要讓內(nèi)部的View攔截點擊事件渊胸。 - 外部滑動方向和內(nèi)部滑動方向一致
在這種情況下就要根據(jù)業(yè)務(wù)來做處理了,滑動到某個地方時台妆,外部View滑動翎猛,某個地方時內(nèi)部View滑動 - 上面兩種情況的嵌套
這種情況相對于前面兩種情況要復(fù)雜一點胖翰,這個時候就要把它分解開來,根據(jù)業(yè)務(wù)來做處理