《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就执行吗