一、效果图
二、知识点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中定义属性
<?xml version="1.0" encoding="utf-8"?>
<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退出时应停止属性动画,避免内存泄漏