Android编程权威指南——DragAndDraw

  • DragAndDraw 项目

创建DragAndDraw新项目,最低SDK版本选择API19,新建空activity并命名为DragAndDraw- Activity。

既然SingLeFragmentActivity可实例化仅包含单个fragment的布局,我们让DragAndDraw-Activity继承它。

在Android Studio中,复制之前项目的SingleFragmentActivity.java和activity fragment. xml文件到DragAndDraw项目的对应目录中。
在DragAndDrawActivity.java中,修改代码继承SingleFragmentActivity类,并创建返回一个DragAndDrawFragment对象(稍后会创建该类)。代码给该如下。
修改activity(DragAndDrawActivity.java)

public class DragAndDrawActivity extends AppCompatActivity SingLeFragmentActivity {


@0verride


public Fragment createFragment() {



return DragAndDrawFragment.newInstance()



}
为准备DragAndDrawFragment的布局,重命名activity_drag and_drawxml为fragment_drag and draw.xml。

继承android.support.v4.app.Fragment超类,新建DragAndDrawFragment类。然后覆盖 onCreateView(…)方法,并在其中实例化fragment drag and_draw.xml布局,如以下代码所示。
创建DragAndDrawFragment

public class DragAndDrawFragment extends Fragment

{


pubLic static DragAndDrawFragment newInstance(){


return new DragAndDrawF ragment();


}


@0verride



public View onCreateView(LayoutInfLater infLater,ViewGroup container,
Bundle savedInstanceState) {



View v= infLater.infLate(R.Layout.fragment_drag_and_draw,container,false);


 return v;


 }


 }


 
运行DragAndDraw应用即可得到带默认布局的DragAndDraw应用。

  • 创建定制视图

创建定制视图所需三大步骤。
(1)选择超类。对于简单定制视图而言,View是个空白画布,因此它作为超类最常见。对于聚合定制视图,我们应选择合适的超类布局,比如FrameLayout。
(2)继承选定的超类,覆盖超类的构造方法。(3)覆盖其他关键方法,以定制视图行为。创建 BoxDrawingView 视图
BoxDrawingView是个简单视图,同时也是View的直接子类。
以View为超类,新建BoxDrawingView类。在BoxDrawingViewjava中,添加两个构造方法。如下代码所示
初始的BoxDrawingView视图类(BoxDrawingViewjava)

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);


}


}
更新fragment _drag _and_draw.xml布局文件以使用它,如下代码清单 所示。

在布局中添加BoxDrawingView(fragment_drag_and_draw.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” />

注意,应给出BoxDrawingView的全路径类名,这样布局inflater才能够找到它。

运行DragAndDraw应用,一切正常的话,屏幕上会出现一个空视图。

  • 未绘制的BoxDrawingView

设置一个触摸事件监听器∶ pubLic void setOnTouchListener(View.0nTouchListener L)

其工作方式与setOnClickListener(View.0nCLickListener)相同。实现View.0nTouch- Listener接口,供触摸事件发生时调用。不过,由于定制视图是View的子类,也可走捷径直接覆盖以下View方法∶ public booleanonTouchEvent(MotionEvent event)该方法接收一个MotionEvent类实例。MotionEvent类可用来描述包括位置和动作的触摸事件。

动作用于描述事件所处的阶段。
动作描述动作常量
手指触摸到屏幕 ACTION_DOWN

手指在屏幕上移动 ACTION_MOVE


手指离开屏幕 ACTION_UP
父视图拦截了触摸事件 ACTION_CANCEL


在BoxDrawingView.java中,添加一个日志tag。如下代码所示。

实现BoxDrawingView视图类(BoxDrawingView.java)

public class BoxDrawingView extends View {

private static final String TAG = “BoxDrawingView”;
@0verride

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;

case MotionEvent.ACTION_MOVE:

action = “ACTION_MOVE”;

break;


case MotionEvent.ACTION_UP:


action = “ACTION_UP”;

break;


case MotionEvent.ACTION_CANCEL:

action = “ACTION_CANCEL”;


break;

}


Log.i(TAG,action +" at x="+ current.X +
",y="+ current.y);



return true;




}



}

运行DragAndDraw应用并打开LogCat视图窗口。触摸屏幕并移动手指,查看BoxDrawingView接收的触摸动作的X和Y坐标记录。

随后新建一个Box类,用于表示一个矩形框的定义数据,如下代码所示。

添加Box类(Box.java)


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 PointF getOrigin(){


return mOrigin;



}



}
DragAndDraw应用中的对象
回到BoxDrawingView类中,使用新Box对象跟踪绘制状态,如下代码所示。
添加拖曳生命周期方法(BoxDrawingViewjava)
public class BoxDrawingView extends View {

private static final String TAG =“BoxDrawingview”;


private Box mCurrentBox;

private List mBoxen = new ArrayList<>();

@0verride


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”;


 
// Reset drawing state
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:



 
 
 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);


 
 

return t rue;


 
 

}


 
 

}


 
 


任何时候,只要接收到ACTION_DOWN动作事件,就以事件原始坐标新建Box对象并赋值给 mCurrentBox,然后再添加到矩形框数组中。

注意ACTION_MOVE事件发生时调用的invatidate()方法。该方法会强制BoxDrawingView重新绘制自己。这样,用户在屏幕上拖曳时就能实时看到矩形框。这同时也引出了接下来的任务∶在屏幕上绘出矩形框。

  • onDraw(…)方法内的图形绘制

Android调用了顶级View视图的draw()方法。当继承树中的所有视图都完成自我绘制后,最顶级View视图也就生效了。
返回BoxDrawingView.java中,在BoxDrawingView的XML构造方法中创建两个Paint对象,如下代码所示。

创建Paint(BoxDrawingView.java)

public class BoxDrawingView extends View {


private static final String TAG = “BoxDrawingView”;


private Box mCurrentBox;



private List mBoxen = new ArrayList<>();


private Paint mBoxPaint;


 private Paint mBackgroundPaint;


 // Used when inflating the view from XML


 
public BoxDrawingView(Context context,AttributeSet attrs){



 
super(context,attrs);



 
// Paint the boxes a nice semitransparent red (ARGB) mBoxPaint = new Paint();


 
mBoxPaint.setColor(0x22ff0000);


 
// Paint the background off-white


 
mBackgroundPaint = new Paint();


 
mBackgroundPaint.setColor(0xfff8efe0);


 
}


 
}


 

有了Paint对象的支持,现在能在屏幕上绘制矩形框了,如下代码所示。


覆盖onDraw(Canvas)方法(BoxDrawingViewjava)

public BoxDrawingView(Context context,AttributeSet attrs){
}
@0verride
protected void onDraw(Canvas canvas){

// FiLl the background
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(…)方法,在屏幕上绘制红色矩形框。

运行代码即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值