自学安卓编程权威指南(二十六)

这一章是用来了解定制视图和触摸事件

这边会有一个项目来响应用户的触摸和拖动,在项目上绘制出矩形框

(1)创建一个activity类去继承SingleFragmentActivity,由此来实例化仅仅单个fragment的布局,修改代码并创建和返回一个DragAndDrawFragment对象

(2)为了准备DragAndDrawFragment的布局,重新命名activity_drag_and_draw.xml为fragment——draw_and_draw.xml

然后创建DragAndDrawFragment类然后覆盖onCreateView()方法,用来实例化fragment_drag_and_draw.xml

(3)定制视图

对于定制视图有两种,一种是简单视图,简单视图不包含子视图,它永远是用来处理定制绘制一种是聚合视图,聚合视图是由其他视图对象来组成的,聚合视图通常用来管理子视图,而不进行图形绘制

下面是创建定制视图所需的三大步骤

(1)选择超类,对于简单视图,我们可以选择用View来作为超类,它是一个空白的画布,所以用它来作为超类最常见,对于聚合视图,我们应该选择适合的超类布局,如FrameLayout

(2)继承选定的超类,覆盖超类的构造方法

(3)覆盖其他关键的方法,用来定制视图行为

 

这边BoxDrawingView是一个简单的视图,所以可以直接继承View,然后去添加两个构造方法

public class BoxDrawingView extends View {

public BoxDrawingView(Context context) {

this(context,null);

}

public BoxDrawingView(Context context,AttributeSet attrs) {

super(context,attrs);

}

}

这边之所以添加两个构造方法,是因为代码可以从代码或者布局文件中实例化,从布局文件中实例化的视图会接收到一个AttributeSet实例,该实例包含了XML布局文件中指定的XML属性,即使不打算使用构造方法,按习惯,也要添加这两个构造方法

有了定制视图类,我们就需要在布局中去更新布局文件来使用它

在fragment_drag_and_draw.xml添加

<com.bignerdranch.android.draganddraw.BoxDrawingView

     xmln:android="http://schemas.android.com/apk/res/android"

     android:layout_width = "match_parent"

     android:layout_height = "match_parent"/>

注意,应该给出BoxDrawingView的全路径类名,这样布局inflater才能够找到它,布局inflater解析布局xml文件,并按照视图定义创建View实例,如果不给全路径,那么inflater会转向在android.view和android.widget包中寻找同类名,找不到就会崩溃

此时运行就会出现一个空的视图

(4)处理触摸事件

监听触摸事件是使用下面的View方法,设置一个触摸监听器:

setOnTouchListener(View.OnTouchListener l) 

上面实现的接口,仅仅提供给触摸事件发送时调用

但是这边由于是View的子类,所以我们直接覆盖下面的方法就可以

public boolean onTouchEvent(MotionEvent event) {

}

该方法接收一个MotionEvent的实例,这个类可以用来描述位置和动作的触摸事件,动作用于描述事件所处的阶段

ACTION_CANCEL :父视图拦截了触摸事件

在MotionEvent方法中查看动作值可以使用 getAction()方法

public boolean onTouchEvent(MotionEvent event) {

PointF current = new PointF(event.getX(),event.getY());

String action = "";

switch(event.getAction()) {

case MotionEvent.ACTION_DOWN:

action  = "ACTION_DOWN";

break;

}

return true;

}

这里的x与y坐标已经封装到PointF对象里面了,我们需要同时传递两个坐标值,这个容器类刚好适合

(5)跟踪运动事件

除了记录坐标,BoxDrawingView主要用于在屏幕上绘制矩形框,要实现这个目标需要知道定义矩形框的(1)原始坐标点,当前坐标点(2)定义一个矩形框,我们还需要追踪记录来自多个MotionEvent的数据,这些数据会保存在Box对象中

public class Box {

private PointF mOrigin;

private PointF mCurrent;

public Box(PointF origin) {

mOrigin = origin;

mCurrent = origin;

}

public PointF getCurrent(){

return mCurrent;

}

public void setCurrent(PointF current){

mCurrent = current;

}

public PonintF getOrigin(){

return mOrigin;

}

}

这样当用户触摸视图界面的时候,新的Box对象就会加到现有的矩形中去

现在回到BoxDrawingView中,使用新的Box对象来跟踪绘制状态

private Box mCurrentBox;

private List<Box> mBoxen = new ArrayList<>();

switch(event.getAction()) {

case MotionEvent.ACTION_DOWN:

action  = "ACTION_DOWN";

mCurrentBox = new Box(current);

mBoxen.add(mCurrentBox);

break;

case MotionEvent.ACTION_MOVE:

action = "dd";

if(mCurrentBox !=null) {

mCurrentBox.setCurrent(current);

invalidate();//这会让BoxDrawingView失效,这会使得它重新自我绘制,并再次调用onDraw(Canvas)方法

break;

}

case:MotionEvent.ACTION_UP:

action= "";

mCurrentBox = null;

break;

}

case MotionEvent.ACTION_CANCEL:

action = ""

mCurrentBox = null;

return true;

}

现在只要接收到ACTION_DOWN的动作坐标,就以事件原始坐标新建立一个Box对象并赋值给mCurrentBox中,然后再添加到矩形数组中去

(6)onDraw()方法中去进行图形的绘制

应用启动后,所有的视图都处于无效的状态,也就是说视图还没有绘制到屏幕上去,为了解决这个问题,Android调用了顶级的View视图的draw()方法,这会引起从上到下的链式调用的反应,首先视图完成自我绘制,然后是子视图的绘制,再然后就是子视图的子视图的自我绘制,由此调用到继承结构的末端,当所有的视图都自我绘制后,最顶级的View视图也已经生效了

为加入这种绘制,可以覆盖下面的方法

protected void onDraw(Canvas canvas) {

 

}

在Android中有两大绘制类

Canvas类拥有我们需要的所有绘制的操作,其方法可以决定绘制在哪里,以及绘制什么,比如圆形

Paint类决定如何绘制,其方法可以指定绘制图形的特征,例如是不是填补图形,使用什么字体绘制

(7)创建Paint

private Paint mBoxPaint;

private Paint mBackgroundPaint;

在BoxDrawingView(Context AttributeSet)方法中去实例化

public BoxDrawingView(Context context,AttributeSet attrs) {

super(context,attrs);

mBoxPaint = new Paint();

mBoxPaint.setColor();

mBackgroundPaint.setColor();

}

有了Paint对象,那么就能在屏幕上绘制矩形框了

(8)覆盖onDraw(Canvas)方法

protected void onDraw(Canvas canvas) {

canvas.drawPaint(mBackgroundPaint);

for(Box box:mBoxen) {

float left = Math.min(box.getOrigin().x,boxgetCurrent().x);

float right = Math.max(box.getOrigin().x,boxgetCurrent().x);

float top  = Math.min(box.getOrigin().y,boxgetCurrent().y);

float bottom = Math.max(box.getOrigin().y,boxgetCurrent().y);

canvas.drawRect(left,top,right,bottom,mBoxPaint);

}

}

现在就可以绘制一些矩形了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值