安卓手势学习
Touch操作
touch事件
touch事件:用户的手势操作
android设备中的应用程序主要依赖于用户的各种手势操作实现交互,
常见的手势操作有:单击,长按,滑动等;
onTouchEvent()方法
在View类中定义了onTouchEvent()方法,用于处理Touch事件,View
的每个子类都可以重写该方法,以决定该View如何处理Touch事件,方法签名为:
public boolean onTouchEvent(MotionEvent event)
在Activity类中也定义了onTouchEvent()方法,则每个Activity的子孙类
都可以重写该方法,用于决定当前Activity中如何处理Touch事件,该方法签名与View类定义的
onTouchEvent()方法的签名完全相同。
View.OnTouchListener接口
在View类中定义了setOnTouchListener()方法,用于为View对象指定Touch事件处理监听器,该方法的参数类型是
View.OnTouchListener接口,借口中的抽象方法签名为:
boolean onTouch(View v,MotionEvent event);
MotionEvent类
无论View类或Activity类中定义的onTouchEvent()方法,或View类中的OnTouchListener
接口的抽象方法中,都使用了MotionEvent的对象作为参数,该类的常用方法有:
public final int getAction()
public final float getX()
public final float getX(int pointerIndex)
public final float getY()
public final float getY(int pointerIndex)
MotionEvent类中定义了一系列的常量,用于标识Touch操作的类型,亦可用于常识匹配
getAction()方法的返回值,常用的常量有:
public static final int ACTION_DOWN
public static final int ACTION_UP
public static final int ACTION_MOVE
处理Touch事件方法的返回值
无论View类或Activity类中定义的onTouchEvent()方法,或View类中的OnTouchListener接口的抽象方法,
各方法的返回值均是boolean类型。
由于同一次的某个操作可能导致多个处理Touch事件的方法被回调,当方法的返回值被指定为true时,表示当前
方法已"消费"该事件,则后续尝试处理该Touch事件的方法不会再被回调,如果返回值被指定为false时,
则后续尝试处理该Touch事件的方法会正常执行。
处理Touch的三种方法
View.onTouchEvent()
Activity.onTouchEvent()
View.setOnTouchListener()
简单的自定义View
当需要自定义View时,需要创建新的java类,继承自View或者View的子孙类。
由于View没有无参数的构造方法,则自定义View需要显式的创建带参数的构造方法:
如果希望在程序中使用new关键字创建自定义View的对象,则必须显式的创建
带1个参数的构造方法;
如果希望在res\layout\下的布局文件中使用自定义View设计布局,则必须
显式的创建带2个参数或者带3个参数的构造方法。
Touch事件的派发和处理逻辑
事件处理的矛盾
在ANDROID系统中,视图大致分为View与ViewGroup:
View是一般独立显示了具体内容的控件,例如TextView、ImageView等。
ViewGroup是用于承载其他控件的,例如RelativeLayout、ListView等。
当出现Touch事件时,需要明确是由View或是ViewGroup处理事件。
事件处理的相关方法
在android系统中,视图系统中存在3个方法处理Touch事件相关的逻辑:
public boolean dispatchTouchEvent(MotionEvent ev):处理事件分发;
public boolean onInterceptTouchEvent(MotionEvent ev):处理事件拦截;
public boolean onTouchEvent(MotionEvent ev): 处理事件响应。
由于简单的View对象不存在子级控件,所以并不存在事件拦截的操作,
即没有onInterceptTouchEvent()方法。
事件分发与处理
每个ViewGroup在接收倒事件后,默认遵循“分发->拦截->处理”的流程执行相关的方法。
在默认情况下:
事件分发:“隧道式”,即从最外层控件依次传递,直至最内层子级控件,也就是说,越靠近根节点,分发的权力越大。
事件处理:“冒泡式”,即从最内层子级控件开始处理,直至最外层的控件。
事件分发详解;
事件分发(dispatchTouchEvent)的逻辑如下:
当返回值为true时,由dispatchTouchEvent()直接消费,事件将不再传递,
即不会拦截、响应,更不会向后分发到其它控件;
当返回值为false时:
如果事件是Activity获取的,则由Activity的onTouchEvent()消费;
如果事件是父控件的,则由父控件的onTouchEvent()消费。
事件拦截详解
时间拦截(onInterceptTouchEvent)的逻辑如下:
当返回值为true时,表示当前控件拦截事件,且当前控件的onTouchEvent()
会被执行,事件并不会向后传递到其它的控件。
当返回值为false时,表示不拦截,即放行,事件将交给子级控件去分发
(即子级控件的dispatchTouchEvent()方法将被执行)。
事件响应详解
事件响应(onTouchEvent)的逻辑如下:
当返回值为true时,表示当前控件已消费事件,则整个事件处理过程结束;
当返回值为false时,表示当前控件未消费事件(可能开发人员已便携程序响应,但只要
返回值为false,就不表示消费了该事件),将由父级控件继续响应,即父级控件的onTouchEvent()
方法会被调用。
特殊的单击事件
在android系统中,关于屏幕上的操作都属于Touch操作,例如单击则是由“按下->弹起”这两种动作组合完成的。
单击事件是直接消费事件,因此,当点击界面上的Button时,一定是由Button处理事件,企鹅其父级控件无法对单击事件进行相应。
touch事件
touch事件:用户的手势操作
android设备中的应用程序主要依赖于用户的各种手势操作实现交互,
常见的手势操作有:单击,长按,滑动等;
onTouchEvent()方法
在View类中定义了onTouchEvent()方法,用于处理Touch事件,View
的每个子类都可以重写该方法,以决定该View如何处理Touch事件,方法签名为:
public boolean onTouchEvent(MotionEvent event)
在Activity类中也定义了onTouchEvent()方法,则每个Activity的子孙类
都可以重写该方法,用于决定当前Activity中如何处理Touch事件,该方法签名与View类定义的
onTouchEvent()方法的签名完全相同。
View.OnTouchListener接口
在View类中定义了setOnTouchListener()方法,用于为View对象指定Touch事件处理监听器,该方法的参数类型是
View.OnTouchListener接口,借口中的抽象方法签名为:
boolean onTouch(View v,MotionEvent event);
MotionEvent类
无论View类或Activity类中定义的onTouchEvent()方法,或View类中的OnTouchListener
接口的抽象方法中,都使用了MotionEvent的对象作为参数,该类的常用方法有:
public final int getAction()
public final float getX()
public final float getX(int pointerIndex)
public final float getY()
public final float getY(int pointerIndex)
MotionEvent类中定义了一系列的常量,用于标识Touch操作的类型,亦可用于常识匹配
getAction()方法的返回值,常用的常量有:
public static final int ACTION_DOWN
public static final int ACTION_UP
public static final int ACTION_MOVE
处理Touch事件方法的返回值
无论View类或Activity类中定义的onTouchEvent()方法,或View类中的OnTouchListener接口的抽象方法,
各方法的返回值均是boolean类型。
由于同一次的某个操作可能导致多个处理Touch事件的方法被回调,当方法的返回值被指定为true时,表示当前
方法已"消费"该事件,则后续尝试处理该Touch事件的方法不会再被回调,如果返回值被指定为false时,
则后续尝试处理该Touch事件的方法会正常执行。
处理Touch的三种方法
View.onTouchEvent()
Activity.onTouchEvent()
View.setOnTouchListener()
简单的自定义View
当需要自定义View时,需要创建新的java类,继承自View或者View的子孙类。
由于View没有无参数的构造方法,则自定义View需要显式的创建带参数的构造方法:
如果希望在程序中使用new关键字创建自定义View的对象,则必须显式的创建
带1个参数的构造方法;
如果希望在res\layout\下的布局文件中使用自定义View设计布局,则必须
显式的创建带2个参数或者带3个参数的构造方法。
Touch事件的派发和处理逻辑
事件处理的矛盾
在ANDROID系统中,视图大致分为View与ViewGroup:
View是一般独立显示了具体内容的控件,例如TextView、ImageView等。
ViewGroup是用于承载其他控件的,例如RelativeLayout、ListView等。
当出现Touch事件时,需要明确是由View或是ViewGroup处理事件。
事件处理的相关方法
在android系统中,视图系统中存在3个方法处理Touch事件相关的逻辑:
public boolean dispatchTouchEvent(MotionEvent ev):处理事件分发;
public boolean onInterceptTouchEvent(MotionEvent ev):处理事件拦截;
public boolean onTouchEvent(MotionEvent ev): 处理事件响应。
由于简单的View对象不存在子级控件,所以并不存在事件拦截的操作,
即没有onInterceptTouchEvent()方法。
事件分发与处理
每个ViewGroup在接收倒事件后,默认遵循“分发->拦截->处理”的流程执行相关的方法。
在默认情况下:
事件分发:“隧道式”,即从最外层控件依次传递,直至最内层子级控件,也就是说,越靠近根节点,分发的权力越大。
事件处理:“冒泡式”,即从最内层子级控件开始处理,直至最外层的控件。
事件分发详解;
事件分发(dispatchTouchEvent)的逻辑如下:
当返回值为true时,由dispatchTouchEvent()直接消费,事件将不再传递,
即不会拦截、响应,更不会向后分发到其它控件;
当返回值为false时:
如果事件是Activity获取的,则由Activity的onTouchEvent()消费;
如果事件是父控件的,则由父控件的onTouchEvent()消费。
事件拦截详解
时间拦截(onInterceptTouchEvent)的逻辑如下:
当返回值为true时,表示当前控件拦截事件,且当前控件的onTouchEvent()
会被执行,事件并不会向后传递到其它的控件。
当返回值为false时,表示不拦截,即放行,事件将交给子级控件去分发
(即子级控件的dispatchTouchEvent()方法将被执行)。
事件响应详解
事件响应(onTouchEvent)的逻辑如下:
当返回值为true时,表示当前控件已消费事件,则整个事件处理过程结束;
当返回值为false时,表示当前控件未消费事件(可能开发人员已便携程序响应,但只要
返回值为false,就不表示消费了该事件),将由父级控件继续响应,即父级控件的onTouchEvent()
方法会被调用。
特殊的单击事件
在android系统中,关于屏幕上的操作都属于Touch操作,例如单击则是由“按下->弹起”这两种动作组合完成的。
单击事件是直接消费事件,因此,当点击界面上的Button时,一定是由Button处理事件,企鹅其父级控件无法对单击事件进行相应。
手势实现的图库部分代码
package com.edu.cn.image;
import java.util.ArrayList;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.view.animation.AnimationUtils;
import android.widget.ImageSwitcher;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
import android.widget.ViewSwitcher;
import android.widget.ViewSwitcher.ViewFactory;
public class DisplayActivity extends Activity implements ViewFactory {
private ArrayList<Integer> data;
private int position;
private ImageSwitcher imageswitcher;
ViewSwitcher v;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_display);
Intent intent = getIntent();
data = intent.getIntegerArrayListExtra("data");
position = intent.getIntExtra("position", 0);
imageswitcher = (ImageSwitcher) findViewById(R.id.imageSwitcher2);
imageswitcher.setFactory(this);
}
private float actionDownX;
@Override
public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
actionDownX = event.getX();
break;
case MotionEvent.ACTION_UP:
if(event.getX() - actionDownX > 20){
doShowPrevious();
}
if(actionDownX - event.getX() > 20){
doShowNext();
}
break;
}
return super.onTouchEvent(event);
}
private void doShowPrevious(){
position--;
if(position < 0){
position = data.size() - 1;
}
imageswitcher.setInAnimation(AnimationUtils.loadAnimation(this, R.anim.left_to_right));
imageswitcher.setInAnimation(AnimationUtils.loadAnimation(this, R.anim.left_out_right));
imageswitcher.setImageResource(data.get(position));
}
private void doShowNext(){
position++;
if(position >= data.size()){
position = 0;
}
imageswitcher.setInAnimation(AnimationUtils.loadAnimation(this, R.anim.right_to_left));
imageswitcher.setInAnimation(AnimationUtils.loadAnimation(this, R.anim.right_out_left));
imageswitcher.setImageResource(data.get(position));
}
@Override
public View makeView() {
// TODO Auto-generated method stub
ImageView view = new ImageView(this);
view.setLayoutParams(new ImageSwitcher.LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));
view.setScaleType(ScaleType.FIT_CENTER);
view.setImageResource(data.get(position));
return view;
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理