安卓开发学习之020 自定义视图的用户交互事件
2015-12-22 10:12
501 查看
要使自定义的视图是可交互的,就需要使它能够对用户事件作出反应,例如,按下按键、触摸屏幕或者单击按钮等。Android提供了多个虚拟事件处理程序,可以对用户输入作出反应,如下所示:
onKeyDown 当任何设备按键被按下时,就会调用它;包括D-pad、键盘、挂断、通话、返回和摄像头按键
onKeyUp 当用户释放一个按键时调用
onTouchEvent 当触摸屏被按下或者释放时调用,或者当检测到运动时调用
本文将通过如下列子简单的介绍上述几个方法
在上一篇自定义视图的基础上,画一个圆,然后实现屏幕触摸事件和点击事件
判断是点击的是圆内还是圆外(系统默认是可以点击View所在的矩形区域)
自定义点击事件回调接口
先给出本文所使用的自定义文件
代码介绍:
1. 重写onDraw方法,在方法中画一个圆,在圆心位置写一字符串
2. 在自定义视图中重写了onKeyDown方法
当按下设备按键时候会调用此方法
注意:必须设置视图可获取焦点
setFocusable(true);方能监听到按键按下事件
3. 重写onTouchEvent方法,监听屏幕触摸事件
4. 定义一个接口 ,里面包含一个点击事件,参数为String类型
5. 给View添加点击监听事件
当点击View的时候判断点击点与圆形的距离,判断点击的是圆内还是圆外,然后调用回调接口中的方法
在布局中写定义了一个自定义视图MyView,在Activity中设置回调事件
当然在Activity中调用自定义视图的默认点击事件也是可以的
效果演示图如下:
开发工具:Android Studio1.5
SDK: Android 6.0
API 23
代码下载:020_MyView_Events
onKeyDown 当任何设备按键被按下时,就会调用它;包括D-pad、键盘、挂断、通话、返回和摄像头按键
onKeyUp 当用户释放一个按键时调用
onTouchEvent 当触摸屏被按下或者释放时调用,或者当检测到运动时调用
本文将通过如下列子简单的介绍上述几个方法
在上一篇自定义视图的基础上,画一个圆,然后实现屏幕触摸事件和点击事件
判断是点击的是圆内还是圆外(系统默认是可以点击View所在的矩形区域)
自定义点击事件回调接口
先给出本文所使用的自定义文件
package com.antex.myview_events; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.PointF; import android.graphics.Rect; import android.util.AttributeSet; import android.util.Log; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; import android.widget.Toast; /** * @author xiaosanyu on 15/12/20. */ public class MyView extends View { private static final String TAG = MyView.class.getSimpleName(); private Paint mPaint; //自定义回调接口 private MyClickListener mListener; //坐标点,记录屏幕按下的位置,后面判断此位置到圆心的距离 private PointF mPoint; public MyView(Context context) { this(context,null); } public MyView(Context context, AttributeSet attrs) { super(context, attrs); mPaint = new Paint(); //消除锯齿 mPaint.setAntiAlias(true); mPaint.setColor(Color.RED); mPaint.setTextSize(30); //描边宽度 mPaint.setStrokeWidth(3); mPoint = new PointF(); //设置可获取焦点 setFocusable(true); //添加点击事件监听器 setOnClickListener(mOnClickListener); } public MyView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { //获取真正的尺寸 int measuredWidth = measureWidth(widthMeasureSpec); int measuredHeight = measureHeight(heightMeasureSpec); //必须调用setMeasuredDimension,否则在布局控件的时候会造成运行时异常 setMeasuredDimension(measuredWidth, measuredHeight); } private int measureHeight(int heightMeasureSpec) { //设置默认高度 int result = 200; //获取控件上下间距 int padding = getPaddingTop() + getPaddingBottom(); //获取模式 int specMode = MeasureSpec.getMode(heightMeasureSpec); //获取值大小 int specSize = MeasureSpec.getSize(heightMeasureSpec); //打印模式和值大小 //Log.i(TAG,"测量高度 " + MeasureSpec.toString(heightMeasureSpec)); switch (specMode) { case MeasureSpec.UNSPECIFIED: break; case MeasureSpec.AT_MOST: //result = specSize; //因为在ondraw里面只是简单的画一个文本。所以只需要文本的高度即可 result = Math.min(specSize, measureTextHeight(mPaint) + padding); break; case MeasureSpec.EXACTLY: result = specSize; break; } return result; } private int measureWidth(int widthMeasureSpec) { //设置默认宽度 int result = 2000; //获取控件左右间距 int padding = getPaddingLeft() + getPaddingRight(); //获取模式 int specMode = MeasureSpec.getMode(widthMeasureSpec); //获取值大小 int specSize = MeasureSpec.getSize(widthMeasureSpec); //打印模式和值大小 //Log.i(TAG, "测量宽度 " + MeasureSpec.toString(widthMeasureSpec)); switch (specMode) { case MeasureSpec.UNSPECIFIED: break; case MeasureSpec.AT_MOST: result = Math.min(specSize, specSize + padding); break; case MeasureSpec.EXACTLY: result = specSize; break; } return result; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mPaint.setColor(Color.GRAY); canvas.drawCircle(getWidth() / 2, getHeight() / 2, Math.min(getWidth(), getHeight()) / 2, mPaint); mPaint.setColor(Color.RED); String string = "MyView"; canvas.drawText("MyView", (getWidth() - measureTextWidth(string, mPaint)) / 2, (getHeight () + measureTextHeight(mPaint)) / 2, mPaint); } //获取文本宽度 private int measureTextWidth(String string, Paint paint) { Rect result = new Rect(); // Measure the text rectangle to get the width paint.getTextBounds(string, 0, string.length(), result); return result.width(); } //获取文本高度 private int measureTextHeight(Paint paint) { Paint.FontMetricsInt fontMetrics = paint.getFontMetricsInt(); // System.out.println("fontMetrics.toString() = " + fontMetrics.toString()); return fontMetrics.descent - fontMetrics.ascent + fontMetrics.leading; } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { Log.d(TAG, "MyView.onKey"); switch (event.getAction()) { case KeyEvent.ACTION_DOWN: Log.d(TAG, "KeyEvent ACTION_DOWN"); break; case KeyEvent.ACTION_UP: Log.d(TAG, "KeyEvent ACTION_UP"); break; case KeyEvent.ACTION_MULTIPLE: Log.d(TAG, "KeyEvent ACTION_MULTIPLE"); break; default: break; } return super.onKeyDown(keyCode, event); } //点击事件注册 private OnClickListener mOnClickListener = new OnClickListener() { @Override public void onClick(View v) { Log.d(TAG, "MyView.onClick"); Toast.makeText(getContext(), "MyView.onClick", Toast.LENGTH_SHORT).show(); //自定义接口回调,判断点击的是圆内还是圆外 if (mListener != null) { //计算当前点击的坐标点与圆心坐标点的距离 int distance = (int) Math.sqrt(Math.pow(mPoint.x - getWidth() / 2, 2) + Math.pow (mPoint.y - getHeight() / 2, 2)); if (distance <= Math.min(getWidth(), getHeight()) / 2) mListener.myClick("inside circle"); else mListener.myClick("outside circle"); } } }; @Override public boolean onTouchEvent(MotionEvent event) { Log.d(TAG, "MyView.onTouch"); mPoint.set(event.getX(), event.getY()); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: Log.d(TAG, "MotionEvent ACTION_DOWN"); break; case MotionEvent.ACTION_UP: Log.d(TAG, "MotionEvent ACTION_UP"); break; case MotionEvent.ACTION_MOVE: Log.d(TAG, "MotionEvent ACTION_MOVE"); break; case MotionEvent.ACTION_OUTSIDE: Log.d(TAG, "MotionEvent ACTION_OUTSIDE"); break; case MotionEvent.ACTION_CANCEL: Log.d(TAG, "MotionEvent ACTION_CANCEL"); break; } return super.onTouchEvent(event); } public void setListener(MyClickListener listener) { mListener = listener; } public interface MyClickListener { void myClick(String s); } }
代码介绍:
1. 重写onDraw方法,在方法中画一个圆,在圆心位置写一字符串
2. 在自定义视图中重写了onKeyDown方法
当按下设备按键时候会调用此方法
注意:必须设置视图可获取焦点
setFocusable(true);方能监听到按键按下事件
3. 重写onTouchEvent方法,监听屏幕触摸事件
4. 定义一个接口 ,里面包含一个点击事件,参数为String类型
public interface MyClickListener { void myClick(String s); }
5. 给View添加点击监听事件
//添加点击事件监听器 setOnClickListener(mOnClickListener);
//点击事件注册 private OnClickListener mOnClickListener = new OnClickListener() { @Override public void onClick(View v) { Log.d(TAG, "MyView.onClick"); Toast.makeText(getContext(), "MyView.onClick", Toast.LENGTH_SHORT).show(); //自定义接口回调,判断点击的是圆内还是圆外 if (mListener != null) { //计算当前点击的坐标点与圆心坐标点的距离 int distance = (int) Math.sqrt(Math.pow(mPoint.x - getWidth() / 2, 2) + Math.pow (mPoint.y - getHeight() / 2, 2)); if (distance <= Math.min(getWidth(), getHeight()) / 2) mListener.myClick("inside circle"); else mListener.myClick("outside circle"); } } };
当点击View的时候判断点击点与圆形的距离,判断点击的是圆内还是圆外,然后调用回调接口中的方法
在布局中写定义了一个自定义视图MyView,在Activity中设置回调事件
view = (MyView) findViewById(R.id.myView); //调用自己定义的点击事件 view.setListener(new MyView.MyClickListener() { @Override public void myClick(String s) { Toast.makeText(MainActivity.this, "MyView.onClick CallBack " + s, Toast .LENGTH_SHORT).show(); } });
当然在Activity中调用自定义视图的默认点击事件也是可以的
//亦可调用系统原有的点击监听方法 /* view.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(MainActivity.this,"View setOnClickListener",Toast.LENGTH_SHORT) .show(); } }); view.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { Toast.makeText(MainActivity.this,"View setOnLongClickListener",Toast.LENGTH_LONG) .show(); return true; } });*/
效果演示图如下:
开发工具:Android Studio1.5
SDK: Android 6.0
API 23
代码下载:020_MyView_Events
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories