前面讲到,自绘控件就是一块显示区域而已,绘制完了之后再想更改界面,就必须使用invalidate方法。
postInvalidate方法和invalidate方法都能够使得界面刷新。
1:我们先看一下postInvalidate方法,里面只有一句,调用postInvalidateDelayed方法:
AttachInfo 是个啥呢?a set of information given to a view when it is attached to its parent window,
dispatchInvalidateDelayed会使用view的ViewRootHandler 发送一条信息到消息队列的末端,处理信息时,调用view的invalidate方法。所以,postInvalidate方法最终会调用invalidate方法。
2:invalidate方法,该方法会使得view树重绘。如果你更改了某些属性值,重绘的时候就会直观的看到。所以,让你的view动起来的level1
方案就是改变属性值然后invalidate,每次改变一点点,就能使view缓慢的动起来。
光说不练家把什,先上效果图:
动态效果就是随着手指的移动,它会跟着你动。支持许多自定义属性,可以满足需要从零到100%选择的所有需求,如音量,满意度等。支持各种自定义
MyStandardView上一个坑里已经介绍过了。
public class MyView_ArcScale extends MyStandardView {
private int smaller;
private int finalHeight;
private int finalWidth;
private float mScale = 0;//degree
private int inCricleColor = Color.BLUE;
private int outArcColor = Color.GREEN;
private int textColor = Color.BLACK;
private float outArcWidth = 20;
private int startDegree = 0;//degree
private float testSize = 15;
private Paint mPaint;
private float halfHeight; //圆心坐标
private float halfWidth;//圆心坐标
public MyView_ArcScale(Context context) {
this(context, null, 0);
}
public MyView_ArcScale(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MyView_ArcScale(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
final TypedArray typedArray = context.obtainStyledAttributes(attrs,
R.styleable.MyView_ArcScale);
this.inCricleColor = typedArray.getColor(R.styleable.MyView_ArcScale_inCircleColor, inCricleColor);
this.outArcColor = typedArray.getColor(R.styleable.MyView_ArcScale_outArcColor, outArcColor);
this.textColor = typedArray.getColor(R.styleable.MyView_ArcScale_testColor, textColor);
this.outArcWidth = typedArray.getDimension(R.styleable.MyView_ArcScale_outArcWidth, outArcWidth);
this.startDegree = typedArray.getInt(R.styleable.MyView_ArcScale_degreeStart, startDegree);
this.testSize = typedArray.getDimension(R.styleable.MyView_ArcScale_testSize, testSize);
typedArray.recycle();//回收资源
mPaint = new Paint();
this.mScale=startDegree;//初始时默认不画外部弧形。
}
@Override
public int getDefaultHeight() {
return 200;
}
@Override
public int getDefaultWidth() {
return 200;
}
/**
*
* @param mScale >0且<360
*/
public void setmScale(float mScale) {
if(mScale<0||mScale>360){
try {
throw new Exception("mScale must between 0-360");
} catch (Exception e) {
e.printStackTrace();
}
return;
}
this.mScale = mScale;
postInvalidate();
}
/**
*
* @param startDegree 三点钟方向为0,顺时针为正向
*/
public void setStartDegree(int startDegree) {
if(mScale<0||mScale>360){
try {
throw new Exception("startDegree must between 0-360");
} catch (Exception e) {
e.printStackTrace();
}
return;
}
this.startDegree = startDegree;
postInvalidate();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
finalHeight = getFinalHeight();
finalWidth = getFinalWidth();
smaller = finalHeight > finalWidth ? finalWidth : finalHeight;
int radiusIn = smaller / 4;
int radiusOut = smaller / 2;
halfHeight = finalHeight / 2;
halfWidth = finalWidth / 2;
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(inCricleColor);
canvas.drawCircle(halfWidth, halfHeight, radiusIn, mPaint);
mPaint.setStrokeWidth(this.outArcWidth);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(this.outArcColor);
float magin = outArcWidth / 2;
RectF mRectF = new RectF(
(halfWidth - radiusOut + magin),
(halfHeight - radiusOut + magin),
(halfWidth + radiusOut - magin),
(halfHeight + radiusOut - magin));
canvas.drawArc(mRectF, this.startDegree, mScale, false, mPaint);
//消除字体锯齿
mPaint.setStrokeWidth(2);
mPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(this.textColor);
mPaint.setTextSize(this.testSize);
canvas.drawText(((int)(mScale / 360 * 100) + "") + "%",
halfWidth - testSize,
halfHeight - testSize,
mPaint);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float xCricle= event.getX()-halfWidth;//相对于圆心的坐标
float yCricle=halfHeight-event.getY();
// 圆心坐标xr,yr 三点钟方向为0,顺时针为正向
// 当前坐标x,y
//求当前坐标所代表的度数。
//startdegree
float tan= Math.abs( yCricle/xCricle);
float result= (float) Math.toDegrees( Math.atan(tan));
// L.d("---aaa"+result);
/**
* 以三点钟为起始,以顺时针为正向,点击点的度数。
*/
float fDegree=0;
if(xCricle==0&&yCricle==0){
return true;
}
else if(xCricle==0&&yCricle!=0){
if(yCricle>0)fDegree=270;
else fDegree=90;
}
else if(xCricle!=0&&yCricle==0){
if(xCricle>0)fDegree=0;
else fDegree=180;
}
else if(xCricle>0&&yCricle<0){
fDegree=result;
// L.d("1");
}
else if(xCricle<0&&yCricle<0){
fDegree=180-result;
// L.d("2");
}
else if(xCricle<0&&yCricle>0){
fDegree=result+180;
// L.d("3");
}
else if(xCricle>0&&yCricle>0){
fDegree=360-result;
// L.d("4");
}
// L.d(event.getX()+"---is"+halfWidth+"---is"+xCricle+"----is"
// +event.getY()+"---is"+halfHeight+"---is"+yCricle+"----is"+result);
float lastmScale=mScale;
float newmScale=0;
//改变mscale的值,使得外层弧线参数改变
if(fDegree<startDegree)newmScale= (float) (360-(startDegree-fDegree));
else newmScale= (float) (fDegree-startDegree);
mScale=newmScale;
invalidate();
// L.d(fDegree+"");
return true;
}
}
attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="MyView_ArcScale">
<attr name="inCircleColor" format="reference" />
<attr name="outArcColor" format="reference" />
<attr name="testColor" format="reference" />
<attr name="outArcWidth" format="dimension" />
<attr name="testSize" format="dimension" />
<attr name="degreeStart" format="integer" />
</declare-styleable>
</resources>
and,布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/aaaaa">
<com.example.administrator.ysdgo.weidget.MyView_ArcScale
android:layout_width="300dp"
android:layout_height="300dp"
android:layout_gravity="center_vertical"
android:padding="10dp"
app:inCircleColor="@color/colorAccent"
app:outArcColor="@color/cc_dot_orage"
app:degreeStart="90"
android:id="@+id/myview_arcScale"
/>
</LinearLayout>
复杂的地方就在于坐标的转化啦哈哈,然鹅也不是很复杂,就是获得事件发生的点后去计算角度,然后设置角度,然后invalidate方法。
注意:画弧线的起始角度是三点钟方向,正向是顺时针。