1.理论Api事件:
MontionEvent 触碰操作
download 产生一次,按下
move 这里的move会调用多次
up 产生一次,松开
getX():获取X轴坐标,原始发生事键按钮自己
getRawX(): 现对于屏幕左上角
屏幕类型:
电阻屏:按下压力感应,软屏
电容屏:现对于低电流来感应屏幕,硬屏
事件传播:
屏幕-》Linxu 内核-》传递到当期应用-》当前Activity-》事件分发dispachTouchEvent(MontionEvent event)
-> 按钮响应事件
-》 如果按钮消费,那么Activity自己处理
2. 事件理论分析:
activity_main.xml 布局文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="lanya.denganzhi.com.montioneventtest.Main2Activity"
android:orientation="vertical">
<ImageView
android:id="@+id/moveImg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@mipmap/ic_launcher"
android:layout_marginLeft="30dp"
android:layout_marginTop="50dp"/>
</LinearLayout>
MyImageView 代码:
package lanya.denganzhi.com.montioneventtest;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
/**
* Created by Administrator on 20-3-8.
*/
public class MyImageView extends android.support.v7.widget.AppCompatImageView {
public MyImageView(Context context) {
super(context);
}
public MyImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
// 分发
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
Log.e("denganzhi","ImageView--dispatchTouchEvent:"+event.getAction());
return super.dispatchTouchEvent(event);
}
// 处理
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.e("denganzhi","ImageView--onTouchEvent:"+event.getAction());
return super.onTouchEvent(event);
}
}
MainActivity 代码:
package lanya.denganzhi.com.montioneventtest;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
MyImageView myImageView=null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myImageView = (MyImageView) findViewById(R.id.myImageView);
myImageView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
Log.e("denganzhi","myImageView--setOnTouchListener:"+event.getAction());
return true;
}
});
}
//
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
Log.e("denganzhi","MainActivity--dispatchTouchEvent:"+event.getAction());
return super.dispatchTouchEvent(event);
}
//
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.e("denganzhi","MainActivity--onTouchEvent:"+event.getAction());
// MotionEvent.ACTION_DOWN 0
// MotionEvent.ACTION_MOVE // 1
// MotionEvent.ACTION_UP //2
return super.onTouchEvent(event);
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
Log.e("denganzhi1","key--dispatch:"+event.getKeyCode());
return super.dispatchKeyEvent(event);
}
}
*****************************************************************
View Api:
boolean onTouchEvnet(MontionEvent evnet) : 调用了方法叫处理了,返回true才表示消费该事件
down事件:
MainActivity--dispatchTouchEvent:0 down事件,activity分发
ImageView--dispatchTouchEvent:0 activity分发给imageview
myImageView--setOnTouchListener:0 imageview的setOnTouch事件调用,不消费,往上传递
ImageView--onTouchEvent:0 imageview 的重写 onTouch方法调用
MainActivity--onTouchEvent:0 activity的重写 onTouch方法调用,最终消费时间
move事件:
MainActivity--dispatchTouchEvent:2
MainActivity--onTouchEvent:2 // move事件都不调用ImageViw的dispatch分发了,直接activity消费
up事件:
MainActivity--dispatchTouchEvent:1 // up事件都不调用ImageViw的dispatch分发了,直接activity消费
MainActivity--onTouchEvent:1
总结:要是第一次down事件不消费,后面的move,up事件不会分发了
*****************************************************************
down事件:
myImageView.setOnTouchListener 返回true
MainActivity--dispatchTouchEvent:0 down事件,activity分发
ImageView--dispatchTouchEvent:0 activity分发给imageview
myImageView--setOnTouchListener:0 返回true,那么时间已经被消费了,时间停止
move事件:
MainActivity--dispatchTouchEvent:2
ImageView--dispatchTouchEvent:2
myImageView--setOnTouchListener:2 消费
up事件:
MainActivity--dispatchTouchEvent:1
ImageView--dispatchTouchEvent:1
myImageView--setOnTouchListener:1 消费
*****************************************************************************************
2. 实现图片拖拽功能:
View 视图Api:
getLeft()、getTop(): 左上角顶点坐标现对于原点坐标
getRight()、getBottom() 右下角相对于原点坐标
layout(int left,top,right,bottom): 对视图进行重新定位
*****************************************************************
实现图片拖动伪代码:
实现图片拖动原理:
lastX
lastY
eventX
eventY
MontionEvent.down
// 1.获取按下点坐标
lastX= event.getRawX();
lastY= evnet.getRawY();
MontionEvent.move
// 2.获取move相对于down移动距离
eventX =event.getRawX();
eventY = event.getRawY();
dx = eventX - lastX;
dy = eventY- lastY;
// 3.重新定位
left= imageview.getLeft()+ dx;
top = imageview.getTop() + dy;
right = imageview.getRight() + dx;
bottom = imageview.getBottom + dy:
imageview.layout(left,top,right,bottom)
//4. 下次移动做准备
lastX= eventX
lastY= eventY
*****************************************************************
源码:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="lanya.denganzhi.com.montioneventtest.Main2Activity"
android:orientation="vertical">
<ImageView
android:id="@+id/moveImg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@mipmap/ic_launcher"
android:layout_marginLeft="30dp"
android:layout_marginTop="50dp"/>
</LinearLayout>
Main2Activity 代码:
package lanya.denganzhi.com.montioneventtest;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
public class Main2Activity extends AppCompatActivity {
ImageView moveImg;
float lastX ,lastY ; //上次位移
float eventX , eventY; // 当前坐标
private LinearLayout parent;
float parentBottom,parentRight;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
moveImg = (ImageView)findViewById(R.id.moveImg);
parent = (LinearLayout) moveImg.getParent(); //parentBottom、parentRight 马上去取为0
moveImg.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
// 得到父视图的 right/bottom
if(parentRight==0){
parentRight= parent.getRight();
parentBottom= parent.getBottom();
}
lastX= event.getRawX();
lastY =event.getRawY();
break;
case MotionEvent.ACTION_MOVE:
eventX = event.getRawX();
eventY = event.getRawY();
float dx= eventX -lastX;
float dy= eventY -lastY;
float left = moveImg.getLeft() + dx;
float top =moveImg.getTop() + dy;
float right = moveImg.getRight() + dx;
float bottom = moveImg.getBottom() + dy;
// 不能移动到外面去
if(left<0){
right = right + (-left);
left=0; // 那么已经移除了left,right也要复原,加上移除的left
}
// 不能移出到左边
if(top < 0){
bottom = bottom + (-top);
top = 0;
}
// 不能移出到右边
if(right > parentRight){
left= left - (right - parentRight);
right= parentRight;
}
if(bottom > parentBottom){
top = top - (bottom - parentBottom);
bottom = parentBottom;
}
moveImg.layout((int)left,(int)top,(int)right,(int)bottom);
lastX= eventX;
lastY=eventY;
break;
case MotionEvent.ACTION_UP:
break;
}
return true;
}
});
}
}
上图:
3. KeyEvent: 事件
基本类型:down: 手指按下, 会被调用多次
up : 手指移动
实现双击back键盘退出
//
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
Log.e("denganzhi","MainActivity--dispatchTouchEvent:"+event.getAction());
return super.dispatchTouchEvent(event);
}
//
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.e("denganzhi","MainActivity--onTouchEvent:"+event.getAction());
// MotionEvent.ACTION_DOWN 0
// MotionEvent.ACTION_MOVE // 1
// MotionEvent.ACTION_UP //2
return super.onTouchEvent(event);
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
Log.e("denganzhi1","key--dispatch:"+event.getKeyCode());
return super.dispatchKeyEvent(event);
}
// 会被 调用多次
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
// 如果要监听back,home键,必须设置下面这2个Api
// startTracking 和 return true;
event.startTracking();
// event.getKeyCode() //获取按键
Log.e("denganzhi1","key--down");
return true;
}
boolean isExit=false;
Handler handler=new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if(msg.what==100){
isExit=false;
}
}
};
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
Log.e("denganzhi1","key--up");
if(event.getKeyCode() == KeyEvent.KEYCODE_BACK){
if(!isExit){
isExit=true;
handler.sendEmptyMessageDelayed(100,4000);
Toast.makeText(MainActivity.this,"退出",Toast.LENGTH_SHORT).show();
return true;
}
// 否则退出 执行super,4s 以后 有需要双击
}
return super.onKeyUp(keyCode, event);
}
@Override
protected void onDestroy() {
handler.removeMessages(100);
super.onDestroy();
}
// 长按监听
@Override
public boolean onKeyLongPress(int keyCode, KeyEvent event) {
Log.e("denganzhi1","key--long");
return super.onKeyLongPress(keyCode, event);
}