Android 高级UI9 Canvas save和restor
2019-03-09 本文已影响14人
香沙小熊
自己定义控件时经常遇到重写View的draw()方法,draw()方法经常设计到save()和restore()这两个方法.这两个相互匹配出现的,作用是用来保存画布的状态和取出保存的状态的。
save():用来保存canvas的状态,save()方法之后的代码,能够调用canvas的平移、放缩、旋转、裁剪等操作!
restore():用来恢复canvas之前保存的状态,防止save()方法代码之后对canvas运行的操作。继续对兴许的绘制会产生影响。通过该方法能够避免连带的影响!
public class MyView extends View {
public MyView(Context context) {
super(context);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.GREEN);
//canvas变换操作不会对前面造成影响
canvas.clipRect(new Rect(100, 200, 500, 500));
canvas.drawColor(Color.BLUE);
}
}
canvas.drawColor(Color.GREEN);
//canvas变换操作不会对前面造成影响
canvas.clipRect(new Rect(100, 200, 500, 500));
canvas.drawColor(Color.BLUE);
Paint paint = new Paint();
paint.setColor(Color.RED);
canvas.drawCircle(200,200,500,paint);
我们发现canvas裁剪产生的画布,绘制,不会对非裁剪的区域造成影响。
canvas.drawColor(Color.GREEN);
//保存画布当前的状态(保存到画布栈里面了)
canvas.save();
//canvas变换操作不会对前面造成影响
canvas.clipRect(new Rect(100, 100, 500, 500));
canvas.drawColor(Color.BLUE);
//恢复画布
canvas.restore();
Paint paint = new Paint();
paint.setColor(Color.RED);
canvas.drawCircle(100, 100, 100, paint);
canvas.drawColor(Color.GREEN);
//保存画布当前的状态
canvas.save();
//canvas变换操作不会对前面造成影响
canvas.clipRect(new Rect(100, 100, 500, 500));
canvas.drawColor(Color.BLUE);
canvas.save();
//恢复画布
//canvas.restore();
Paint paint = new Paint();
paint.setColor(Color.RED);
canvas.drawCircle(100, 100, 100, paint);
canvas.restore();
paint.setColor(Color.YELLOW);
canvas.drawCircle(150,150,100,paint);
结论:画板是以栈的形式进行存储
搜索动画实际案例
public abstract class BaseController {
public static final int STATE_ANIM_NONE = 0;
public static final int STATE_ANIM_START = 1;
public static final int STATE_ANIM_STOP = 2;
public static final int DEFAULT_ANIM_TIME = 5000;
public static final float DEFAULT_ANIM_STARTF = 0;
public static final float DEFAULT_ANIM_ENDF = 1;
private MySearchView mySearchView;
public int mState = STATE_ANIM_NONE;
public abstract void draw(Canvas canvas,Paint paint);
public void startAnim(){
}
public void resetAnim(){
}
public int getWidth(){
return mySearchView.getWidth();
}
public int getHeight(){
return mySearchView.getHeight();
}
public void setSearchView(MySearchView mySearchView){
this.mySearchView = mySearchView;
}
public float mpro = -1;
public ValueAnimator startViewAnimation(){
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0,1);
valueAnimator.setDuration(800L);
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mpro = (float) animation.getAnimatedValue();
mySearchView.invalidate();
}
});
valueAnimator.start();
mpro = 0;
return valueAnimator;
}
}
绘制类
public class Controller1 extends BaseController {
private String mColor = "#4CAF50";
private int cx, cy, cr;
private RectF mRectF;
private int j = 15;
public Controller1() {
mRectF = new RectF();
}
@Override
public void draw(Canvas canvas, Paint paint) {
canvas.drawColor(Color.parseColor(mColor));
switch (mState) {
case STATE_ANIM_NONE:
drawNormalView(paint, canvas);
break;
case STATE_ANIM_START:
drawStartAnimView(paint, canvas);
break;
case STATE_ANIM_STOP:
// drawNormalView(paint, canvas);
drawStopAnimView(paint, canvas);
break;
}
}
private void drawStopAnimView(Paint paint, Canvas canvas) {
}
private void drawStartAnimView(Paint paint, Canvas canvas) {
canvas.save();
//0~1
if (mpro <= 0.5f) {
/**
* 绘制圆和把手
*/
/**
*
* -360 ~ 0 需要变换的范围
* 0 ~ 0.5 实际的变化范围
* 转换公式:360*(mpro*2-1)
*/
canvas.drawArc(
mRectF,
45,
360 * (mpro * 2 - 1),
false,
paint);
canvas.drawLine(
mRectF.right - j,
mRectF.bottom - j,
mRectF.right + cr - j,
mRectF.bottom + cr - j,
paint);
} else {
/**
* 绘制圆和把手
*/
canvas.drawLine(
mRectF.right - j + cr * (mpro * 2 - 1),
mRectF.bottom - j + cr * (mpro * 2 - 1),
mRectF.right - j + cr,
mRectF.bottom + cr - j,
paint);
}
canvas.drawLine(
(mRectF.right - j + cr) * (1 - mpro * 0.8f),
mRectF.bottom + cr - j,
mRectF.right - j + cr,
mRectF.bottom + cr - j,
paint);
canvas.restore();
mRectF.left = cx - cr + mpro * 250;
mRectF.right = cx + cr + mpro * 250;
mRectF.top = cy - cr;
mRectF.bottom = cy + cr;
}
private void drawNormalView(Paint paint, Canvas canvas) {
cr = getWidth() / 20;
cx = getWidth() / 2;
cy = getHeight() / 2;
mRectF.left = cx - cr;
mRectF.right = cx + cr;
mRectF.top = cy - cr;
mRectF.bottom = cy + cr;
canvas.save();
paint.reset();
paint.setAntiAlias(true);
paint.setColor(Color.WHITE);
paint.setStrokeWidth(5);
paint.setStyle(Paint.Style.STROKE);
canvas.rotate(45, cx, cy);
canvas.drawLine(cx + cr, cy, cx + cr * 2, cy, paint);
// canvas.drawArc(
// mRectF,
// 0, //起始角度,相对X轴正方向
// 360, //画多少角度的弧度
// false, //boolean,false :只用一个弧度线;true:闭合的边
// paint);
// canvas.restore();
canvas.drawArc(
mRectF,
0,
360,
false,
paint);
canvas.restore();
}
@Override
public void startAnim() {
super.startAnim();
mState = STATE_ANIM_START;
startViewAnimation();
}
@Override
public void resetAnim() {
// TODO Auto-generated method stub
super.resetAnim();
mState = STATE_ANIM_STOP;
startViewAnimation();
}
}
public class MySearchView extends View {
private Paint mPaint;
private BaseController mController;
public MySearchView(Context context) {
super(context);
}
public MySearchView(Context context,
@Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setStrokeWidth(5);
}
public void setController(BaseController controller) {
this.mController = controller;
mController.setSearchView(this);
invalidate();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mController.draw(canvas,mPaint);
}
public void startAnimation(){
if(mController!=null){
mController.startAnim();
}
}
public void resetAnimation(){
if(mController!=null){
mController.resetAnim();
}
}
}
public class MainActivity extends AppCompatActivity {
private MySearchView searchView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
searchView = (MySearchView) findViewById(R.id.sv);
searchView.setController(new Controller1());
}
public void start(View view) {
searchView.startAnimation();
}
public void reset(View view) {
searchView.resetAnimation();
}
}