Android自定义View入门

来源:互联网 发布:php str split 函数 编辑:程序博客网 时间:2024/06/06 12:38

在成千上万的移动应用中,我们都能够看到各种不同酷炫的界面效果,如果你是一个android开发人员,你可能会想,这些效果是怎么实现的,因为android原生控件根本不能做出那么酷炫的东西的。其实这就是自定义View。然后对于很多初级android开放者来说,自定义View看起来很难,学起来也很难。今天这篇博客的目的是让大家来体会一下自定义View的整体感知。

废话不多说,开始咱们的正题,先上效果图:

这里写图片描述

今天勒,就是通过自定义View来实现小球跟随手指的移动的一个例子。

自定义View的分类

自定义View大致可以分为三类:

1. 组合控件:直接通过android提供的原生控件来进行自定义操作

2. 拓展控件:在原有控件的基础上进行功能性的扩展

3. 完全自定义控件:完全自定义View和完全自定义ViewGroup

自定义View所涉及到的三个常用核心方法

  1. onMeasure:该方法用于测量控件的大小(宽高)

  2. onLayout:自定义View一般不需要,用于自定义ViewGroup摆放子控件的布局方式。

  3. onDraw:绘制(View上面显示什么),比如TextView显示文本,就是把文本绘制到TextView上;ImageView显示图片,就是把图片绘制到ImageView上面

自定义View构造方法

  1. public View (Context context):如果该View需要通过代码来进行实例化,那么就会调用这个构造方法

  2. public View (Context context, AttributeSet attrs):如果自定义需要通过布局xml文件中设置,那么就会调用这个构造方法

  3. public View (Context context, AttributeSet attrs, int defStyle):如果自定义需要通过布局xml文件中设置,并且设置了style属性,则调用该构造方法

实战小球跟随手指移动

上面介绍了下自定义View的分类、核心方法及构造方法,下面就来感受下自定义View。

直接先上代码,再进行分析

public class BallView extends View {    private Paint mPaint = null;//画笔对象    private int rX = 200;    private int rY = 200;    public BallView(Context context) {        this(context,null);    }    public BallView(Context context, AttributeSet attrs) {        this(context, attrs,0);    }    public BallView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        init();    }    private void init() {        mPaint = new Paint();        mPaint.setColor(Color.parseColor("#ff0000"));        mPaint.setAntiAlias(true);//设置抗锯齿    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        //画圆,参数1:圆心x坐标,参数2:圆心y坐标 参数3:半径        canvas.drawCircle(rX,rY,100,mPaint);    }    /**     * 触摸事件     * @param event     * @return:true:表示该控件对当前的事件感兴趣,并将后续事件都交给这个控件来进行处理     */    @Override    public boolean onTouchEvent(MotionEvent event) {        switch (event.getAction()){            case MotionEvent.ACTION_DOWN: //手指按下                drawXY(event);                return true;            case MotionEvent.ACTION_MOVE: //手指移动                drawXY(event);                break;            case MotionEvent.ACTION_UP:   //手指抬起                break;        }        return super.onTouchEvent(event);    }    private void drawXY(MotionEvent event){        int x = (int) event.getX();        int y = (int) event.getY();        rX = x;        rY = y;        invalidate();//重绘控件方法,调用后会自动的调用onDraw方法        postInvalidate();//重绘控件方法,通常在子线程中执行    }}

从代码可以看到,我们直接定义一个类来继承了View,并重写了三个构造方法,那么可能你会问,这构造方法里面不是都调用父类的构造方法吗,怎么直接调用自己的不同重载的构造方法?我们都知道,构造方法主要是对类进行一些初始化的操作,上面的构造方法中的写法是在自定义View中一种比较常规的写法。

关于小球的绘制:

首先从我们生活中画画来看,一幅画的组成无非有两个元素组成:画笔、画板。画笔提供了你所要画的东西的颜色啊、大小等,画板提供了你所要画的东西的一个介质。其实我们的自定义View的绘制过程也是这样的,Paint类对应着画笔,Canvas类对应着画板。

由于我们需要在View在绘制一个小球,所以重写了View的onDraw方法,该方法接收一个canvas参数的对象,用于绘制所用。

canvas.drawCircle(rX,rY,100,mPaint);

这里就绘制了一个圆,第一二个参数表示了圆心坐标,第三个参数表示圆的半径,第四个参数也就是我们的画笔对象了。那么我们绘制出来的小球怎么会在View上这样显示了,这涉及到View的坐标系,在Android中View的坐标系如下图:

这里写图片描述

接下来看看最核心的代码

  /**     * 触摸事件     * @param event     * @return:true:表示该控件对当前的事件感兴趣,并将后续事件都交给这个控件来进行处理     */    @Override    public boolean onTouchEvent(MotionEvent event) {        switch (event.getAction()){            case MotionEvent.ACTION_DOWN: //手指按下                drawXY(event);                return true;            case MotionEvent.ACTION_MOVE: //手指移动                drawXY(event);                break;            case MotionEvent.ACTION_UP:   //手指抬起                break;        }        return super.onTouchEvent(event);    }

该方法主要由于处理View的触摸事件的,这里写出了三种触摸类型:手指刚接触屏幕、手指在屏幕上移动、以及手指离开屏幕。这里大家看到对应手指按下的处理,我们直接返回了true,这是为什么?这涉及到View的事件传递机制,返回true就表示了该控件对当前的事件感兴趣,并将后续事件都交给这个控件来进行处理。也就是说当前控件对于手指按下屏幕的事件感兴趣,并且后续的ACTION_MOVE和ACTION_UP事件都将交给该控件来处理。如果我们返回了false或者直接返回父类的super.onTouchEvent(event),就会导致我们无法处理后续的事件了,从而导致我们的ACTION_MOVE和ACTION_UP事件将失效。

最后我们来看一下这个方法:

 private void drawXY(MotionEvent event){        int x = (int) event.getX();        int y = (int) event.getY();        rX = x;        rY = y;        invalidate();//重绘控件方法,调用后会自动的调用onDraw方法        postInvalidate();//重绘控件方法,通常在子线程中执行    }

这里大家又可能会想,有时候看到event.getX(),event.getRawX();event.getY(),event.getRawY()。那么它们到底有啥区别啊?其实很简单,getX()表示我们所绘制出来的东西相对于当前控件的x坐标,而getRawX()表示我们所绘制出来的东西相对于整个屏幕左边的x轴坐标。总结如下:

getX():获取点击事件相对控件左边的x轴坐标,即点击事件距离控件左边的距离

getY():获取点击事件相对控件顶边的y轴坐标,即点击事件距离控件顶边的距离

getRawX():获取点击事件相对整个屏幕左边的x轴坐标,即点击事件距离整个屏幕左边的距离

getRawY():获取点击事件相对整个屏幕顶边的y轴坐标,即点击事件距离整个屏幕顶边的距离

这就是给大家介绍的自定义View入门的一些知识了。

3 0