《Android自定义组件开发详解》是网络上关于学习自定义开发组件的一本比较火的教材,书本第四章的实例是一个绘图App例子,里面,主要是应用双缓存画图。实例中各类的作用如下

而本人的问题主要是ImageView和继承ShapeDrawer的子类怎么样在上面绘图的逻辑有点不懂,本书之前第三章有个很简单的绘图例子就是如下

如上面,在View的子类中onTouchEvent方法中不断去绘图,而现在是各种绘图器在view上绘图,但是绘图器的父类ShapeDrawer也会有onTouchEvent这个方法,这让本人很疑惑,毕竟ShapeDrawer不是基于View的子类,怎么会有这个方法,就算你定义了这个方法在view上绘图的时候也应该不会起作用。望各位给小弟解疑,谢谢!
相关的两个类是:
ShapeDrawer.java

而本人的问题主要是ImageView和继承ShapeDrawer的子类怎么样在上面绘图的逻辑有点不懂,本书之前第三章有个很简单的绘图例子就是如下

如上面,在View的子类中onTouchEvent方法中不断去绘图,而现在是各种绘图器在view上绘图,但是绘图器的父类ShapeDrawer也会有onTouchEvent这个方法,这让本人很疑惑,毕竟ShapeDrawer不是基于View的子类,怎么会有这个方法,就算你定义了这个方法在view上绘图的时候也应该不会起作用。望各位给小弟解疑,谢谢!
相关的两个类是:
ShapeDrawer.java
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.view.MotionEvent;
import android.view.View;
/**
* 绘图的基类
* Created by ZhiyuLiu on 2017/1/10.
*/
public abstract class ShapeDrawer {
private View view;
public ShapeDrawer(View view){
super();
this.view=view;
}
public View getView() {
return view;
}
/**
* 用于绘图
* @param viewCanvas
* 用于展示结果的画布
* @return
*/
public void draw(Canvas viewCanvas){
Bitmap bitmap=BitmapBuffer.getInstance().getBitmap();
viewCanvas.drawBitmap(bitmap,0,0,null);
}
/**
* 用于响应触摸事件
*
* @param event
* @return
*/
public abstract boolean onTouchEvent(MotionEvent event);
/**
* 绘图的逻辑
*/
public abstract void logic();
RectDrawer.java
import android.graphics.Canvas;
import android.graphics.Paint;
import android.view.MotionEvent;
import android.view.View;
/**
* 用于绘制矩形
* Created by ZhiyuLiu on 2017/1/10.
*/
public class RectDrawer extends ShapeDrawer {
private float firstX;
private float firstY;
private float currentX;
private float currentY;
public RectDrawer(View view){
super(view);
}
@Override
public void draw(Canvas viewCanvas){
super.draw(viewCanvas);
drawShape(viewCanvas,firstX,firstY,currentX,currentY);
}
/**
* 画当前的形状
* @param canvas
*/
protected void drawShape(Canvas canvas,float firstX,float firstY,
float currentX,float currentY){
Paint paint=AttributesTool.getInstance().getPaint();
if(firstX<currentX&&firstY<currentY){
canvas.drawRect(firstX,firstY,currentX,currentY,paint);
}else if(firstX>currentX&&firstY>currentY){
canvas.drawRect(currentX,currentY,firstX,firstY,paint);
}else if(firstX>currentX&&firstY<currentY){
canvas.drawRect(currentX,firstY,firstX,currentY,paint);
}else if(firstX<currentX&&firstY>currentY){
canvas.drawRect(firstX,currentY,currentX,firstX,paint);
}
}
@Override
public boolean onTouchEvent(MotionEvent event){
float x=event.getX();
float y=event.getY();
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
firstX=x;
firstY=y;
break;
case MotionEvent.ACTION_MOVE:
currentX=x;
currentY=y;
getView().invalidate();
break;
case MotionEvent.ACTION_UP:
Canvas canvas=BitmapBuffer.getInstance().getCanvas();
drawShape(canvas,firstX,firstY,currentX,currentY); //将绘图最终结果绘制到保存绘图历史的保存类BitmapBuffer中
getView().invalidate();
BitmapBuffer.getInstance().pushBitmap();
break;
default:
break;
}
return true;
}
@Override
public void logic(){
}
}
ImageView.java
import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
/**
* 绘图view
* Created by ZhiyuLiu on 2017/1/10.
*/
public class ImageView extends View {
private ShapeDrawer shapeDrawer;
public void setShapeDrawer(ShapeDrawer shapeDrawer){
this.shapeDrawer=shapeDrawer;
}
@Override
protected void onSizeChanged(int w,int h,int oldw,int oldh){
super.onSizeChanged(w, h, oldw, oldh);
SystemParams.areaWidth=this.getMeasuredWidth();
SystemParams.areaHeight=this.getMeasuredHeight();
}
@Override
protected void onDraw(Canvas canvas){
if(SystemParams.isRedo){
canvas.drawBitmap(BitmapBuffer.getInstance().getBitmap(),0,0,null);
SystemParams.isRedo=false;
}else {
shapeDrawer.draw(canvas);
}
shapeDrawer.logic();
}
@Override
public boolean onTouchEvent(MotionEvent event){
return shapeDrawer.onTouchEvent(event);
}
public ImageView(Context context, AttributeSet attrs){
super(context,attrs);
shapeDrawer=new RectDrawer(this);
}
}
MainActivity.java
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
public class MainActivity extends AppCompatActivity {
private ImageView draw;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
draw=(ImageView)findViewById(R.id.image);
}
@Override
public boolean onOptionsItemSelected(MenuItem item){
ShapeDrawer shapeDrawer=null;
AttributesTool at=AttributesTool.getInstance();
switch (item.getItemId()){
case R.id.remove:
BitmapBuffer.getInstance().redo();
SystemParams.isRedo=true;
draw.invalidate();
break;
case R.id.rect:
shapeDrawer=new RectDrawer(draw);
break;
case R.id.oval:
shapeDrawer=new OvalDrawer(draw);
break;
default:
break;
}
if (shapeDrawer!=null){
draw.setShapeDrawer(shapeDrawer);
}
return super.onOptionsItemSelected(item);
}
@Override
public boolean onCreateOptionsMenu(Menu menu){
getMenuInflater().inflate(R.menu.main,menu);
return true;
}
解决方案
15
shapeDrawer中onTouchEvent是本人定义的,就相当于把imageview的onTouchEvent的实现单独提出来实现,然后在imageView中onTouchEvent中调用。shapeDrawer中onTouchEvent方法,可以取名A,也可以取名B。只是imageView中onTouchEvent方法调用的具体实现罢了。取相同名字是方法理解。
25
ShapeDrawer是你本人定义的类,里面的方法当然也是你本人定义命名的,像楼上说的那样 shapeDrawer中onTouchEvent方法,可以取名A,也可以取名B,其实关键在于它的参数MotionEvent,虽然ShapeDrawer不是基于View的子类,但是MotionEvent参数是从View的子类的onTouchEvent方法传过来的
10
是的,这个代码不就是view的onTouchEvent执行的时候ShapeDrawer的onTouchEvent就执行吗