android UI之Path

     Path作为UI绘制的重要的一个类,在官方文档上对于的介绍如下:

    Path封装了由直线段,二次曲线和三次曲线组成的复合几何路径,它可以用canvas.drawPath()进行绘制,填充,描画,或者可以用于剪切或者绘制路径上的文字。

   下面关于它常见的API进行一个简单的记录:

方法 讲解
lineTo(float x, float y) 绘制直线,连接上一点和当前点
moveTo(float x, float y) 移动画笔,将画笔的开始位置移动到(x,y)
arcTo(RectF oval, float startAngle, float sweepAngle) 绘制圆弧,oval绘制圆弧的矩形局域,startAngle其实角度,sweepAngle旋转角度
quadTo(float x1, float y1, float x2, float y2)

绘制二阶贝塞尔曲线,当前path位置为起点,(x1,y1)为控制点(x2,y2)终点

cubicTo(float x1, float y1, float x2, float y2,float x3, float y3)

绘制三阶贝塞尔曲线   当前path位置为起点,(x1,y1)为控制点1,(x2,y2)控制点2,(x3,y3)终点

 

add方法

方法 讲解
addArc(RectF oval, float startAngle, float sweepAngle) 添加圆弧到当前path,oval添加区域,startAngle开始角度,sweepAngle圆弧旋转的角度
addCircle(float x, float y, float radius, Direction dir) 添加圆到当前path,(x,y)圆心的坐标,radius半径,dir线的闭合方向(CW顺时针方向 ,CCW逆时针方向)
addOval(RectF oval, Direction dir) 添加椭圆到当前path,oval绘制区域,dir:闭合方向
addRect(RectF rect, Direction dir) 添加矩形到当前path
addRoundRect(RectF rect, float rx, float ry, Direction dir) 添加圆角矩形,rect区域,rx横轴半径,ry纵轴半径,dir闭合方向,该方法的圆角是统一大小的
addRoundRect(RectF rect, float[] radii, Direction dir) 添加圆角矩形(非统一),rect矩形区域,radii四个圆角矩形分别对应的横轴半径和纵轴半径,一个8个,dir闭合反向
addPath(Path src) 添加Path,添加path到当前path
addPath(Path src, float dx, float dy) 添加平移后的path到当前path,src需要平移的path,(dx,dy)平移后的x,y坐标
addPath(Path src, Matrix matrix) 添加经过矩阵变幻后的path

 

Fill type -Path的填充模式

方法 讲解
setFillType(FillType ft)

设置填充模式,ft取值共有:

EVEN_ODD:取Path所在并不相交区域

INVERSE_EVEN_ODD :取Path未占或相交区域

WINDING:取Path所有区域,默认模式

INVERSE_WINDING:取Path所有未占区域

getFillType() 获取当前path的填充模式
isInverseFillType() 判断当前填充模式是否是反向规则,即(INVERSE_XX)
toggleInverseFillType() 当前填充模式与其反向规则模式进行反向取

 

其他零散重要的方法

方法 讲解
close() 封闭当前path,连接起点和终点
reset() 清空path,相当于new Path
rewind() 清空path上面的直线和曲线,保留数据结构
set(Path src) 用名为src的path替换当前path
op(Path path, Op op)

当前path与名为path的路径进行布尔运算:

DIFFERENCE:差集
REVERSE_DIFFERENCE:反向差集,

INTERSECT:交集,

UNION:并集

XOR:异或

offset(float dx, float dy) 平移path,dx-x轴上的移动距离,dy-Y轴上的移动距离
offset(float dx, float dy, Path dst) 平移dstPath
transform(Matrix matrix) 对当前path进行矩阵变幻
setLastPoint(float dx, float dy) 设置当前path的终点
isEmpty() 判断当前path是否是空
isConvex() 判断当前path是否为凸多边形
isRect(RectF rect) 如果当前path是矩形,那么储存放入rect中

以上的是Path的创建方法,在日常的开发工作中我们可以根据自己需要调用合适API,在上篇文章androidUI之贝塞尔曲线中我们主要简介了贝塞尔曲线的原理以及算法,在这里我们主要以Path绘制贝塞尔曲线为例子进行API的简单实用。

  Path绘制二阶贝塞尔曲线:quadTo()

  private void init() {
        mPath = new Path();
        xC1 = 300;
        yC1 = 60;

        xEnd = 500;
        yEnd = 300;

        mPaint = new Paint();
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(5);
        mPaint.setColor(Color.RED);


        pPaint = new Paint();
        pPaint.setStyle(Paint.Style.FILL);
        pPaint.setColor(Color.BLACK);

    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mPath.moveTo(100, 100);
        mPath.quadTo(xC1, yC1, xEnd, yEnd);//二阶贝塞尔曲线
        canvas.drawPath(mPath, mPaint);

        canvas.drawCircle(100, 100, 10, pPaint);
        canvas.drawCircle(xEnd, yEnd, 10, pPaint);
        //控制点
        pPaint.setColor(Color.GREEN);
        canvas.drawCircle(xC1, yC1, 10, pPaint);

    }

android UI之Path_第1张图片

三阶贝塞尔曲线:cublicTo

 private void init() {
        mPath = new Path();
        xStart = 100;
        yStart = 100;

        xC1 = 300;
        yC1 = 60;

        xC2 = 500;
        yC2 = 500;

        xEnd = 800;
        yEnd = 300;

        mPaint = new Paint();
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(5);
        mPaint.setColor(Color.RED);


        pPaint = new Paint();
        pPaint.setStyle(Paint.Style.FILL);
        pPaint.setColor(Color.BLACK);

    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mPath.moveTo(xStart, yStart);
        mPath.cubicTo(xC1, yC1, xC2, yC2, xEnd, yEnd);//三阶贝塞尔曲线
        canvas.drawPath(mPath, mPaint);

        //控制点
        canvas.drawCircle(xC1, yC1, 10, pPaint);
        canvas.drawCircle(xC2, yC2, 10, pPaint);
        //起始点
        pPaint.setColor(Color.GREEN);
        canvas.drawCircle(xStart, yStart, 10, pPaint);
        canvas.drawCircle(xEnd, yEnd, 10, pPaint);

    }

 

android UI之Path_第2张图片 

多阶:利用Path+德卡斯特利奥算法:

package com.barry.lsn_7_path_bezier.hy;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;


/**
 * @author huanghaha
 * @desc 多阶贝塞尔曲线
 */
public class OtherBesselView extends View {

    private Path mPath;
    private Paint mPaint;//点线之间的画笔
    private Paint pPaint;//贝塞尔曲线的画笔
    private float xStart, yStart;
    private float xEnd, yEnd;
    private List cPoints = new ArrayList<>();

    public OtherBesselView(Context context) {
        super(context);
        init();
    }

    public OtherBesselView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public OtherBesselView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public OtherBesselView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

    }


    private void init() {
        mPath = new Path();

        mPaint = new Paint();
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setStrokeWidth(5);
        mPaint.setColor(Color.RED);

        pPaint = new Paint();
        pPaint.setStyle(Paint.Style.STROKE);
        pPaint.setStrokeWidth(5);
        pPaint.setColor(Color.GREEN);


        Random random = new Random();
        for (int i = 0; i < 6; i++) {
            int cX = random.nextInt(600) + 100;
            int cY = random.nextInt(600) + 100;
            PointF p = new PointF(cX, cY);
            cPoints.add(p);
        }

    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //1.画出控制点以及他们之间的线段-仅仅为了对照
        for (int i = 0; i < cPoints.size(); i++) {
            PointF pointF = cPoints.get(i);
            if (i > 0) {
                canvas.drawLine(cPoints.get(i - 1).x, cPoints.get(i - 1).y, pointF.x, pointF.y, mPaint);
            }
            canvas.drawCircle(pointF.x, pointF.y, 10, mPaint);
        }

        //2.根据德卡斯特利奥算法画出贝塞尔曲线
        buildBezierPoints(canvas);


    }

    /**
     * 绘制贝塞尔曲线
     */
    private void buildBezierPoints(Canvas canvas) {
        int order = cPoints.size() - 1; //当前贝塞尔曲线的阶数
        float delta = 1.0f / 100;// 绘制的密度,(如果密度太小可能不能绘制完所有的曲线)
        for (float t = 0.0f; t <= 1.0f; t += delta) {
            PointF pointF = new PointF(deCusterLeoX(order, 0, t), deCusterLeoY(order, 0, t));//贝塞尔曲线上的点

            //使用path连接点
            if (t == 0.0f) {//移动画笔到第一个点
                mPath.moveTo(pointF.x, pointF.y);

            } else {//连接点
                mPath.lineTo(pointF.x, pointF.y);
            }


        }
        canvas.drawPath(mPath, pPaint);

    }

    /**
     * 利用递归思想求出在t-比例不断变动的情况先贝塞尔曲线上的点
     * 由于递归的计算有压栈的特点,所以这儿的j进入的时候传入的0,为方便理解可以打开注释
     *
     * @param order 阶数
     * @param j     当前控制点
     * @param t     比例
     * @return
     */
    private float deCusterLeoX(int order, int j, float t) {
//        Log.e("msg", "开始计算的条件" + " order=" + order + "  j=" + j + "  t=" + t);
        float reuslt = 0.0f;
        if (order == 1) {//一阶段
            reuslt = (1 - t) * cPoints.get(j).x + t * cPoints.get(j + 1).x;
        } else {

            float val1 = (1 - t) * deCusterLeoX(order - 1, j, t);
            float val2 = t * deCusterLeoX(order - 1, j + 1, t);

            reuslt = val1 + val2;

        }
//        Log.e("msg", "开始计算的结果" + reuslt);
        return reuslt;

    }

    private float deCusterLeoY(int order, int j, float t) {
        if (order == 1) {//一阶段
            return (1 - t) * cPoints.get(j).y + t * cPoints.get(j + 1).y;
        } else {


            return (1 - t) * deCusterLeoY(order - 1, j, t) + t * deCusterLeoY(order - 1, j + 1, t);

        }

    }
}

android UI之Path_第3张图片

以上便是path关于贝塞尔曲线的简单应用。

 

你可能感兴趣的:(Android,移动开发)