Android自定义view初识(一)

爱哥的自定义View其实很简单
鸿洋大神的Android自定义view
Android群英传(徐宜生)

自定义View这件事,确实如鸿洋大神所说,对于新手来说是一件比较恐怖的事情。比如在下这只小菜鸟,一直想好好学习自定义View,却又总是半途而废。这一次,一定坚持掌握自定义View技巧。

那么让我们进入正题:
在学习自定义View之前,先让我们了解一下Android的控件架构

在Android中,控件大致被分为两类:VIew和ViewGroup。
ViewGroup作为父控件,可以包含多个View,并对其进行管理。通过ViewGroup,整个界面上就形成了一个控件树,上层控件负责对下层控件的测量和绘制。并且传递交互事件。通常,我们用到的findviewById就是通过遍历控件树来寻找对应的元素。

view树结构
UI界面架构图

好的,简单的了解一下,让我们进入正题,究竟如何实现自定义view呢。
在Android中,自定义View必定是继承View或者是VIew的子控件,如:Button、TextView等等。

首先我们继承自VIew。

public class MyCircle extends View {
}

IDE主动提示我们要声明构造方法;


 public CustomCircle(Context context) {
            this(context, null);
      }
//此构造方法解析Android自带的属性
      public CustomCircle(Context context, AttributeSet attrs) {
            this(context, attrs, 0);

      }
//此构造方法解析自定义的属性
      public CustomCircle(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);    
      }

我们重写了三个构造方法,将前两个方法中的super该为this,如果不改的话,会在onDraw中使用画笔的时候报空指针异常,因为根本走不到第三个构造方法。

接下来我们先重写onDraw方法,

 @Override
      protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
      }

当我们要画一些什么的时候,我们就要在这个方法中进行操作,在现实生活中,我们如果想要画画的话,首先需要的就是画笔和画板。当然,Android也给我们提供了Paint和Canvas,一个是画笔,当然另一个就是画布啦。我们可以看到,在onDraw方法中,画布Canvas是作为参数传递进了这个方法中,也就是说这个画布是Android为我们准备好的,我们不用去管就是了。

好了,现在有了画布,我们还需要一个画笔Paint,
在爱哥的博客中我们知道,因为Android不建议我们在draw和layout的过程中去初始化话画笔,因为这两个过程可能是需要频繁进行重复操作的过程,我们知道new是需要分配内存空间的,如果我们如此频繁的去进行new操作,内存会不会爆呢?这个我们并不知道,但浪费内存这个确实可以肯定的。所以Android不建议我们在这两个过程中初始化画笔。
那我们就在构造方法中实例化对象

  public CustomCircle(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            mContext = context;
            initPaint();

      }

      private void initPaint() {

            //初始化画笔并打开抗锯齿模式
            mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            /*
         * 设置画笔样式为描边并填充
         *
         * 画笔样式分三种:
         * 1.Paint.Style.STROKE:描边(圆环嘛)
         * 2.Paint.Style.FILL_AND_STROKE:描边并填充
         * 3.Paint.Style.FILL:填充
         */
            mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
            // 设置画笔颜色为黄色
            mPaint.setColor(Color.YELLOW);
            /*
         * 设置描边的粗细,单位:像素px
         * 注意:当setStrokeWidth(0)的时候描边宽度并不为0而是只占一个像素
         */
          //  mPaint.setStrokeWidth(10);
      }

现实中的画笔,我们可以去挑选颜色、类型等等等等各种属性,当然在Android我们也可以去设置paint的各种属性,现实中有的,Android有,现实中没有的,Android还有。


Paint.set

当然,Paint集成了画的属性,那么Canvas就定义了我们所要画的东西。

Canvas.draw
@Overrideprotected void onDraw(Canvas canvas) {      super.onDraw(canvas);    
/*
* 画一个圆,
* 第一个参数为水平方向的中心坐标
* 第二个参数为垂直方向的中心坐标
* 第三个参数为圆的半径
* 第四个参数为我们的画笔
* */
  canvas.drawCircle(MeasureUtil.getScreenSize((Activity) mContext)[0] / 2, 300, radiu, mPaint);      }

现在我们的圆是确确实实的画出来了

按照爱哥的想法,我们现在要实现让圆从小到大不断的变化。
就这样我们让我们的class实现了Runnable方法,

 @Override
      public void run() {
             /*
     * 确保线程不断执行不断刷新界面
     */
            while (true) {
                  try {
            /*
             * 如果半径小于200则自加否则大于200后重置半径值以实现往复
             */
                        if (radiu <= 200) {
                              radiu += 10;

                              // 刷新View
                              postInvalidate();
                        } else {
                              radiu = 0;
                        }

                        // 每执行一次暂停40毫秒
                        Thread.sleep(40);
                  } catch (InterruptedException e) {
                        e.printStackTrace();
                  }
            }
      }

在activity中启动线程:

new Thread(mCustomView).start();

完整代码

package com.bx.myproject.MyView;

import android.app.Activity;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;

import com.bx.myproject.R;

public class CustomCircle extends View implements Runnable{

      private Context mContext;//上下文引用
      private Paint mPaint;  //画笔
      private String mText;
      private int mTextColor;
      private int mTextSize;

      private int radiu;// 圆环半径

      public CustomCircle(Context context) {
            this(context, null);
      }

      public CustomCircle(Context context, AttributeSet attrs) {
            this(context, attrs, 0);

      }

      public CustomCircle(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            mContext = context;
            initPaint();

      }

      private void initPaint() {

            //初始化画笔并打开抗锯齿模式
            mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            /*
         * 设置画笔样式为描边,圆环嘛……当然不能填充不然就么意思了
         *
         * 画笔样式分三种:
         * 1.Paint.Style.STROKE:描边
         * 2.Paint.Style.FILL_AND_STROKE:描边并填充
         * 3.Paint.Style.FILL:填充
         */
            mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
            // 设置画笔颜色为浅灰色
            mPaint.setColor(Color.YELLOW);
            /*
         * 设置描边的粗细,单位:像素px
         * 注意:当setStrokeWidth(0)的时候描边宽度并不为0而是只占一个像素
         */
          //  mPaint.setStrokeWidth(10);

      }


      @Override
      protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
/*
* 画一个圆,
* 第一个参数为水平方向的中心坐标
* 第二个参数为垂直方向的中心坐标
* 第三个参数为圆的半径
* 第四个参数为我们的画笔
* */
            canvas.drawCircle(MeasureUtil.getScreenSize((Activity) mContext)[0] / 2, 300, radiu, mPaint);

      }

      @Override
      public void run() {
             /*
     * 确保线程不断执行不断刷新界面
     */
            while (true) {
                  try {
            /*
             * 如果半径小于200则自加否则大于200后重置半径值以实现往复
             */
                        if (radiu <= 200) {
                              radiu += 10;

                              // 刷新View
                              postInvalidate();
                        } else {
                              radiu = 0;
                        }

                        // 每执行一次暂停40毫秒
                        Thread.sleep(40);
                  } catch (InterruptedException e) {
                        e.printStackTrace();
                  }
            }
      }
}

Canvas的常用绘制方法:

方法 作用
drawRect() 画矩形
drawCircle() 画圆形
drawArc() 画圆弧
drawBitmap() 画Bitmap
drawOval() 画椭圆
drawRoundRect() 画圆角矩形

好吧,现在我们多少了解了一下自定义View,这仅仅是个开始。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,013评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,205评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,370评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,168评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,153评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,954评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,271评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,916评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,382评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,877评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,989评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,624评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,209评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,199评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,418评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,401评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,700评论 2 345

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,498评论 25 707
  • 一、概述 1. 四线格与基线 小时候,我们在刚开始学习写字母时,用的本子是四线格的,我们必须把字母按照规则写在四线...
    addapp阅读 7,609评论 2 17
  • 1.使用使用编译器提供的宏来操作 2.关闭某一个指定文件的某种指定类型的警告 双击 文件, 在其中添加 -Wno...
    MisterZhai阅读 427评论 0 0
  • 新年后上班第一天开始阅读《于丹趣品人生》。央视名嘴白岩松为书作序,序中摘抄:远方的事,只是一面镜子;当下的路,还得...
    楚歌儿阅读 302评论 0 1
  • 有些事我并不想对你说 因为我害怕你会想太多 有时候你并不懂我的心情 我希望你可以多了解我一点 我知道我有一颗只在乎...
    你深情他一往阅读 515评论 0 1