安卓自定义View介绍使用

来源:互联网 发布:远程教育软件哪家好 编辑:程序博客网 时间:2024/05/22 10:53

1.自定义View介绍:
自定义View我们大部分时候只需重写两个函数:onMeasure()、onDraw()。onMeasure负责对当前View的尺寸进行测量,onDraw负责把当前这个View绘制出来。当然了,你还得写至少写2个构造函数:

public MyView(Context context) {        super(context);    }    public MyView(Context context, AttributeSet attrs) {        super(context, attrs);     }

关于onMeasure,我们为什么需要测量?
我们平时写view的大小无非三种情况:而是wrap_content或者是match_parent或者指定大小,那么自定义view为什么还需要来测量宽高呢,我们知道将尺寸设置为“包住内容”和“填充父布局给我们的所有空间”,但是这两个设置并没有指定真正的大小,可是我们绘制到屏幕上的View必须是要有具体的宽高的,正是因为这个原因,我们必须自己去处理和设置尺寸。当然了,View类给了默认的处理,但是如果View类的默认处理不满足我们的要求,我们就得重写onMeasure函数啦~。这里举个例子,比如我们希望我们的View是个正方形,如果在xml中指定宽高为wrap_content,如果使用View类提供的measure处理方式,显然无法满足我们的需求。
我们重写的onMeasure()函数是:

protected void onMeasure(int widthMeasureSpec, int                         heightMeasureSpec)

我们可以通过:

int widthMode = MeasureSpec.getMode(widthMeasureSpec);int widthSize = MeasureSpec.getSize(widthMeasureSpec);

取得我们需要的测量模式和大小。
其中测量模式有三种:

测量模式 ——————– 表示意思
UNSPECIFIED ————-父容器没有对当前View有任何限制,当前View可以任意取尺寸
EXACTLY————— 当前的尺寸就是当前View应该取的尺寸
AT_MOST————— 当前尺寸是当前View能取的最大尺寸

而上面的测量模式跟我们的布局时的wrap_content、match_parent以及写成固定的尺寸有什么对应关系呢?

match_parent—>EXACTLY。怎么理解呢?match_parent就是要利用父View给我们提供的所有剩余空间,而父View剩余空间是确定的,也就是这个测量模式的整数里面存放的尺寸。
wrap_content—>AT_MOST。怎么理解:就是我们想要将大小设置为包裹我们的view内容,那么尺寸大小就是父View给我们作为参考的尺寸,只要不超过这个尺寸就可以啦,具体尺寸就根据我们的需求去设定。
固定尺寸(如100dp)—>EXACTLY。用户自己指定了尺寸大小,我们就不用再去干涉了,当然是以指定的大小为主啦。

1. 感受一下onMeasure的使用,假设我们要实现这样一个效果:将当前的View以正方形的形式显示,即要宽高相等,并且默认的宽高值为100像素。就可以这些编写:

private int getMySize(int defaultSize, int measureSpec) {        int mySize = defaultSize;        int mode = MeasureSpec.getMode(measureSpec);        int size = MeasureSpec.getSize(measureSpec);        switch (mode) {            case MeasureSpec.UNSPECIFIED: {//如果没有指定大小,就设置为默认大小                mySize = defaultSize;                break;            }            case MeasureSpec.AT_MOST: {//如果测量模式是最大取值为size                //我们将大小取最大值,你也可以取其他值                mySize = size;                break;            }            case MeasureSpec.EXACTLY: {//如果是固定的大小,那就不要去改变它                mySize = size;                break;            }        }        return mySize;}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        int width = getMySize(100, widthMeasureSpec);        int height = getMySize(100, heightMeasureSpec);        if (width < height) {            height = width;        } else {            width = height;        }        setMeasuredDimension(width, height);}

我们设置一下布局

<com.hc.studyview.MyView        android:layout_width="match_parent"        android:layout_height="100dp"        android:background="#ff0000" />

看看使用了我们自己定义的onMeasure函数后的效果:
自定义View
这里写图片描述
而如果我们不重写onMeasure,效果则是如下:
这里写图片描述

2. 重写onDraw开始画图
我们要View显示一个圆形,由于我们在上面已经实现了宽高尺寸相等,下面就简单了:

@Override    protected void onDraw(Canvas canvas) {        //调用父View的onDraw函数,因为View这个类帮我们实现了一些        // 基本的而绘制功能,比如绘制背景颜色、背景图片等        super.onDraw(canvas);        int r = getMeasuredWidth() / 2;//也可以是getMeasuredHeight()/2,本例中我们已经将宽高设置相等了        //圆心的横坐标为当前的View的左边起始位置+半径        int centerX = getLeft() + r;        //圆心的纵坐标为当前的View的顶部起始位置+半径        int centerY = getTop() + r;        Paint paint = new Paint();        paint.setColor(Color.GREEN);        //开始绘制        canvas.drawCircle(centerX, centerY, r, paint);    }

这里写图片描述

3. 使用自定义布局属性
可以在布局文件中由用户写属性,
自定义View的属性,首先在res/values/ 下建立一个attrs.xml , 在里面定义我们的属性和声明我们的整个样式。

<?xml version="1.0" encoding="utf-8"?>  <resources>      <attr name="titleText" format="string" />      <attr name="titleTextColor" format="color" />      <attr name="titleTextSize" format="dimension" />      <declare-styleable name="CustomTitleView">          <attr name="titleText" />          <attr name="titleTextColor" />          <attr name="titleTextSize" />      </declare-styleable>  </resources>  

或者这样写:

<resources> <declare-styleable name="CustomTitleView"> <attr name="titleText" format="string" /> <attr name="titleTextColor" format="color" /> <attr name="titleTextSize" format="dimension" /> </declare-styleable> </resources>

第一种写法可以提供共用属性的,当自定义view多时,很有用的。

我们定义了字体,字体颜色,字体大小3个属性,format是值该属性的取值类型:一共有:string,color,demension,integer,enum,reference,float,boolean,fraction,flag;不清楚的可以google一把。
然后在布局中声明我们的自定义View

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"      xmlns:tools="http://schemas.android.com/tools"      xmlns:custom="http://schemas.android.com/apk/res/com.example.customview01"      android:layout_width="match_parent"      android:layout_height="match_parent" >      <com.example.customview01.view.CustomTitleView          android:layout_width="200dp"          android:layout_height="100dp"          custom:titleText="3712"          custom:titleTextColor="#ff0000"          custom:titleTextSize="40sp" />  </RelativeLayout>  

一定要引入

xmlns:custom=”http://schemas.android.com/apk/res/com.example.customview01”

我们的命名空间,后面的包路径指的是项目的package
然后在View的构造方法中,获得我们的自定义的样式

/**      * 文本      */      private String mTitleText;      /**      * 文本的颜色      */      private int mTitleTextColor;      /**      * 文本的大小      */      private int mTitleTextSize;      /**      * 绘制时控制文本绘制的范围      */      private Rect mBound;      private Paint mPaint;      public CustomTitleView(Context context, AttributeSet attrs)      {          this(context, attrs, 0);      }      public CustomTitleView(Context context)      {          this(context, null);      }      /**      * 获得我自定义的样式属性      *       * @param context      * @param attrs      * @param defStyle      */      public CustomTitleView(Context context, AttributeSet attrs, int defStyle)      {          super(context, attrs, defStyle);          /**          * 获得我们所定义的自定义样式属性          */          TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomTitleView, defStyle, 0);          int n = a.getIndexCount();          for (int i = 0; i < n; i++)          {              int attr = a.getIndex(i);              switch (attr)              {              case R.styleable.CustomTitleView_titleText:                  mTitleText = a.getString(attr);                  break;              case R.styleable.CustomTitleView_titleTextColor:                  // 默认颜色设置为黑色                  mTitleTextColor = a.getColor(attr, Color.BLACK);                  break;              case R.styleable.CustomTitleView_titleTextSize:                  // 默认设置为16sp,TypeValue也可以把sp转化为px                  mTitleTextSize = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(                          TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));                  break;              }          }          a.recycle();          /**          * 获得绘制文本的宽和高          */          mPaint = new Paint();          mPaint.setTextSize(mTitleTextSize);          // mPaint.setColor(mTitleTextColor);          mBound = new Rect();          mPaint.getTextBounds(mTitleText, 0, mTitleText.length(), mBound);      }

我们重写了3个构造方法,默认的布局文件调用的是两个参数的构造方法,所以记得让所有的构造调用我们的三个参数的构造,我们在三个参数的构造中获得自定义属性。

更多高级用法参考:http://blog.csdn.net/huachao1001/article/details/51577291

–>路要一步一步走,记住自己走过的路,不再犯同样的错误,才是真正的成长!欢迎指点、交流。<–

0 0
原创粉丝点击