美文网首页
Android自定义view初识(二)

Android自定义view初识(二)

作者: wt龙 | 来源:发表于2016-10-31 13:40 被阅读53次

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

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

首先先了解下自定义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;
      }


}

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

相关文章

网友评论

      本文标题:Android自定义view初识(二)

      本文链接:https://www.haomeiwen.com/subject/bfcduttx.html