Canvas的保存和恢复的demo

作者: 凌川江雪 | 来源:发表于2019-08-20 11:07 被阅读9次

    由于篇幅问题,
    笔者把文章
    6.4 Android绘图技巧(Primary:Canvas & Layer, 附demo-仪表盘、圆形头像、裁剪动画绘制)
    的概念demo代码单独迁到这篇文章这里,
    欢迎各位小伙伴惠读指教~

    先上代码

    这个代码一来是记录一个demo,二来是分享一下代码逻辑的设计思路;

    activity_main.xml:
    就一个带了id的ViewGroup而已:

    <?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:id="@+id/ll_nextParent"
        xmlns:tools="http://schemas.android.com/tools"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    
    </LinearLayout>
    

    MainActivity:
    主要的功能都写在代码中的注释里了哈~

    public class MainActivity extends AppCompatActivity {
    
        private LinearLayout ll_nextParent;
        private LinearLayout.LayoutParams layoutParams;
    
        private CanvasTestView canvasTestView;
        private int canvasDrawId;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            //初始化控件和点击事件
            initViews();
    
            //为了方便调试,定义此方法,输入不同的id,显示不同的自定义View
            configCustomViews(1);
        }
    
        private void initViews() {
    
            canvasDrawId = 0;
    
            ll_nextParent = findViewById(R.id.ll_nextParent);
    
            layoutParams = new LinearLayout.LayoutParams(
                    LinearLayout.LayoutParams.WRAP_CONTENT,
                    LinearLayout.LayoutParams.WRAP_CONTENT);
    
            testTheCanvas();
        }
    
    
        private void configCustomViews(int drawId) {
            switch (drawId) {
                case 0:
                    SpiderView spiderViewOri = new SpiderView(this);
                    ll_nextParent.addView(spiderViewOri, layoutParams);
                    break;
    
                case 1:
                    canvasTestView = new CanvasTestView(this);
                    ll_nextParent.addView(canvasTestView, layoutParams);
                    break;
    
                default:
            }
        }
    
        //这个方法加在initView中,测试canvas的存取
        private void testTheCanvas(){
            ll_nextParent.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    canvasTestView.setDrawId(canvasDrawId);
                    canvasDrawId ++ ;
                }
            });
    
            ll_nextParent.setOnLongClickListener(new View.OnLongClickListener() {
                @Override
                public boolean onLongClick(View v) {
                    canvasDrawId = 0;
                    canvasTestView.setDrawId(canvasDrawId);
                    return false;
                }
            });
        }
    }
    

    自定义的CanvasTestView

    • 整个demo的设计思路就是,
      把不同的绘制调试代码分别顺序写在case中,
      通过MainActivity的点击事件,点击一下就更新全局id,然后重绘,
      重绘的时候就会因为id的更新而选择下一套绘制代码进行绘制,
      绘制出不同的内容:

    • 设置一个全局drawId
      通过点击事件更改drawId,并重绘
      重绘制时根据改变了的不同的drawId
      绘制不同的图像

    public class CanvasTestView extends View {
    
        private int drawId;
    
    
        public CanvasTestView(Context context) {
            super(context);
            drawId = 0;
            setLayerType(LAYER_TYPE_SOFTWARE, null);
        }
    
        public CanvasTestView(Context context, AttributeSet attrs) {
            super(context, attrs);
            drawId = 0;
            setLayerType(LAYER_TYPE_SOFTWARE, null);
        }
    
        public void setDrawId(int drawId) {
            this.drawId = drawId;
            postInvalidate();
        }
    
        public void resetDrwaId() {
            drawId = 0;
            postInvalidate();
        }
    
        /**
         * 设置一个全局drawId
         * 通过点击事件更改drawId,并重绘
         * 重绘制时根据改变了的不同的drawId
         * 绘制不同的图像
         *
         */
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
    
            switch (drawId) {
                case 0:
                    canvas.drawColor(Color.RED);
                    canvas.save();
                    break;
                case 1:
                    canvas.drawColor(Color.RED);
                    canvas.save();
                    canvas.clipRect(new Rect(100, 100, 800, 800));
                    canvas.drawColor(Color.GREEN);
                    break;
                case 2:
                    canvas.drawColor(Color.RED);
                    canvas.save();
                    canvas.clipRect(new Rect(100, 100, 800, 800));
                    canvas.drawColor(Color.GREEN);
                    canvas.restore();
                    canvas.drawColor(Color.BLUE);
                    break;
    
                case 3:
                    draw1ColorAnd4Rect(canvas);
                    break;
                case 4:
                    draw1ColorAnd4Rect(canvas);
    
                    canvas.restore();
                    canvas.drawColor(Color.YELLOW);
                    break;
                case 5:
                    draw1ColorAnd4Rect(canvas);
    
                    canvas.restore();
                    canvas.restore();
                    canvas.restore();
                    canvas.drawColor(Color.YELLOW);
                    break;
    
                case 6:
                    draw1ColorAnd4Rect(canvas);
                    break;
    
                case 7:
                    draw1ColorAnd4RectWithCount(canvas);
                    break;
            }
        }
    
        //抽取相同部分代码
        private void draw1ColorAnd4Rect(Canvas canvas) {
            canvas.drawColor(Color.RED);
            canvas.save();
    
            canvas.clipRect(new Rect(100, 100, 800, 800));
            canvas.drawColor(Color.GREEN);
            canvas.save();
    
            canvas.clipRect(new Rect(200,200,700,700));
            canvas.drawColor(Color.BLUE);
            canvas.save();
    
            canvas.clipRect(new Rect(300,300,600,600));
            canvas.drawColor(Color.BLACK);
            canvas.save();
    
            canvas.clipRect(new Rect(400,400,500,500));
            canvas.drawColor(Color.WHITE);
        }
    
        //抽取代码
        private void draw1ColorAnd4RectWithCount(Canvas canvas) {
            canvas.drawColor(Color.RED);
            int c1 = canvas.save();
    
            canvas.clipRect(new Rect(100, 100, 800, 800));
            canvas.drawColor(Color.GREEN);
            int c2 = canvas.save();
    
            canvas.clipRect(new Rect(200,200,700,700));
            canvas.drawColor(Color.BLUE);
            int c3 = canvas.save();
    
            canvas.clipRect(new Rect(300,300,600,600));
            canvas.drawColor(Color.BLACK);
            int c4  = canvas.save();
    
            canvas.clipRect(new Rect(400,400,500,500));
            canvas.drawColor(Color.WHITE);
    
            canvas.restoreToCount(c2);
            canvas.drawColor(Color.YELLOW);
        }
    }
    

    效果图

    • 点击一次,重绘一次,切换一套绘制代码,(drawId++)
      长按则从头开始,(drawId = 0)
      结合效果图,
      我们可以体会到Canvas的保存和恢复相关的三个方法的作用和使用过程:

    相关文章

      网友评论

        本文标题:Canvas的保存和恢复的demo

        本文链接:https://www.haomeiwen.com/subject/njpusctx.html