Quantcast
Channel: CSDN博客移动开发推荐文章
Viewing all articles
Browse latest Browse all 5930

Android:视图绘制(四) ------Path进阶

$
0
0

这里主要讲Path的填充方式 FillType 和 他的一个辅助工具类 PathMeasure

前文我们已经讲过如何用Path画出各种图形,《Android:视图绘制(三) ——Path介绍》,不了解的朋友可以移步。

FillType 填充方式

前文讲Paint的时候,我们就讲到过填充方式,不记得的朋友请移步《Android:视图绘制(一) ——基本的绘图操作Paint和Canvas》,Path的填充方式和Paint的不同,他提供了四种可供选择的值。

· FillType.WINDING: 默认值,取Path的所有区域
· FillType.EVEN_ODD: 取path所在并不相交的区域
· FillType.INVERSE_WINDING: 取path的外部区域
· FillType.INVERSE_EVEN_ODD: 取path外部和相交区域

INVERSE 相反取逆的意思,所以下面的两种填充方式是上面两种的相反形式。

Path提供了 setFillType(FillType ft) 方法,来设置填充方式。下面看图:

这里写图片描述

这里写图片描述

这里写图片描述

值得注意的是,当我们用了INVERSE 属性,取相交外部区域,会填充整个Canvas。

FillType系列还有一些函数。

boolean isInverseFillType() 是否是INVERSE 系列函数。
void toggleInverseFillType() 切换到相反的函数。即 WINDING 切换到 INVERSE_WINDING,反之亦然。

PathMeasure Path的辅助工具类,用于Path的计算的。其可以获得Path的长度和其中任意点的坐标,基于此,我们多是实现一些沿特定图形运动的动画。

其提供了两个构造方法。

PathMeasure()
PathMeasure(Path path, boolean forceClosed)

一种是无参的,另一种提供了两个参数。

参数一 path:因为PathMeasure是用于Path的计算的,所以PathMeasure一定要和我们要操作的Path绑定到一起,其内部会有一个全局的变量用于保存我们的Path,这个构造函数就是一个赋值的过程。

参数二 forceClosed:强制关闭,是一个Boolean的变量。官方解释:If true, then the path will be considered as “closed” even if its contour was not explicitly closed. 就是说,如果我们设置为true的话,就相当于强行的把Path闭合了,也就是相当于调用了Path的close。

PathMeasure 还提供了一个方法setPath(Path path, boolean forceClosed) 可以看到其参数和构造方法中的一样,其实就是对应上面那个无参的构造方法,用来设置值的。

下面来看一下 PathMeasure 中的主要方法。

float getLength() 返回Path的总长度。

boolean getPosTan(float distance, float pos[], float tan[]) 获得距Path起点distance长度的点的坐标,并赋值给pos[]

boolean getSegment(float startD, float stopD, Path dst, boolean startWithMoveTo) 获得距Path起点startD到stopD长度的path,并赋值给dst

还记得前面讲的贝塞尔曲线吗,今天用这个贝塞尔曲线加PathMeasure ,给大家模拟一个小球落地的例子:

这里写图片描述

Gif效果不是很好,有兴趣的可以拷到自己程序中看效果。直接上代码,注释很详细,就不在赘述了。

/**
 * 模拟小球抛物线落地 Demo
 *
 * @author adong
 * @date 2016-9-24 17:11:39
 */
public class CustomPaintView extends View {

    private Paint mPaint;
    private Path mPath;
    private PathMeasure pathMeasure;

    // path长度
    private int mLenght;
    // 当前距离
    private int mCurrentPath;
    // 当前点坐标
    private float[] currentPosition;
    // 用于存放小球的Bitmap
    private Bitmap bitmap;

    public CustomPaintView(Context context, AttributeSet attrs) {
        super(context, attrs);

        setLayerType(View.LAYER_TYPE_SOFTWARE, null);

        mPaint = new Paint();
        mPath = new Path();
        currentPosition = new float[2];
        bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.leida_point_small);
        mPaint.setColor(Color.parseColor("#ff0000"));
        mPaint.setStyle(Paint.Style.STROKE);

        mPath.moveTo(0, 100);
        // 贝塞尔曲线,用于模拟抛物线
        mPath.cubicTo(300, 50, 600, 150, 800, 500);
        mPath.quadTo(950, 400, 1000, 500);

        pathMeasure = new PathMeasure();
        pathMeasure.setPath(mPath, false);
        // 获得长度
        mLenght = (int) pathMeasure.getLength();
    }

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

    public CustomPaintView(Context context) {
        super(context);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawPath(mPath, mPaint);
        if (mCurrentPath == 0) {
            // 第一次启动
            startAnimator();
        } else {
            // 在每次ValueAnimator的回调中更新小球的位置
            canvas.drawBitmap(bitmap, currentPosition[0] - bitmap.getWidth() / 2,
                    currentPosition[1] - bitmap.getHeight() / 2, mPaint);
        }
    }

    /**
     * 计算每次的位置
     */
    private void startAnimator() {
        ValueAnimator valueAnimator = ValueAnimator.ofInt(0, mLenght);
        // 持续时间
        valueAnimator.setDuration(5000);
        // 加速插值器
        valueAnimator.setInterpolator(new AccelerateInterpolator());
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                // 获得当前的长度
                mCurrentPath = (int) animation.getAnimatedValue();
                // 获得对应点坐标
                pathMeasure.getPosTan(mCurrentPath, currentPosition, null);

                // 重绘
                invalidate();
            }
        });
        valueAnimator.start();
    }
}
作者:u010635353 发表于2016/9/24 17:19:14 原文链接
阅读:7 评论:0 查看评论

Viewing all articles
Browse latest Browse all 5930

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>