Android自定义View初步(一)

一、效果图

Android自定义View初步(一)_第1张图片

二、知识点Get

一)自定义View的步骤

1、自定义View的属性
2、在View的构造方法中获得我们自定义的属性
[ 3、重写onMesure ]
4、重写onDraw

注意点

1、重写构造方法:

1)public View (Context context) 是在java代码创建视图的时候被调用,如果是从xml填充的视图,就不会调用这个,在代码里new的话用这个构造方法就OK了!
2)public View (Context context, AttributeSet attrs) 调用2个参数的 attr里边传过来的是 xml里边对应的height width等参数,包括自己定义的参数,如果在xml里边写入自定义控件的话 必须要重写2个参数的构造函数
3)public View (Context context, AttributeSet attrs, int defStyle) 传style的吧貌似

所以如果要在xml中使用自定义属性的话,那么至少重写前两个构造方法!!!
否则会报错(遇到过)

2、构造方法中应该做些神马?

做一些初始化工作,如:

1)一些new 操作,如new paint,避免在onDraw()中重复new 消耗资源
2)通过xml初始化自定义属性

姿势如下:

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

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

    public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr); 
        mContext = context;
        init(attrs, defStyleAttr);
    }

private void init(AttributeSet attrs, int defStyleAttr){
        //圆弧画笔
        mPaintArc = new Paint();
        mPaintArc.setColor(0x55000000);
        mPaintArc.setAntiAlias(true);
        mPaintArc.setStyle(Style.STROKE);
        mPaintArc.setTextSize(56);

        recArc = new RectF();

        //图片画笔
        mPaintBit = new Paint();
        mPaintBit.setAntiAlias(true);

        // 初始化属性
        if (attrs != null){
            int  slideButtonResId= attrs.getAttributeResourceValue(NAMESPACE, "myviewImg", -1);
            bitmap = BitmapFactory.decodeResource(getResources(), slideButtonResId);
        }

        recBit = new RectF();

        //属性动画
        percentAnimator = ValueAnimator.ofInt(0, 360);
        percentAnimator.addUpdateListener(newValueAnimator.AnimatorUpdateListener(){
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                percentArc = (Integer) animation.getAnimatedValue();
                invalidate();
            }
        });

        percentAnimator.setDuration(2000);
        percentAnimator.setRepeatCount(-1);  //循环次数
        percentAnimator.setInterpolator(new LinearInterpolator());  //线性插值器
        percentAnimator.start();
    }

3、重写onMeasure

重写之前先了解MeasureSpec的specMode,一共三种类型:

EXACTLY:一般是设置了明确的值或者是MATCH_PARENT
AT_MOST:表示子布局限制在一个最大值内,一般为WARP_CONTENT
UNSPECIFIED:表示子布局想要多大就多大,很少使用

由于我的要求不高,可在xml中指定宽高具体值即可
so:

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // TODO Auto-generated method stub
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        width = MeasureSpec.getSize(widthMeasureSpec);
        height = MeasureSpec.getSize(heightMeasureSpec);

        widthArc = width/10;   //基于控件宽度的十分之一
        recArc.set(widthArc*0.5f, widthArc*0.5f, width - widthArc*0.5f, height - widthArc*0.5f);

        recBit.set(widthArc*0.5f, widthArc*0.5f, width - widthArc*0.5f, height - widthArc*0.5f);

        setMeasuredDimension(width, height);
    }

注意:在onMeasure中获取控件的宽高,可以基于控件的宽高去设置View的其他宽度大小(如画笔宽度、文字大小等)

4、重写onDraw()

onDraw()中就靠自己通过Paint、Canvas等API自由发挥了
注意:
1)onDraw()中避免创建对象(如new Paint)
2)onDraw()中避免做耗时操作

三)为自定义控件添加属性

1、在attrs.xml中定义属性


<resources>
    <declare-styleable name="SuiYi">
         <attr name="myviewImg" format="reference" />
    declare-styleable>

resources>

declare-styleable name 可以随意命名,不影响
attr name=”myviewImg” 属性名!!!

format的几种格式:

  • reference:参考某一资源ID
  • color:颜色值
  • boolean:布尔值
  • string:字符串
  • …..等等

2、布局中使用

1)命名空间

xmlns:custom=”http://schemas.android.com/apk/com.example.zsign”
切记添加命名空间 格式为 schemas.android.com/apk/ + 包名

2)使用

<com.example.zsign.MyView
        android:id="@+id/myview"
        android:layout_width="100dp"
        android:layout_height="100dp"
        custom:myviewImg="@drawable/ic_launcher" />

custom:myviewImg=”@drawable/ic_launcher”

3、自定义View中获取属性值

通过AttributeSet attrs获取属性值

// 初始化属性
        if (attrs != null){
            int  slideButtonResId= attrs.getAttributeResourceValue(NAMESPACE, "myviewImg", -1);
            bitmap = BitmapFactory.decodeResource(getResources(), slideButtonResId);
        }

具体请参考AttributeSet API

四)属性动画的使用

属性动画通过动态地改变对象的属性从而达到动画效果

//属性动画
        percentAnimator = ValueAnimator.ofInt(0, 360);
        percentAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                percentArc = (Integer) animation.getAnimatedValue();
                invalidate();
            }
        });

        percentAnimator.setDuration(2000);
        percentAnimator.setRepeatCount(-1);  //循环次数
        percentAnimator.setInterpolator(new LinearInterpolator());  //线性插值器
        percentAnimator.start();

通过动态的改变属性值,再进行重绘invalidate()达到动画效果
这里体现出了属性动画相较于View动画的优越性

注意:
1)在主线程中start()属性动画
2)invalidate()和postInvalidate()的区别
3)Activity退出时应停止属性动画,避免内存泄漏

你可能感兴趣的:(Android自定义View)