Apidemo 学习 Layers MeasureText PathEffects

Canvas 在一般的情况下可以看作是一张画布,所有的绘图操作如drawBitmap, drawCircle都发生在这张画布上,这张画板还定义了一些属性比如Matrix,颜色等等。

但是如果需要实现一些相对复杂的绘图操作,比如多层动画,地图(地图可以有多个地图层叠加而成,比如:政区层,道路层,兴趣点层)。

Canvas提供了图层(Layer)支持,缺省情况可以看作是只有一个图层Layer。如果需要按层次来绘图,Android的Canvas可以使用SaveLayerXXX, Restore 来创建一些中间层,对于这些Layer是按照“栈结构“来管理的:

创建一个新的Layer到“栈”中,可以使用saveLayer, savaLayerAlpha, 从“栈”中推出一个Layer,可以使用restore,restoreToCount。但Layer入栈时,后续的DrawXXX操作都发生在这个Layer上,而Layer退栈时,就会把本层绘制的图像“绘制”到上层或是Canvas上,在复制Layer到Canvas上时,可以指定Layer的透明度(Layer),这是在创建Layer时指定的:

public int saveLayerAlpha(RectF bounds, int alpha, int saveFlags)

本例Layers 介绍了图层的基本用法:Canvas可以看做是由两个图层(Layer)构成的,为了更好的说明问题,我们将代码稍微修改一下,缺省图层绘制一个红色的圆,在新的图层画一个蓝色的圆,新图层的透明度为0×88。

1 @Override protected void onDraw(Canvas canvas) {
2  canvas.drawColor(Color.WHITE);
3  
4  canvas.translate(1010);
5  
6  mPaint.setColor(Color.RED);
7  canvas.drawCircle(757575, mPaint);
8  
9  canvas.saveLayerAlpha(002002000x88, LAYER_FLAGS);
10  
11  
12  mPaint.setColor(Color.BLUE);
13  canvas.drawCircle(12512575, mPaint);
14  
15  canvas.restore();
16 }

在调用canvas.saveLayerAlpha 创建一个新图层之后,后续的canvas.drawCircle 都会发生的这个新图层上, canvas.restore() 将这个新图层绘制的图像“复制”到Canvas的缺省图层上,透明度为0×88。


public class Layers extends GraphicsActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(new SampleView(this));
    }

    private static class SampleView extends View {
        private static final int LAYER_FLAGS = Canvas.MATRIX_SAVE_FLAG |
                                            Canvas.CLIP_SAVE_FLAG |
                                            Canvas.HAS_ALPHA_LAYER_SAVE_FLAG |
                                            Canvas.FULL_COLOR_LAYER_SAVE_FLAG |
                                            Canvas.CLIP_TO_LAYER_SAVE_FLAG;
        //ALL_SAVE_FLAG; 
        //该参数当画布执行restore 操作时,需要restore的状态属性分别对应:matrix,clip,alpha,color,越界的clip,everything

        private Paint mPaint;

        public SampleView(Context context) {
            super(context);
            setFocusable(true);

            mPaint = new Paint();
            mPaint.setAntiAlias(true);
        }

        @Override protected void onDraw(Canvas canvas) {
            canvas.drawColor(Color.WHITE); //第一层

            canvas.translate(10, 10);

            mPaint.setColor(Color.RED);
            canvas.drawCircle(75, 75, 75, mPaint);
            
            
            canvas.saveLayerAlpha(0, 0, 200, 200, 0x88, LAYER_FLAGS);// 第二层的 透明度是0x88
            mPaint.setColor(Color.BLUE);
            canvas.drawCircle(125, 125, 75, mPaint);

            canvas.restore(); // canvas.restore() 将这个新图层绘制的图像“复制”到Canvas的缺省图层上,透明度为0×88。
        }
    }
}


public class MeasureText extends GraphicsActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(new SampleView(this));
    }

    private static class SampleView extends View {
        private Paint   mPaint;
        private float   mOriginX = 10;
        private float   mOriginY = 80;

        public SampleView(Context context) {
            super(context);
            setFocusable(true);

            mPaint = new Paint();
            mPaint.setAntiAlias(true);
            mPaint.setStrokeWidth(5);
            mPaint.setStrokeCap(Paint.Cap.ROUND);
            mPaint.setTextSize(64);
            mPaint.setTypeface(Typeface.create(Typeface.SERIF,
                                               Typeface.ITALIC));
        }

        private void showText(Canvas canvas, String text, Paint.Align align) {
         //   mPaint.setTextAlign(align);

            Rect    bounds = new Rect();
            float[] widths = new float[text.length()];

            int count = mPaint.getTextWidths(text, 0, text.length(), widths);
            float w = mPaint.measureText(text, 0, text.length());//使用paint 测量text的长度
            mPaint.getTextBounds(text, 0, text.length(), bounds); //拿到字体的文字的矩形区域

            mPaint.setColor(0xFF88FF88);
            canvas.drawRect(bounds, mPaint);//绘制背景
            mPaint.setColor(Color.BLACK);
            canvas.drawText(text, 0, 0, mPaint);//绘制文字

            float[] pts = new float[2 + count*2]; 
            float x = 0;
            float y = 0;
            pts[0] = x;
            pts[1] = y;
            for (int i = 0; i < count; i++) {
                x += widths[i];
                pts[2 + i*2] = x;
                pts[2 + i*2 + 1] = y;
            }
            mPaint.setColor(Color.RED);
            mPaint.setStrokeWidth(0);
            canvas.drawLine(0, 0, w, 0, mPaint);//绘制下线
            mPaint.setStrokeWidth(5);
            canvas.drawPoints(pts, 0, (count + 1) << 1, mPaint);//绘制下面的点号 pts就是位置 :x0 y0 x1y1 x2 y2 ...
        }

        @Override protected void onDraw(Canvas canvas) {
            canvas.drawColor(Color.WHITE);

            canvas.translate(mOriginX, mOriginY);

            showText(canvas, "Measure", Paint.Align.LEFT);
            canvas.translate(0, 80);
            showText(canvas, "wiggy!", Paint.Align.CENTER);
            canvas.translate(0, 80);
            showText(canvas, "Text", Paint.Align.RIGHT);
        }
    }
}

public class PathEffects extends GraphicsActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(new SampleView(this));
    }

    private static class SampleView extends View {
        private Paint mPaint;
        private Path mPath;
        private PathEffect[] mEffects;
        private int[] mColors;
        private float mPhase;

        private static void makeEffects(PathEffect[] e, float phase) {
            e[0] = null;     // no effect
            e[1] = new CornerPathEffect(10); //柔化圆角CornerPathEffect 修改路径上线段连接处的显示模式(从尖角改为可以指定圆弧半径的圆角连接)。
          //DashPathEffect 虚线线显示效果,使用数组来指定需线和间隔的长度。数组中序数(下标)为偶数表示虚线的实线长度,
          //奇数为虚线的间隔长度。 只对Paint设为STROKE 或STROKE_AND_FILL时有效。
            e[2] = new DashPathEffect(new float[] {10, 5, 5, 5}, phase); 
            e[3] = new PathDashPathEffect(makePathDash(), 12, phase,
                                          PathDashPathEffect.Style.ROTATE);
            e[4] = new ComposePathEffect(e[2], e[1]);
            e[5] = new ComposePathEffect(e[3], e[1]);
//            e[0] 不含任何PathEffect,缺省绘制Path的风格,单色实线,连接处为尖角。
//            e[1] 连接使用圆弧连接。
//            e[2] 使用缺省的虚线绘制路径。
//            e[3] 使用自定义的图形(本例为一箭头)的虚线绘制路径
//            e[4] 为使用e[2]和e[1]综合效果,虚线并圆弧连接。
//            e[5] 为使用e[3]和e[1]综合效果,自定义虚线并圆弧连接。
            
//            CornerPathEffect 修改路径上线段连接处的显示模式(从尖角改为可以指定圆弧半径的圆角连接)。
//            DashPathEffect 虚线显示效果,使用数组来指定需线和间隔的长度。数组中序数为偶数表示虚线的实线长度,奇数为虚线的间隔长度。 只对Paint设为STROKE 或STROKE_AND_FILL时有效。
//            PathDashPathEffect 和DashPathEffect类似显示虚线,但可以自定义虚线的模式(DashPathEffect使用的是矩形,而PathDashPathEffect允许使用Path对象自定义虚线的模式),同样只对Paint设为STROKE 或STROKE_AND_FILL时有效。
//            ComposePathEffect 允许组合两个PathEffect (outer ,inner) , 分两次综合结果ComposePathEffect = Outer(inner(path)).
//            SumPathEffect  组合两个两个PathEffect (first, second)  SumPathEffect=first(path) + second(path).
//            DiscretePathEffect 将路径划分成指定长度的线段,然后把每条线段随机偏移原来的位置。
        }

        public SampleView(Context context) {
            super(context);
            setFocusable(true);
            setFocusableInTouchMode(true);

            mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            mPaint.setStyle(Paint.Style.STROKE);
            mPaint.setStrokeWidth(6);

            mPath = makeFollowPath();

            mEffects = new PathEffect[6];

            mColors = new int[] { Color.BLACK, Color.RED, Color.BLUE,
                                  Color.GREEN, Color.MAGENTA, Color.BLACK
                                };
        }

        @Override protected void onDraw(Canvas canvas) {
            canvas.drawColor(Color.WHITE);

            RectF bounds = new RectF();
            mPath.computeBounds(bounds, false);
            canvas.translate(10 - bounds.left, 10 - bounds.top);

            makeEffects(mEffects, mPhase);
            mPhase += 1;
            invalidate();

            for (int i = 0; i < mEffects.length; i++) {
                mPaint.setPathEffect(mEffects[i]);
                mPaint.setColor(mColors[i]);
                canvas.drawPath(mPath, mPaint);
                canvas.translate(0, 28);
            }
        }

        @Override public boolean onKeyDown(int keyCode, KeyEvent event) {
            switch (keyCode) {
                case KeyEvent.KEYCODE_DPAD_CENTER:
                    mPath = makeFollowPath(); //按方向键上“中间键”将随机产生一个新的绘制路径。
                    return true;
            }
            return super.onKeyDown(keyCode, event);
        }

        private static Path makeFollowPath() { //绘制 路径 android.graphics.Path允许使用线段,二次曲线,三次曲线构成路径(类似SVG)
            Path p = new Path();
            p.moveTo(0, 0);
            for (int i = 1; i <= 15; i++) {
                p.lineTo(i*20, (float)Math.random() * 35);
            }
            return p;
        }

        private static Path makePathDash() {// makePathDash定义了自定义虚线类型上的小箭头图案:
            Path p = new Path();
            p.moveTo(4, 0);
            p.lineTo(0, -4);
            p.lineTo(8, -4);
            p.lineTo(12, 0);
            p.lineTo(8, 4);
            p.lineTo(0, 4);
            return p;
        }
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值