关于《Android自定义组件开发详解》绘图App例子的问题

Android 码拜 3年前 (2017-04-30) 534次浏览
《Android自定义组件开发详解》是网络上关于学习自定义开发组件的一本比较火的教材,书本第四章的实例是一个绘图App例子,里面,主要是应用双缓存画图。实例中各类的作用如下
关于《Android自定义组件开发详解》绘图App例子的问题
而本人的问题主要是ImageView和继承ShapeDrawer的子类怎么样在上面绘图的逻辑有点不懂,本书之前第三章有个很简单的绘图例子就是如下
关于《Android自定义组件开发详解》绘图App例子的问题
如上面,在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

引用:
Quote: 引用:

ShapeDrawer是你本人定义的类,里面的方法当然也是你本人定义命名的,像楼上说的那样  shapeDrawer中onTouchEvent方法,可以取名A,也可以取名B,其实关键在于它的参数MotionEvent,虽然ShapeDrawer不是基于View的子类,但是MotionEvent参数是从View的子类的onTouchEvent方法传过来的

你好,也就是说原因是在下图的代码中shapeDrawer.onTouchEvent(event)的参数是从View子类onTouchEvent的参数传来的,所以调用了shapeDrawer.onTouchEvent的具体内容
关于《Android自定义组件开发详解》绘图App例子的问题

是的,这个代码不就是view的onTouchEvent执行的时候ShapeDrawer的onTouchEvent就执行吗


CodeBye 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明关于《Android自定义组件开发详解》绘图App例子的问题
喜欢 (0)
[1034331897@qq.com]
分享 (0)