Android图形graphics

一:弧形柱的画法

/**
         * 弧形柱的画法,可用于饼图
         */
        float outSideRadius = getWidth()/3;//外圆半径
        float inSideRadius = getWidth()/4;//内圆半径
        //midX和midY是View的中心位置,这里用作俩圆的圆心(midX,midY)坐标
        float midX = getWidth()/2;
        float midY = getHeight()/2;
        canvas.drawCircle(midX, midY, outSideRadius, ringPaint);//外层圆,第一二个参数是圆心的x,y坐标,这里是View的中心,第二个参数是半径,第三个参数是Paint
        canvas.drawCircle(midX, midY, inSideRadius, ringPaint);//内层圆
        //圆心的x,y坐标各减半径即为包裹该圆的矩形左上角的x,y坐标,各加半径即为右下角的坐标,这样就确定了这个矩形
        RectF outSideRectF = new RectF(midX-outSideRadius,midY-outSideRadius,midX + outSideRadius, midY+outSideRadius);//包裹外层圆
        RectF inSideRectF = new RectF(midX-inSideRadius,midY-inSideRadius,midX+inSideRadius,midY+inSideRadius);//包裹内层圆的矩形
        canvas.drawRect(outSideRectF,ringPaint);
        canvas.drawRect(inSideRectF, ringPaint);

        Paint arcPaint = new Paint();
        arcPaint.setColor(Color.GREEN);
        arcPaint.setAntiAlias(true);
        //默认就是FILL,FILL的意思是显示将Paint的起点和终点直线联系后形成闭合再用指定的颜色填满后的效果,STROKE是指只显示Paint走过的线的路径
        arcPaint.setStyle(Paint.Style.FILL);
        //路径,可以理解为线性的路径,没有宽度概念?
        Path path = new Path();
        //arcTo方法只是指定弧形的路径,还没有画出来显示到canvas上
        //画弧形的原理是:截取矩形所包裹的椭圆(包含圆)的一段即为弧形,
        // 圆的起始角度是圆心的正右侧(0度),第二个参数是弧形开始的角度,第三个参数是弧形走过的角度,顺时针为正,逆时针为负
        path.arcTo(outSideRectF, 0, 90);//外层弧形
//        path.arcTo(inSideRectF, 0, 90);//内层弧形,不要这样走,这样两个path走不成弧形柱,可以用笔画一下,参考下图的图二
        path.arcTo(inSideRectF, 0+90, -90);//内层弧形,第二个path应该倒着走,这样就走成了一个空的弧形柱,再用paint的颜色一填充就形成了相应颜色的实体的扇形柱,参考下图图二
//        path.close();//封闭轮廓,即轮廓是闭合的,没有开口
        //将path指定的弧形用画笔画到画布上
        canvas.drawPath(path,arcPaint);
        //一个画笔Paint画两个Path中间是不可以抬笔的,类似于汉字的连笔字
        //即一个path从起点画到终点后要直接连(这个连是有痕迹的,类似连笔字,也是paint画出的内容)到下一个path的起点
弧形柱图片:

二:创建Canvas,在该画布上画圆,画矩形并在当前View上显示,ProterDuff.Mode用法

效果如下图:

代码如下:
public class TestView extends View {
    private Canvas myCanvas;
    private Paint ringPaint;//在当前View画空心圆用的画笔
    private Paint circlePaint;
    private int mRadius;
    private Paint mFgroundPaint;
    private RectF mRect;
    public TestView(Context context) {
        super(context);
        initView();
    }

    private void initView() {
        mRadius = getScreenWidth()*1/4;
        ringPaint = new Paint();
        circlePaint = new Paint();
        mFgroundPaint = new Paint();

//        ringPaint.setStyle(Paint.Style.FILL);
        ringPaint.setStyle(Paint.Style.STROKE);
        ringPaint.setAntiAlias(true);
//        ringPaint.setARGB(255, 255 ,225, 255);
        ringPaint.setColor(Color.RED);
//        ringPaint.setStrokeWidth(10);

        circlePaint.setStrokeWidth(mRadius);
        circlePaint.setAntiAlias(true);
//        circlePaint.setARGB(255, 0, 0, 0);
        circlePaint.setColor(Color.BLUE);
        //PorterDuff.Mode用在上面图形的Paint上,用于与下面图形的交互,两个图形用一个Paint也是相同的道理
        circlePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.XOR));


        mFgroundPaint.setAntiAlias(true);
//        mFgroundPaint.setARGB(185, 0, 0, 0);
        mFgroundPaint.setColor(Color.GREEN);
//        mFgroundPaint.setStrokeWidth(10);
//        mFgroundPaint.setStyle(Paint.Style.STROKE);不设置默认fill
        mFgroundPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.XOR));
    }

    public TestView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView();
    }

    public TestView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView();
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public TestView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        initView();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
//        canvas.drawColor(Color.BLUE);
        mRect = new RectF(0, 0, getWidth(), getHeight());
        Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
        myCanvas = new Canvas(bitmap);//创建Canvas要指定一个Bitmap,也可用无参的构造器之后手动指定
        //在当前View的画布上画红色空心圆
        canvas.drawCircle(getWidth() / 2, getHeight() / 2, getWidth() / 3, ringPaint);
        myCanvas.drawRect(new RectF(getWidth() / 2, getHeight() / 2, getWidth(), getHeight()), mFgroundPaint) ;//在自己的画布上画绿色矩形
        myCanvas.drawCircle(getWidth() / 2, getHeight() / 2, mRadius, circlePaint);//在自己的画布上画蓝色实心圆
        //在你自己创建的画布myCanvas上画完图像后,要将myCanvas的bitmap画到当前View的canvas上才能显示出来
        canvas.drawBitmap(bitmap, null, mRect, null);//第三个参数是bitmap要画到的目标矩形
        //你在自己画布上画的图形添加到当前View的canvas上后会遮挡当前view的对应区域
    }

    private int getScreenWidth() {
        WindowManager wm = (WindowManager) this.getContext().getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics m = new DisplayMetrics();
        wm.getDefaultDisplay().getMetrics(m);
        return m.widthPixels;
    }
}

三:我想使用ProterDuff.Mode.DST_OUT实现如下图一的效果,结果实际效果却是下图二

原因是:在该例中你直接在当前View的Canvas上画图,无论你使用什么Mode,两个图的的相交部分总是黑色的,不知道是从哪里来的,要想实现Mode的正常效果,可以自己创建一个myCanvas,在该画布上画完图后再在当前View的画布上显示,如上一个例子一样。
           
图一 图二
错误代码:该代码运行的结果是图二,二不是我希望的图一
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        float outSideRadius = getWidth()/3;//外圆半径
        float inSideRadius = getWidth()/4;//内圆半径
        float midX = getWidth()/2;
        float midY = getHeight()/ 2;
        ringPaint.reset();
        ringPaint.setColor(Color.GREEN);
        ringPaint.setAntiAlias(true);
        canvas.drawCircle(midX, midY, outSideRadius, ringPaint);//外层圆,第一二个参数是圆心的x,y坐标,这里是View的中心,第二个参数是半径,第三个参数是Paint
        ringPaint.reset();
        ringPaint.setColor(Color.BLUE);
        ringPaint.setAntiAlias(true);
        ringPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));//取下层图片非交集部分
        canvas.drawCircle(midX, midY, inSideRadius, ringPaint);//内层圆
    }

四:使用saveLayer创建一个新的图层,结合ProterDuff.Mode实现上图一的效果

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //当前View的画布上使用了xfermode, color filter, or alpha时常用saveLayer方法创建一个新的图层
//        创建一个单独的图层,并放入Canvas图层栈
        int saveCount = canvas.saveLayer(0, 0, getWidth(), getHeight(), null,
                Canvas.ALL_SAVE_FLAG);
        float outSideRadius = getWidth()/3;//外圆半径
        float inSideRadius = getWidth()/4;//内圆半径
        float midX = getWidth()/2;
        float midY = getHeight()/ 2;
        ringPaint.reset();
        ringPaint.setColor(Color.GREEN);
        ringPaint.setAntiAlias(true);
        canvas.drawCircle(midX, midY, outSideRadius, ringPaint);
        ringPaint.reset();
        ringPaint.setColor(Color.BLUE);
        ringPaint.setAntiAlias(true);
        ringPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
        canvas.drawCircle(midX, midY, inSideRadius, ringPaint);//内层圆
        //将之前创建的图层从图层栈中退出,并将在该图层绘制的图片”绘制“到canvas上
        canvas.restoreToCount(saveCount);
//        canvas.restore();
    }




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值