安卓基础学习 Day18|按键事件+手势操作(图片的放大、缩小、切换)

目录

一、按键事件的概念

二、案例演示

1.提出要求

 2.主布局资源文件

3.主界面

一、触摸事件的概述

触摸分类

触摸动作

触摸监听器

触摸方法

触点个数与坐标

二、单点触摸

案例:移动米老鼠

提出要求

 主布局资源文件

主界面

 三、多点缩放

案例:缩放米老鼠

提出要求

  主布局资源文件

主界面

四、手势切换照片 

1.手势操作原理

2.安卓手势类与接口

MotionEvent

GestureDetector

OnGestureListener

3.案例操作

1.提出要求

2. 下载喜欢的图片并存放在res/mipmap中

3.主布局资源文件

 4.主界面

一、按键事件的概念

按键事件:用户按下或者释放手机键盘上的某个界面时产生的事件

监听器是:View.OnKeyListener

事件处理方法是:onKey()

二、案例演示

1.提出要求

通过按上、下、左、右方向键来移动米老鼠。

 2.主布局资源文件

将布局设置为线性布局,并在里面插入一张图片

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/root"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <ImageView
        android:id="@+id/iv_mickey"
        android:layout_width="100dp"
        android:layout_height="130dp"
        android:src="@mipmap/mickey"
        android:scaleType="fitXY" />

</LinearLayout>

效果

3.主界面

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {
    //声明变量
    protected static final int STEP = 10;
    private ImageView ivMickey;
    private LinearLayout root;
    private LinearLayout.LayoutParams layoutParams;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //利用布局资源文件设置用户界面
        setContentView(R.layout.activity_main);
        //通过资源索引获取控件实例
        ivMickey = findViewById(R.id.iv_mickey);
        root = findViewById(R.id.root);

        //设置根布局可以获取焦点
        root.setFocusable(true);
        //让根布局获取焦点
        root.requestFocus();

        //获取图像控件的布局参数
        layoutParams = (LinearLayout.LayoutParams) ivMickey.getLayoutParams();

        //给根布局注册监听器
        root.setOnKeyListener(new View.OnKeyListener() {
            @Override
            public boolean onKey(View v, int keyCode, KeyEvent event) {
                switch (keyCode) {
                    //根据按键修改图像控件的布局参数
                    case KeyEvent.KEYCODE_DPAD_UP://按上方按键
                        //上边界碰撞检测
                        if (ivMickey.getTop() >= 10) {
                            layoutParams.topMargin = layoutParams.topMargin - STEP;
                        } else {
                            Toast.makeText(MainActivity.this, "碰到上边界", Toast.LENGTH_SHORT).show();
                        }
                        break;
                    case KeyEvent.KEYCODE_DPAD_DOWN://按下方按键
                        layoutParams.topMargin = layoutParams.topMargin + STEP;
                        break;
                    case KeyEvent.KEYCODE_DPAD_LEFT://按左方按键
                        layoutParams.leftMargin = layoutParams.leftMargin - STEP;
                        break;
                    case KeyEvent.KEYCODE_DPAD_RIGHT://按右方按键
                        layoutParams.leftMargin = layoutParams.leftMargin + STEP;
                        break;
                }
                //重新获取图像控件的布局参数
                ivMickey.setLayoutParams(layoutParams);

                return false;
            }
        });
    }
}

效果展示:

这里只有上边缘的碰撞检测,现在对剩下的三边添加代码进行碰撞检测

switch (keyCode) {
                    //根据按键修改图像控件的布局参数
                    case KeyEvent.KEYCODE_DPAD_UP://按上方按键
                        //上边界碰撞检测
                        if (ivMickey.getTop() >= 10) {
                            layoutParams.topMargin = layoutParams.topMargin - STEP;
                        } else {
                            Toast.makeText(MainActivity.this, "碰到上边界", Toast.LENGTH_SHORT).show();
                        }
                        break;
                    case KeyEvent.KEYCODE_DPAD_DOWN://按下方按键
                        //下边界碰撞检测
                        if (ivMickey.getBottom() <= 1800) {
                            layoutParams.topMargin = layoutParams.topMargin + STEP;
                        } else {
                            Toast.makeText(MainActivity.this, "碰到下边界", Toast.LENGTH_SHORT).show();
                        }
                        break;
                    case KeyEvent.KEYCODE_DPAD_LEFT://按左方按键
                        //左边界碰撞检测
                        if (ivMickey.getLeft() >= 0) {
                            layoutParams.leftMargin = layoutParams.leftMargin - STEP;
                        } else {
                            Toast.makeText(MainActivity.this, "碰到左边界", Toast.LENGTH_SHORT).show();
                        }
                        break;
                    case KeyEvent.KEYCODE_DPAD_RIGHT://按右方按键
                        //右边界碰撞检测
                        if (ivMickey.getRight() <= 1100) {
                            layoutParams.leftMargin = layoutParams.leftMargin + STEP;
                        } else {
                            Toast.makeText(MainActivity.this, "碰到右边界", Toast.LENGTH_SHORT).show();
                        }
                        break;
                }

 效果展示:

到边缘会停止,但是由于吐司的时间导致显示的比较慢 

一、触摸事件的概述

按键事件:用户触摸手机屏幕的某个界面时产生的事件

触摸分类

1.单点触摸(滑动)

2.多点触摸(放大、缩小)

触摸动作

1.按下(MotionEvent.ACTION_DOWN)

2.移动(MotionEvent.ACTION_MOVE)

3.松开(MotionEvent.ACTION_UP)

触摸监听器

onTouchListener

触摸方法

onTouch() 方法里,我们可以根据不同动作编写不同事件处理代码。

触点个数与坐标

单点触摸,通过MotionEvent对象getX()getY()方法可以获得触摸点的坐标。

多点触摸,通过getPointerCount()获取触点个数,然后通过getX(pointerIndex)getY(pointerIndex)获得某个触点的坐标。

二、单点触摸

案例:移动米老鼠

提出要求

在这里插入图片描述

 主布局资源文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/root"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <ImageView
        android:id="@+id/ivmickey"
        android:layout_width="100dp"
        android:layout_height="130dp"
        android:scaleType="fitXY"
        android:src="@mipmap/mickey" />

</LinearLayout>

主界面

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;

public class MainActivity extends AppCompatActivity {
    //声明变量
    protected static final String TAG = "move_mickey_by_touch";
    private ImageView ivMickey;
    private LinearLayout root;
    private LinearLayout.LayoutParams layoutParams;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //利用布局资源文件设置用户界面
        setContentView(R.layout.activity_main);
        //通过资源索引获取控件实例
        ivMickey = findViewById(R.id.ivmickey);
        root = findViewById(R.id.root);

        //设置根布局可以获取焦点
        root.setFocusable(true);
        //让根布局获取焦点
        root.requestFocus();

        //获取图像控件的布局参数
        layoutParams = (LinearLayout.LayoutParams) ivMickey.getLayoutParams();

        //给根布局注册触摸监听器,实现触摸监听器接口,编写触摸事件代码
        root.setOnTouchListener(new View.OnTouchListener() {

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                //根据触摸执行不同的操作
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN: // 触点按下
                        Log.d(TAG, "ACTION_DOWN(" + event.getX() + "," + event.getY() + ")");
                        break;
                    case MotionEvent.ACTION_MOVE: //触点移动
                        Log.d(TAG, "ACTION_MOVE(" + event.getX() + "," + event.getY() + ")");
                        break;
                    case MotionEvent.ACTION_UP: // 触点拿开
                        Log.d(TAG, "ACTION_UP(" + event.getX() + "," + event.getY() + ")");
                        break;
                }
                // 根据变化的触点坐标来更新图像控件的布局参数
                layoutParams.leftMargin = (int) event.getX();
                layoutParams.topMargin = (int) event.getY();

                //重新设置图像控件的布局参数
                ivMickey.setLayoutParams(layoutParams);

                return true; // 只有设置为真,按下、移动、松开才会依次执行
            }
        });
    }
}

 打印显示

效果展示

将触点定位在米老鼠的中心

 三、多点缩放

案例:缩放米老鼠

提出要求

  主布局资源文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/root"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <ImageView
        android:id="@+id/ivmickey"
        android:layout_width="100dp"
        android:layout_height="130dp"
        android:scaleType="fitXY"
        android:src="@mipmap/mickey" />

</LinearLayout>

主界面

【首先判断是一个触点还是两个触点,获取到两个触点的坐标,利用两坐标的距离的变化,来判断用户想进行的操作是放大还是缩小,获取到一个触点就跟随用户移动】

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;

import java.lang.annotation.ElementType;

public class MainActivity extends AppCompatActivity {
    private ImageView ivMickey; // 米老鼠图像控件
    private LinearLayout root; // 线性根布局
    private LinearLayout.LayoutParams layoutParams; //线性布局布局参数
    private float x1, y1; // 第一个触点的坐标
    private float x2, y2; // 第一个触点的坐标
    private float next_x1, next_y1; // 第一个触点下次的坐标
    private float next_x2, next_y2; // 第一个触点下次的坐标
    private float distance; //两个触点之间的距离
    private float next_distance; //下一次两个触点之间的距离

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //利用布局资源文件设置用户界面
        setContentView(R.layout.activity_main);

        //通过资源索引获取控件实例
        ivMickey = findViewById(R.id.ivmickey);
        root = findViewById(R.id.root);

        //设置根布局可以获取焦点
        root.setFocusable(true);
        //让根布局获取焦点
        root.requestFocus();

        //获取图像控件的布局参数
        layoutParams = (LinearLayout.LayoutParams) ivMickey.getLayoutParams();

        //给根布局注册触摸监听器
        root.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent event) {
                //根据触点个数执行不同的操作(两个触点缩放图像,单个触点移动图像)
                if (event.getPointerCount() == 2) {//两点触摸
                    //根据触摸动作执行不同的动作
                    switch (event.getAction()) {
                        case MotionEvent.ACTION_DOWN:
                            //获取第一个触点的坐标
                            x1 = event.getX(0);
                            y1 = event.getY(0);
                            //获取第二个触点的坐标
                            x2 = event.getX(1);
                            y2 = event.getY(1);

                            //计算两点之间的距离
                            distance = (float) Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
                            break;
                        case MotionEvent.ACTION_MOVE: // 触点移动
                            //获取第一个触点的坐标
                            next_x1 = event.getX(0);
                            next_y1 = event.getY(0);
                            //获取第二个触点的坐标
                            next_x2 = event.getX(1);
                            next_y2 = event.getY(1);

                            //计算两点之间的距离
                            next_distance = (float) Math.sqrt(Math.pow(next_x2 - next_x1, 2) + Math.pow(next_y2 - next_y1, 2));
                            break;
                        case MotionEvent.ACTION_UP: // 触点松开
                            break;
                    }
                    //修改图像控件的布局参数
                    if (next_distance > distance) {
                        layoutParams.width = (int) (layoutParams.width * 1.05);
                        layoutParams.height = (int) (layoutParams.height * 1.05);
                    } else {
                        layoutParams.width = (int) (layoutParams.width * 0.95);
                        layoutParams.height = (int) (layoutParams.height * 0.95);
                    }
                    //坐标迭代
                    x1 = next_x1;
                    y1 = next_y1;
                    x2 = next_x2;
                    y2 = next_y2;

                    //两点之间的距离
                    distance = distance = (float) Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
                } else if (event.getPointerCount() == 1) {//单点触摸
                    if (event.getAction() == MotionEvent.ACTION_MOVE) {
                        //修改图像控件的布局参数(因为线性布局中的gravity设置的为center,所以要减去屏幕的一半尺寸)
                        layoutParams.leftMargin = (int) (event.getX() - getWindowManager().getDefaultDisplay().getWidth() / 2);
                        layoutParams.topMargin = (int) (event.getX() - getWindowManager().getDefaultDisplay().getWidth() / 2);
                    }
                }

                //重新设置图像控件的布局参数
                ivMickey.setX(event.getX() - ivMickey.getWidth()/2);
                ivMickey.setY(event.getY() - ivMickey.getHeight()/2);
                ivMickey.setLayoutParams(layoutParams);
                return true; // 只有设置为真,按下、移动、松开才会依次执行
            }
        });
    }
}

结果展示:(我这里电脑无法完成两点触摸,于是我将程序在手机上运行便出现了下面的效果) 

四、手势切换照片 

1.手势操作原理

在安卓系统中,每一次的手势交互都会依照以下执行顺序执行

(1)触屏的一刹那,触发一个MotionEvent事件

(2)该事件被OnTouchListener监听,在其onTouch()方法里获得该MotionEvent对象。

(3)通过GestureDetector(手势侦测器)将此MotionEvent对象移交给OnGestureListener

(4)OnGestureListener监听器获得该事件对象,然后根据该对象封装的信息,做出合适的处理。

上面这四个步骤的顺序,可以说是手势操作的原理

2.安卓手势类与接口

MotionEvent

动作事件类,用于封装手势、触摸笔、轨迹球等等的动作事件。其内部封装了两个重要的属性X和Y,这两个属性分别用于记录横轴和纵轴的坐标。

GestureDetector

手势侦测器,用于识别各种手势。

OnGestureListener

手势监听器,是一个手势交互的监听接口,其中提供了多个抽象方法,并根据GestureDetector的手势识别结果调用相对应的方法。

3.案例操作

1.提出要求

利用手势切换图片

 

2. 下载喜欢的图片并存放在res/mipmap中

3.主布局资源文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/root"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@mipmap/img1"
    android:orientation="vertical"
    tools:context=".MainActivity">
</LinearLayout>

 4.主界面

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.widget.LinearLayout;

public class MainActivity extends AppCompatActivity {
    //声明变量
    private GestureDetector detector;//手势侦测器
    private int[] imgIds;//图像资源标识符数组
    private int imgIndex;//图像索引,反映在图像资源标识符数组中的位置
    private LinearLayout root;//根线性布局
    private final static int IMG_COUNT = 13;//图片总数
    private final static String TAG = "switchimagebyguesture";//定义程序标记

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //利用布局资源文件设置用户界面
        setContentView(R.layout.activity_main);

        //通过资源标识符获取控件实例
        root = findViewById(R.id.root);

        //初始化图像标识数组
        imgIds = new int[IMG_COUNT];
        for (int i = 0; i < IMG_COUNT; i++) {
            imgIds[i] = getResources().getIdentifier(
                    "img" + (i + 1),//标识符名称
                    "mipmap",//定义图片类型
                    "net.lzt.switchimagebyguesture"//定义包名
            );
        }
        //实例化手势检测器(参数1:上下文 ,参数2:手势监听器对象)
        detector = new GestureDetector(new GestureDetector.OnGestureListener() {
            @Override
            public boolean onDown(MotionEvent e) {
                Log.i(TAG, "onDown");
                return false;
            }

            @Override
            public void onShowPress(MotionEvent e) {
                Log.i(TAG, "onShowPress");
            }

            @Override
            public boolean onSingleTapUp(MotionEvent e) {
                Log.i(TAG, "onSingleTapUp");
                return false;
            }

            @Override
            public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
                Log.i(TAG, "onScroll");
                return false;
            }

            @Override
            public void onLongPress(MotionEvent E) {
                Log.i(TAG, "onLongPress");
            }

            @Override
            public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
                Log.i(TAG, "onFling");
                //手势向左滑动20个像素,图像切换到下一张
                if (e2.getX() < e1.getX() - 5) {
                    if (imgIndex < IMG_COUNT - 1) {
                        imgIndex++;
                    } else {
                        imgIndex = 0;
                    }
                }

                //手势向右滑动20个像素,图像切换到上一张
                if (e2.getX() > e1.getX() + 5) {
                    if (imgIndex > 0) {
                        imgIndex--;
                    } else {
                        imgIndex = IMG_COUNT - 1;
                    }
                }
                //要根据变换之后图像索引更新布局的背景图片
                root.setBackgroundResource(imgIds[imgIndex]);
                return false;
            }
        });
    }

    //将窗口的触摸事件交给手势侦测器来处理

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return detector.onTouchEvent(event);
    }
}

效果展示

 

  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小鲁不吃猪蹄

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值