标签:math 崩溃 引用 屏幕 ida and 目标 ontouch validate
1.定制视图
Android自带众多优秀的标准视图与组件,但有时为追求独特的应用视觉效果,我们仍需创建定制视图。
定制视图分为两大类别:
创建定制视图的所需的三大步骤:
1.1 创建一个简单的视图类
public class BoxDrawingView extends View {
// Used when creating the view in code
public BoxDrawingView(Context context) {
this(context, null);
}
// Used when inflating the view from XML
public BoxDrawingView(Context context, AttributeSet attrs) {
super(context, attrs);
}
}
从布局文件中实例化的视图可收到一个AttributeSet实例,该实例包含了XML布局文件中指定的XML属性。即使不打算使用构造方法,按习惯做法也应添加他们。
有了定制视图类,可以在布局文件里面引用它。
<com.bignerdranch.android.draganddraw.BoxDrawingView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
在引用时必须使用自定义View的全路径名,这样布局inflater才能够找到它,布局文件inflater解析布局XML文件,并按视图定义创建View实例,如果元素名不是全路径名,布局inflater
会转而在android.view和android.widget包中寻找目标,如果目标视图放置在其他包中,布局inflater将无法找到目标并最终导致应用崩溃。
因此,对于android.view和android.widger包以外的定制视图类,必须指定它们的全路径名。
1.2 处理触摸事件
监听触摸事件的一种方式是使用以下view方法,设置一个触摸事件监听器:
public void setOnTouchListener(View.OnTouchListener l)
不过我们的定制视图是View的子类,因此可走捷径直接覆盖以下View方法:
public boolean onTouchEvent(MotionEvent event)
该方法接收一个MotionEvent类实例,MotionEvent类可用来描述包括位置和动作的触摸事件。动作用于描述事件所处的阶段。
动作常量 | 动作描述 |
ACTION_DOWN | 手指触摸到屏幕 |
ACTION_MOVE | 手指在屏幕上移动 |
ACTION_UP | 手指离开屏幕 |
ACTION_CANCEL | 父视图拦截了触摸事件 |
在onTouchEvent()实现方法中,可使用以下MotionEvent方法查看动作值:
public final int getAction()
我们的目的就是在一根手指放下的时候记录下放下的位置,移动时随之变化,放开时固定该矩形框。并且之前画的矩形框数据需要记录下来。
建立一个实体类,用于表示一个矩形框的定义数据。用来保存原始坐标点(手指的初始位置)和当前坐标点(手指的当前位置):
public class Box {
private PointF mOrigin;
private PointF mCurrent;
public Box(PointF origin) {
mOrigin = origin;
mCurrent = origin;
}
//get、set略
}
然后重写onTouchEvent()方法并进行相应操作:
private Box mCurrentBox;
private List<Box> mBoxen = new ArrayList<>();
@Override
public boolean onTouchEvent(MotionEvent event) {
// 每次有触摸事件都记录下现在的坐标
PointF current = new PointF(event.getX(), event.getY());
String action = "";
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
action = "ACTION_DOWN";
// 每次按下的时候在列表中中新增一个 Box
mCurrentBox = new Box(current);
mBoxen.add(mCurrentBox);
break;
case MotionEvent.ACTION_MOVE:
action = "ACTION_MOVE";
if (mCurrentBox != null) {
// 移动的时候都要重绘
mCurrentBox.setCurrent(current);
invalidate();
}
break;
case MotionEvent.ACTION_UP:
// 抬起的时候不再指向最新的 Box
action = "ACTION_UP";
mCurrentBox = null;
break;
case MotionEvent.ACTION_CANCEL:
action = "ACTION_CANCEL";
mCurrentBox = null;
break;
}
Log.i(TAG, action + " at x=" + current.x +
", y=" + current.y);z
return true;
}
在取消触摸事件或用户手指离开屏幕时,应清空mCurrentBox以结束屏幕绘制,以完成的Box会安全的存储在数组中。
invalidate()方法会强制BoxDrawingView重新绘制自己,这样在拖拽时就能实时看到矩形框。
2 onDraw()方法内的图形绘制
应用启动时,所有视图都处于无效状态(视图还没有绘制到屏幕上),为解决这个问题,Android调用了顶级View视图的draw()方法,这会引起自上而下的链式调用反映。
首先,视图完成自我绘制,然后是子视图的自我绘制,再然后是子视图的子视图的自我绘制,如此调用下去直至继承结构的末端。当继承结构中的所有视图都完成自我绘制后,最顶级
View 视图也就生效了。
为加入这种绘制,可覆盖以下 View 方法:
protected void onDraw(Canvas canvas);
在onTouchEvent()方法中响应ACTION_MOVE动作时,我们调用invalidate()方法再次让BoxDrawingView处于失效状态,这迫使他重新完成自我绘制,并再次调用onDraw()方法。
Canvas和Paint是Android系统的两大绘制类。
public BoxDrawingView(Context context, AttributeSet attrs){ //AttributeSet实例包含了XML布局文件中指定的XML属性。 super(context,attrs); mBoxPaint = new Paint(); mBoxPaint.setColor(0x22ff0000); mBackgroundPaint = new Paint(); mBackgroundPaint.setColor(0xfff8efe0); } @Override protected void onDraw(Canvas canvas){ //先画出背景 canvas.drawPaint(mBackgroundPaint); //画出每个绘制过的矩形 for(Box box : mBoxen){ float left = Math.min(box.getOrigin().x, box.getCurrent().x); float right = Math.max(box.getOrigin().x, box.getCurrent().x); float top = Math.min(box.getOrigin().y, box.getCurrent().y); float bottom = Math.max(box.getOrigin().y,box.getCurrent().y); canvas.drawRect(left, top ,right ,bottom, mBoxPaint); } }
以上代码的第一部分简单直接:使用米白背景paint,填充canvas以衬托矩形框。然后,针对矩形框数组中的每一个矩形框,据其两点坐标,确定矩形框上下左右的位置。绘制时,左端和顶端的值作为最小值,右端和底端的值作为最大值。完成位置坐标值计算后,调用 Canvas.drawRect(...) 方法,在屏幕上绘制红色矩形框。
标签:math 崩溃 引用 屏幕 ida and 目标 ontouch validate
原文地址:http://www.cnblogs.com/chase1/p/7225877.html