Android自定义view初识(二)

其实这一篇的代码是在一个周之前学习的,这里做复习用吧。

首先 我们了解一下自定义控件的一些属性以及用法:

首先先了解下自定义view的属性吧:

目前已知的属性:
reference 资源类型,通常是@开头,例如@+id/XXXX
string 字符串类型,通常是文字信息
dimension 浮点类型,通常是尺寸度量
color 颜色类型 通常是颜色16进制代码,支持ARBG
boolean 布尔类型 true和false
enum 枚举类型,通常是代表这个属性提供了几种值来进行选择,并且只能选择这几种中的一个
flag 与enum基本没有区别。
integer 整数类型,通常是整数

在values文件夹下新建attrs.xml :写法如下

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <attr name="viewtext" format="string"/>
    <attr name="viewSize"  format="dimension"/>
    <attr name="viewColor" format="color"/>
    <attr name="isCircle" format="boolean"/>
<!-- 如果即支持string 又支持reference的话--!>
<!--  <attr name="this" format="string|reference"/>--!>

    <declare-styleable name="customText">
        <attr name="viewtext"/>
        <attr name="viewSize"/>
        <attr name="viewColor"/>
        <attr name="isCircle"/>
    </declare-styleable>

</resources>

在这里我定义了控件的text 、大小、颜色、和一个布尔值 。这些属性
那么在attrs中定义了属性的话,我们如何在代码中获得这些属性呢:

记得在自定义view时重写的三个构造方法,第三个构造方法便是用来解析自定义属性的:

 public MyCustom(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            mContext = context;
            // 使用context对象获得我们自定义的属性的值,attrs是我们xml中使用的属性集合,其中包括属性名和属性值等相关信息,后面是我们自定义的属性,也就是我们定义的declare-styleable。
            TypedArray typedArray = mContext.obtainStyledAttributes(attrs, R.styleable.customText);

            // 使用相应的方法获取各个类型属性的值,第二个参数是获取不到属性值默认的属性值。
            mText = typedArray.getString(R.styleable.customText_viewtext);

            mTextSize = typedArray.getDimension(R.styleable.customText_viewSize, 16);
            mTextColor = typedArray.getColor(R.styleable.customText_viewColor, Color.BLACK);
            isCircle = typedArray.getBoolean(R.styleable.customText_isCircle, false);

            // 没啥,google推荐的,使用完及时释放
            typedArray.recycle();

            initPaint();
      }

下面是我复习的一点Paint的用法和自定义view测量大小写的一点东西:

当时我是画了一个圆,然后呢,我在想,能不能再圆上写上字,然后让字居中显示,我在xml中写了:

android:text="HELLO"

发现然并卵,然后我发现,我们要在代码中给控件画上字,然后设置文字的显示位置,这里还用到了一点字体测量的知识(FontMetrics这个和字体相关的重要的类),然后为了证实我们的居中位置判断的没错,特意给控件画上了一条中心线。
关于字体测量这一块:
爱哥的自定义控件其实很简单有非常详细非常全面的介绍 。

效果如下图

Paste_Image.png
public class MyCustom extends View {

      private Context mContext;
      private String mText;
      private float mTextSize;
      private boolean isCircle;
      private int mTextColor;

      private Paint mPaint;

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

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

      public MyCustom(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            mContext = context;
            // 使用context对象获得我们自定义的属性的值,attrs是我们xml中使用的属性集合,其中包括属性名和属性值等相关信息,后面是我们自定义的属性,也就是我们定义的declare-styleable。
            TypedArray typedArray = mContext.obtainStyledAttributes(attrs, R.styleable.customText);

            // 使用相应的方法获取各个类型属性的值,第二个参数是获取不到属性值默认的属性值。
            mText = typedArray.getString(R.styleable.customText_viewtext);

            mTextSize = typedArray.getDimension(R.styleable.customText_viewSize, 16);
            mTextColor = typedArray.getColor(R.styleable.customText_viewColor, Color.BLACK);
            isCircle = typedArray.getBoolean(R.styleable.customText_isCircle, false);

            // 没啥,google推荐的,使用完及时释放
            typedArray.recycle();

            initPaint();
      }

      private void initPaint() {

            mPaint = new Paint();
            mPaint.setStyle(Paint.Style.FILL_AND_STROKE);

      }


      @Override
      protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            //测量控件的宽和高
            setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));
      }

      @Override
      protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
          //在这里判断是绘制圆形还是正方形
            if (isCircle) {
                /*  
                * 1.先画圆,
                *  2.其次 文字
                */
                  mPaint.setColor(Color.GRAY);
                    //画圆,这里的参数是: 圆心的坐标x,y,圆的半径,和画笔
                  canvas.drawCircle(canvas.getWidth() / 2, canvas.getHeight() / 2, canvas.getHeight() / 2, mPaint);

                  mPaint.setColor(mTextColor);
                  mPaint.setTextSize(mTextSize);
                  //文字的x轴坐标
                  //获取text的宽度 (Paint.measureText()这个方法可以直接获取text的宽度)
                  float textWidth = mPaint.measureText(mText);
                  //计算text开始的横坐标:  圆半径/2  -  text宽度/2
                  float x = (canvas.getWidth() - textWidth) / 2;
                  //文字的y轴坐标 (这里用到FontMetrics不详细注释,之后会详细学习这一块)
                  Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();
                  float y = canvas.getHeight() / 2 + (Math.abs(fontMetrics.ascent) - fontMetrics.descent) / 2;
                  canvas.drawText(mText, x, y, mPaint);//这里的y是指的text的基线的位置


            } else {
                  mPaint.setColor(Color.GRAY);
                  float left = getLeft();
                  float top = getTop();
                  float bottom = getBottom();
                  float right = getRight();
                  canvas.drawRect(left, top, right, bottom, mPaint);

                  //     Log.i("NUM-->", canvas.getDensity()+"");

                  mPaint.setColor(mTextColor);
                  mPaint.setTextSize(mTextSize);
                  float textWidth = mPaint.measureText(mText);
                  float x = canvas.getWidth() / 2 - textWidth / 2;

                  Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();
                  float y = canvas.getHeight() / 2 + (Math.abs(fontMetrics.ascent) - fontMetrics.descent) / 2;

                  canvas.drawText(mText, x, y, mPaint);
            }

            //画出控件的水平中心线
            mPaint.setColor(Color.YELLOW);
            // float startX, float startY, float stopX, float stopY,
            canvas.drawLine(0, canvas.getHeight() / 2, canvas.getWidth(), canvas.getHeight() / 2 + 1, mPaint);
      }


      private int measureWidth(int widthMeasureSpec) {

            int result;
            int specMode = MeasureSpec.getMode(widthMeasureSpec);
            int specSize = MeasureSpec.getSize(widthMeasureSpec);

            if (specMode == MeasureSpec.EXACTLY) {

                  result = specSize;
            } else {

                  result = 200;
                  if (specMode == MeasureSpec.AT_MOST) {
                        result = Math.min(result, specSize);

                  }
            }

            return result;
      }


      private int measureHeight(int heightMeasureSpec) {
            int result;

            int specMode = MeasureSpec.getMode(heightMeasureSpec);
            int specSize = MeasureSpec.getSize(heightMeasureSpec);

          /*  根据测量模式和设置的大小来进行测量
          *       测量模式有三种类型
          *       1、EXACTLY 精确模式。用户设置了精确的宽和高或者是设置了match_parent充满父控件
          *       2、AT_MOST  用户设置了warp_content
          *       3.UNSPECTIFIED 什么都不设置。一般是画的控件
          * */

            if (specMode == MeasureSpec.EXACTLY) {
              //如果用户设置的精确模式,则返回用户设置的值
                  result = specSize;

            } else {
          //如果用户没有设置精确模式,那么我们首先定义一个标准值,
                  result = 200;
                  if (specMode == MeasureSpec.AT_MOST) {
                        result = Math.min(result, specSize);
                  }

            }

            return result;
      }


}

本人菜鸟,正在努力学习中。。有什么错误,希望大家指导。

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

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,421评论 25 707
  • 6、View的绘制 (1)当测量好一个View之后,我们就可以简单的重写 onDraw()方法,并在 Canvas...
    b5e7a6386c84阅读 1,875评论 0 3
  • View的继承关系 Android中所有控件,都是View或View的子类,比如开发中最常写的代码 findVie...
    四月一号阅读 696评论 1 3
  • 走出医院时,晚心无意识的向医院的东边看了看,那是火车站的方向,他依旧没有出现在晚心的视线里。 晚心抬头看着乌云密布...
    小鱼叔阅读 525评论 1 2
  • 最近看的电影部部都让我落泪。 本以为看个温情的喜剧电影不会再哭。 结果,哭得更难过了。 一 四口之家三人都有听说障...
    一隻兔几阅读 342评论 1 2