Android开发中自定义视图

很多时候,Android自身提供给我们的视图可能不能满足我们的需求,这个时候我们就需要 自定义视图
虽然自定义视图很多,但总体归为两个类别:

  1. 简单视图 。简单视图内部当然也可以很复杂,之所以称之为简单视图是因为,简单视图中不包括子视图。简单视图几乎总是用来处理定制绘制。
  2. 聚合视图 。聚合视图一般包括很多个子视图,在聚合视图中一般不处理绘制事件,而是对子视图进行管理,绘制的任务一般都是有子视图来完成。

一般来说,自定义视图一般可以分为两步来完成。

  1. 选择合适的父类。 一般来说,如果我们想在某个控件的基础上进行延伸,一般选择该控件为父类进行自定义视图。如果我们向更加自由一下,那我们一般选择 View 作为我们的父类,继承View 相当于我们在一张空白的画纸上作画,所以更加自由,所以这种方法用的最多。
  2. 覆盖那些我们需要使用到的方法,在其中完成绘图操作。

接下来就开始我们的工作。
先新建一个 继承自 ViewDrawingView 的类,并覆盖 View 的构造方法和 onDraw 方法。

package com.tobetheonlyone.startandroid;

import android.content.Context;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;

/**
 * Created by ToBeTheOnlyOne on 2018/2/10.
 */

public class DrawingView extends View {

    public DrawingView1(Context context, AttributeSet attrs){
        super(context,attrs);

    }

    @Override
    protected void onDraw(Canvas canvas){

    }
}

先在 onDraw 方法中在绘制视图颜色为0xffdfdada ,并在视图中间绘制一个半经为 100 的圆。

@Override
    protected void onDraw(Canvas canvas){

        //绘制背景
        canvas.drawColor(0xffdfdada);

        //画笔的初始化
        Paint drawPaint = new Paint();
        drawPaint.setColor(0xffff0000);
        //绘制圆形,前两个参数为圆点位置,第三个参数为圆的半径,第四个为使用的画笔
        canvas.drawCircle(getWidth()/2,getHeight()/2,100,drawPaint);
    }

运行效果如下:

现在基本的步骤我们都知道了,那如果我们自定义的视图要和用户交互该怎么办呢?其实也很简单,只要我们重写父类的 onTouchEvent 方法就可以,如下:

public class DrawingView extends View {

    private final static String TAG = "DrawingView";

    ...

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        String action = " ";
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                action = "ACTION_DOWN";
                break;
            case MotionEvent.ACTION_UP:
                action = "ACTION_UP";
                break;
            case MotionEvent.ACTION_MOVE:
                action = "ACTION_MOVE";
                break;
            case MotionEvent.ACTION_CANCEL:
                action = "ACTION_CANCEL";
                break;
        }
        Log.w(TAG,action);
        return true;
    }
}

onTouchEvent 方法中我们对四个触摸动作进行了处理,即 ACTION_DOWN , ACTION_UP , ACTION_MOVE , ACTION_CANCEL 这四个动作。这四个动作所处事件的阶段如下:

  • ACTION_DOWN 手指触摸到屏幕
  • ACTION_UP 手指离开屏幕
  • ACTION_MOVE 手指在屏幕上移动
  • ACTION_CANCEL 父视图拦截了触摸事件

再次运行项目,我们手指在屏幕上点击移动就可以在控制台看到响应事件。
接下来我们来实现一个简单的交互,即用户手指在屏幕上移动,DrawingView 在用户手指移动的区域画一个正方形。

首先,要知道定义矩形框的两个坐标点 : 原始坐标点(即手指的初始位置),当前坐标点(即手指当前的位置)。
因此,我们来新建一个 Rectangle 的类来保存我们矩形的属性:
Rectangle.class

public class Rectangle {
    private PointF mOriginPoint;
    private PointF mCurrentPoint;

    public Rectangle(PointF origin){
        mOriginPoint = origin;
        mCurrentPoint = origin;
    }

    public PointF getCurrentPoint(){
        return mCurrentPoint;
    }

    public void setCurrentPoint(PointF currentPoint){
        mCurrentPoint = currentPoint;
    }

    public PointF getOriginPoint(){
        return mOriginPoint;
    }
}

修改我们的DrawingView
DrawingView.class

public class DrawingView extends View {

    private Paint drawPaint;
    private Rectangle mCurrentRect;
    private List<Rectangle> mRectangleList = new ArrayList<>();




    public DrawingView(Context context, AttributeSet attrs){
        super(context,attrs);

        //画笔的初始化
        drawPaint = new Paint();
        drawPaint.setColor(0x22ff0000);
    }



    @Override
    protected void onDraw(Canvas canvas){

        //绘制背景
        canvas.drawColor(0xffdfdada);


    }

    @Override
    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";

                mCurrentRect = new Rectangle(current);
                mRectangleList.add(mCurrentRect);
                break;
            case MotionEvent.ACTION_UP:
                action = "ACTION_UP";
                mCurrentRect = null;
                break;
            case MotionEvent.ACTION_MOVE:
                action = "ACTION_MOVE";
                if(mCurrentRect!=null){
                    mCurrentRect.setCurrentPoint(current);
                    invalidate();
                }
                break;
            case MotionEvent.ACTION_CANCEL:
                action = "ACTION_CANCEL";
                mCurrentRect = null;
                break;
        }
        Log.w("DrawingView",action);

        return true;
    }
}

修改之后,无论在任何时候,视图接受到 ACTION_DOWN 动作事件,就以手指按下的点新建 Rectangle 对象并赋值给 mCurrentRect ,然后再将该对象添加到矩形框的列表中。
当用户手指在屏幕上移动时,会将手指所在的位置更新给 mCurrentRect.mCurrentPoint ,同时调用 invalidate() 方法强制 DrawingView 重新绘制自己,这样用户在屏幕上移动时就可以看到矩形框。
当取消触摸事件或者用户手指离开屏幕的时候,清空 mCurrentRect 以结束屏幕的绘制。
这些工作完成之后,运行项目,发现并没有出现绘制。这是因为我们并没有在 onDraw 方法中进行绘制,修改 onDraw 方法:

public class DrawingView extends View {

    ...

    @Override
    protected void onDraw(Canvas canvas){

        //绘制背景
        canvas.drawColor(0xffdfdada);

        //绘制圆形
        canvas.drawCircle(getWidth()/2,getHeight()/2,100,drawPaint);

        for(Rectangle rectangle:mRectangleList){
            float left = Math.min(rectangle.getOriginPoint().x,rectangle.getCurrentPoint().x);
            float right = Math.max(rectangle.getOriginPoint().x,rectangle.getCurrentPoint().x);
            float top = Math.min(rectangle.getOriginPoint().y,rectangle.getCurrentPoint().y);
            float bottom = Math.max(rectangle.getOriginPoint().y,rectangle.getCurrentPoint().y);
            canvas.drawRect(left,top,right,bottom,drawPaint);
        }
    }

    ...
}

修改之后再次运行,效果如下:

到此,我们自定义视图简单的探究就完成了。。。。

PS:开发了一个制作个性二维码的应用,有兴趣的朋友可以试一试~ 创意二维码制作

猜你喜欢

转载自blog.csdn.net/ToBeTheOnlyOne/article/details/79305574