1、自定义View的属性
2、在View的构造方法中获得我们自定义的属性
[ 3、重写onMesure ]
4、重写onDraw
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中使用自定义属性的话,那么至少重写前两个构造方法!!!
否则会报错(遇到过)
做一些初始化工作,如:
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();
}
重写之前先了解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的其他宽度大小(如画笔宽度、文字大小等)
onDraw()中就靠自己通过Paint、Canvas等API自由发挥了
注意:
1)onDraw()中避免创建对象(如new Paint)
2)onDraw()中避免做耗时操作
<resources>
<declare-styleable name="SuiYi">
<attr name="myviewImg" format="reference" />
declare-styleable>
resources>
declare-styleable name 可以随意命名,不影响
attr name=”myviewImg” 属性名!!!
format的几种格式:
xmlns:custom=”http://schemas.android.com/apk/com.example.zsign”
切记添加命名空间 格式为 schemas.android.com/apk/ + 包名
<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”
// 初始化属性
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退出时应停止属性动画,避免内存泄漏