贝塞尔曲线在Android中的应用
来源:互联网 发布:淘宝关键词竞争指数 编辑:程序博客网 时间:2024/06/05 23:42
今天要讲解的内容是Android中贝塞尔曲线的应用。可能很多人对贝塞尔曲线不甚了解,这里先对它的概念做一下简单介绍。
贝塞尔曲线由多个点组成:起始点、终止点以及0到n个相互分离的中间点。根据中间点的不同,可以分为线性贝塞尔曲线、二阶贝塞尔曲线、三阶贝塞尔曲线和高阶贝塞尔曲线。一般的矢量图形软件通过它来精确画出曲线,贝塞尔曲线由线段与节点组成,节点是可拖动的支点,线段像可伸缩的皮筋。对于三阶贝塞尔曲线,它由两个锚点P0、P3和两个中间点P1、P2组成。曲线起始于P0走向P1,并从P2的方向来到P3。曲线一般不会经过P1和P2,这两个点只是提供方向资讯。P0和P1之间的间距,决定了曲线在转而趋进P3之前,走向P2方向的“长度有多长”。关于贝塞尔曲线的更多内容,可以从这里了解:http://blog.csdn.net/androidzhaoxiaogang/article/details/8680330
下面是二阶、三阶和四阶曲线的效果图,红色曲线为最终绘制出来的结果,大家可以了解一下。
有个网站为我们提供了工具,可以生成对应的二阶贝塞尔曲线的数值:cubic-bezier.com。拖拽左边图像中的2个中间点,就会在右边显示两个中间点归一化的坐标值。我们还可以点击SAVE按钮将曲线保存下来,然后点击GO就可以查看通过当前曲线计算出来的差值器的效果。具体功能看下面的图。
了解了贝塞尔曲线的基本概念,下面来看一下贝塞尔曲线在Android中的具体应用。贝塞尔曲线在Android中主要有三个用途:动画差值器、绘制动画轨迹、实现平滑绘图。
动画差值器
我们知道Android动画可以设置差值器Interpolator来修饰动画效果,其作用是把0到1的浮点值变化映射到另一个浮点值变化,然后将这个值作为动画的变化率。定义差值器需要实现Interpolator接口,然后根据三阶贝塞尔曲线的公式,得到下面的差值器。其中p1、p2是两个中间点的坐标,需要调用者传入来得到不同的曲线。如果我们要得到曲线横轴方向上的变化率,就将两个中间点的y坐标带入公式;否则,就将两个中间点的x坐标带入公式。
public class BezierInterpolator implements Interpolator { float p1; float p2; BezierInterpolator(float p1, float p2) { this.p1 = p1; this.p2 = p2; } @Override public float getInterpolation(float t) { return 0 * (1 - t) * (1 - t) * (1 - t) + 3 * p1 * t * (1 - t) * (1 - t) + 3 * p2 * t * t * (1 - t) + 1 * t * t * t; }}绘制动画轨迹
说明这个问题之前,必须先了解属性动画中的TypeEvaluator。TypeEvaluator有什么作用呢?简单来说,就是告诉系统动画如何从初始值过度到结束值。其实这个TypeEvaluator也可以理解为差值器,只是它的定义是泛型的,我们可以将泛型参数设置为PointF,就能得到当前运动轨迹的坐标位置。而Interpolator只是一个线性的差值器,只能得到运动速率的变化,不能得到运动轨迹。如果还不理解,就看下面的代码吧。
public class BezierEvaluator implements TypeEvaluator<PointF> { PointF mPointF1; PointF mPointF2; public BezierEvaluator(PointF mPointF1, PointF mPointF2) { this.mPointF1 = mPointF1; this.mPointF2 = mPointF2; } @Override public PointF evaluate(float t, PointF point0, PointF point3) { //t 百分比 0~1 PointF pointF = new PointF(); pointF.x = point0.x * (1 - t) * (1 - t) * (1 - t) + 3 * mPointF1.x * t * (1 - t) * (1 - t) + 3 * mPointF2.x * t * t * (1 - t) + point3.x * t * t * t; pointF.y = point0.y * (1 - t) * (1 - t) * (1 - t) + 3 * mPointF1.y * t * (1 - t) * (1 - t) + 3 * mPointF2.y * t * t * (1 - t) + point3.y * t * t * t; return pointF; }}
private ValueAnimator getBezierValueAnimator() { PointF pointf0 = new PointF(0, 0); PointF pointf1 = new PointF(width / 8, height * 7 / 8); PointF pointf2 = new PointF(width * 7 / 8, height / 8); PointF pointf3 = new PointF(width - 100, height - 100); //通过贝塞尔曲线公式,自定义估值器 final BezierEvaluator evaluator = new BezierEvaluator(pointf1, pointf2); //将估值器传入属性动画,不断的修改控件的坐标 ValueAnimator animator = ValueAnimator.ofObject(evaluator, pointf0, pointf3); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { PointF pointf = (PointF) animation.getAnimatedValue(); mImageView.setX(pointf.x); mImageView.setY(pointf.y); } }); animator.setTarget(mImageView); animator.setDuration(3000); animator.setInterpolator(new BezierInterpolator(1.61f, -0.26f)); return animator; }
实现平滑绘图
实现一个绘图功能,基本思路就是处理Touch事件,通过调用lineTo去更新Path,然后通过Canvas的drawPath不断地重绘。然而,这样绘出来的曲线在弯曲处不平滑。如果要绘制出平滑的曲线,就需要用到贝塞尔曲线。Android的Path类的quadTo方法恰恰就封装了二阶贝塞尔曲线的功能。下面看具体的实现代码。
public class BezierDrawView extends View { private float mX; private float mY; private final Paint mGesturePaint = new Paint(); private final Path mPath = new Path(); public BezierDrawView(Context context) { this(context, null); } public BezierDrawView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public BezierDrawView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mGesturePaint.setAntiAlias(true); mGesturePaint.setStyle(Paint.Style.STROKE); mGesturePaint.setStrokeWidth(8); mGesturePaint.setColor(Color.RED); } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: handleDown(event); break; case MotionEvent.ACTION_MOVE: handleMove(event); } invalidate(); return true; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawPath(mPath, mGesturePaint); } private void handleDown(MotionEvent event) { mPath.reset(); float x = event.getX(); float y = event.getY(); mX = x; mY = y; mPath.moveTo(x, y); } private void handleMove(MotionEvent event) { final float x = event.getX(); final float y = event.getY(); final float preX = mX; final float preY = mY; final float dx = Math.abs(x - preX); final float dy = Math.abs(y - preY); //两点之间的距离大于等于3时,生成贝塞尔绘制曲线 if (dx >= 3 || dy >= 3) { //设置贝塞尔曲线的操作点为起点和终点的一半 float cX = (x + preX) / 2; float cY = (y + preY) / 2; //二次贝塞尔,实现平滑曲线;previousX, previousY为操作点,cX, cY为终点 mPath.quadTo(preX, preY, cX, cY);// mPath.lineTo(x, y); mX = x; mY = y; } }}
对比一下通过quadTo和lineTo绘制出来曲线的不同,左边的曲线比右边的曲线要平滑一些,仔细看右边的图会发现曲线上有明显的拐角。
下面是贝塞尔曲线在Android中应用的最终动效图,我们把三个功能集成到了一个页面中。
点我下载Demo
参考文章:
http://www.cnblogs.com/benhero/p/4377374.html?utm_source=tuicool&utm_medium=referral
http://blog.csdn.net/androidzhaoxiaogang/article/details/8680330
- 贝塞尔曲线在Android中的应用
- 贝塞尔曲线原理以及在android中的应用
- Bezier曲线在Android动画中的应用
- 贝塞尔曲线在css3中的应用
- Android-贝塞尔曲线应用
- opencv3逼近多边形曲线-approxPolyDP函数在图像中的应用
- opencv3逼近多边形曲线-在图像中的应用-滚动条
- opencv3逼近多边形曲线-approxPolyDP函数在图像中的应用
- android贝塞尔曲线的简单应用
- android view-贝塞尔曲线应用实例
- Android贝塞尔曲线的理解与应用
- Android 贝塞尔曲线简单应用(一)
- Android 中的贝塞尔曲线分析详解
- 贝塞尔曲线移动 应用
- 贝塞尔曲线的应用
- 贝塞尔曲线的应用
- 贝塞尔曲线的应用
- 贝塞尔曲线应用
- Andriod Checkbox
- 使用js实现上移、下移、置顶、置底功能及源码案例
- HDU 4391 Paint The Wall
- 【c++】第十二周上机实践作业 项目 1-2
- Python中tile函数的用法
- 贝塞尔曲线在Android中的应用
- CSS选择器总结
- 服务器上的Mysql表全丢了情况下恢复数据
- R语言入门
- AndFix热修复 —— 实战与源码解析
- Problem N
- Oracle,视图,序列,索引
- 拼接最小字典序
- 1001. 害死人不偿命的(3n+1)猜想