贝塞尔制作水平移动带弹性的圆
来源:互联网 发布:视频加速器软件 编辑:程序博客网 时间:2024/06/08 06:58
今天我们来学习怎么制作水平移动带弹性的圆,先上效果图:
下面讲解一下具体的步骤,在了解之前大家先看一张图,后面的代码可以参考这张图:
接下来上代码,可以分成两个部分,一个是易懂,一个是变形,注释做的比较全,大家可以参考:
是不是很容易,理解,大家可以自己练习一下:
import android.content.Context;import android.graphics.Canvas;import android.graphics.Paint;import android.graphics.Path;import android.graphics.PointF;import android.util.AttributeSet;import android.view.View;import android.view.animation.AccelerateDecelerateInterpolator;import android.view.animation.Animation;import android.view.animation.Transformation;/** * 代码写的比较仓猝,以后再优化写法和补充那些数值的具体含义,求勿喷QAQ */public class MagicCircle extends View { private Path mPath; private Paint mFillCirclePaint; /** * View的宽度 **/ private int width; /** * View的高度,这里View应该是正方形,所以宽高是一样的 **/ private int height; private float maxLength; private float mInterpolatedTime; private float stretchDistance; private float cDistance; private float radius; private float c; private float blackMagic = 0.551915024494f; //这是三次贝塞尔式的常量,详解请见:http://spencermortensen.com/articles/bezier-circle/ /* * 下面定义了p1, p2, p3, p4,四个对象,人要想明明是四个控制点,为什么要定义四个对象呢,因为这里是为了把这四个点和他们的辅助点联系在一起, * 所以总共应该是四个控制点和八个辅助点 * */ private VPoint p2, p4; //定义了p2,p4两个对象,即圆的上面两个点,一个是右边的点,一个是左边的点 private HPoint p1, p3; //定义了p1,p3两个对象,即圆的上面两个点,一个是下边的点,一个是上面边的点 public MagicCircle(Context context) { this(context, null, 0); } public MagicCircle(Context context, AttributeSet attrs) { this(context, attrs, 0); } public MagicCircle(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { /* * 下面设置一些这个圆的参数,包括颜色,圆边框宽度(因为圆被填充了,所以也看不出来),还有抗锯齿 * */ mFillCirclePaint = new Paint(); mFillCirclePaint.setColor(0xFFfe626d); mFillCirclePaint.setStyle(Paint.Style.FILL); mFillCirclePaint.setStrokeWidth(1); mFillCirclePaint.setAntiAlias(true); mPath = new Path(); p2 = new VPoint(); p4 = new VPoint(); p1 = new HPoint(); p3 = new HPoint(); } /* * 下面用来初始化一些数据 * */ @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); width = getWidth(); height = getHeight(); radius = 50; c = radius * blackMagic; stretchDistance = radius; cDistance = c * 0.45f; maxLength = width - radius / 8; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mPath.reset(); //每次绘制前要重置路径 canvas.translate(radius, radius); //这里将坐标中心点移至圆心,这样的话是分两步的,这里用来处理位移,下面的几个方法用来处理变形,好理解一些 if (mInterpolatedTime >= 0 && mInterpolatedTime <= 0.2) { model1(mInterpolatedTime); } else if (mInterpolatedTime > 0.2 && mInterpolatedTime <= 0.5) { model2(mInterpolatedTime); } else if (mInterpolatedTime > 0.5 && mInterpolatedTime <= 0.8) { model3(mInterpolatedTime); } else if (mInterpolatedTime > 0.8 && mInterpolatedTime <= 0.9) { model4(mInterpolatedTime); } else if (mInterpolatedTime > 0.9 && mInterpolatedTime <= 1) { model5(mInterpolatedTime); } float offset = maxLength * (mInterpolatedTime - 0.2f); offset = offset > 0 ? offset : 0; /* * 下面四行用来将圆形进行水平滑动,大家可以先注释掉,然后就能更加清楚的看见圆形的变化过程,不受位移的影响了 * */ p1.adjustAllX(offset); p2.adjustAllX(offset); p3.adjustAllX(offset); p4.adjustAllX(offset); /* *经过上面的一系列判断和调整,四个点和八个辅助点的位置都固定好了,然后将圆分成四个部分,然后连接路径,最后绘制 * */ mPath.moveTo(p1.x, p1.y); mPath.cubicTo(p1.right.x, p1.right.y, p2.bottom.x, p2.bottom.y, p2.x, p2.y); mPath.cubicTo(p2.top.x, p2.top.y, p3.right.x, p3.right.y, p3.x, p3.y); mPath.cubicTo(p3.left.x, p3.left.y, p4.top.x, p4.top.y, p4.x, p4.y); mPath.cubicTo(p4.bottom.x, p4.bottom.y, p1.left.x, p1.left.y, p1.x, p1.y); canvas.drawPath(mPath, mFillCirclePaint); } /* * 给四个点做初始化,各自固定好位置,等下用来变形 * */ private void model0() { p1.setY(radius); p3.setY(-radius); p3.x = p1.x = 0; p3.left.x = p1.left.x = -c; p3.right.x = p1.right.x = c; p2.setX(radius); p4.setX(-radius); p2.y = p4.y = 0; p2.top.y = p4.top.y = -c; p2.bottom.y = p4.bottom.y = c; } /* * 初始化过后我们要做的第一件事就是移动p2这个点,将p2往右移,移动距离从0到stretchDistance * time * 5,也就是整个圆的半径大小(此时达到圆的最大横向长度,3倍圆半径), * 给人的感觉是右边被拉了,其他不变,长度为一个半径 * */ private void model1(float time) {//0~0.2 model0(); p2.setX(radius + stretchDistance * time * 5); } /* *这里做了两个处理,一个是p1,p3横坐标的移动,也就是往右移,然后就是p2,p4的四个辅助点的纵坐标,这样的话移动过程中就会有弯曲的感觉了,只要做稍稍调整即可, * 观察的效果给人感觉是圆形从左往右移,长度为一个半径,左右有向内凹的感觉 * */ private void model2(float time) {//0.2~0.5 model1(0.2f); time = (time - 0.2f) * (10f / 3); p1.adjustAllX(stretchDistance / 2 * time); p3.adjustAllX(stretchDistance / 2 * time); p2.adjustY(cDistance * time); p4.adjustY(cDistance * time); } /* * 这里的处理和上面其实是差不多的,只不过全部反过来处理了,易懂,最后还移动p4的位置,保持圆的横向长度不变(此时圆横向长度应为3倍圆半径), * 左右两边给人凸起来的感觉 * */ private void model3(float time) {//0.5~0.8 model2(0.5f); time = (time - 0.5f) * (10f / 3); p1.adjustAllX(stretchDistance / 2 * time); p3.adjustAllX(stretchDistance / 2 * time); p2.adjustY(-cDistance * time); p4.adjustY(-cDistance * time); p4.adjustAllX(stretchDistance / 2 * time); } /* * 这里将p4多往右边移动了一点,目的是为了等下的回弹,这样的话给人的感觉是比较正常的 * */ private void model4(float time) {//0.8~0.9 model3(0.8f); time = (time - 0.8f) * 10; p4.adjustAllX(stretchDistance / 2 * time); } /* * 这里直接用函数回弹p4的坐标 * */ private void model5(float time) { model4(0.9f); time = time - 0.9f; p4.adjustAllX((float) (Math.sin(Math.PI * time * 10f) * (2 / 10f * radius))); } /* * 这个类用来定义p2和p4,因为只有这两个点拥有top和Botton这样的辅助点 * */ class VPoint { public float x; public float y; public PointF top = new PointF(); public PointF bottom = new PointF(); /* * 用来设置控制点和辅助点的起始位置 * */ public void setX(float x) { this.x = x; top.x = x; bottom.x = x; } /* * 仅控制辅助点的位置 * */ public void adjustY(float offset) { top.y -= offset; bottom.y += offset; } /* * 控制控制点和辅助点的位置 * */ public void adjustAllX(float offset) { this.x += offset; top.x += offset; bottom.x += offset; } } /* * 这个类用来定义p1和p2,因为只有这两个点拥有left和right这样的辅助点 * */ class HPoint { public float x; public float y; public PointF left = new PointF(); public PointF right = new PointF(); public void setY(float y) { this.y = y; left.y = y; right.y = y; } public void adjustAllX(float offset) { this.x += offset; left.x += offset; right.x += offset; } } /* * 下面的动画用来控制时间,然后动态刷新界面,从而达到流畅的效果 * */ private class MoveAnimation extends Animation { @Override protected void applyTransformation(float interpolatedTime, Transformation t) { super.applyTransformation(interpolatedTime, t); mInterpolatedTime = interpolatedTime; invalidate(); } } /* * 对外开放的函数,用来开始动画 * */ public void startAnimation() { mPath.reset(); mInterpolatedTime = 0; MoveAnimation move = new MoveAnimation(); move.setDuration(10000); //用来设置动画时长 move.setInterpolator(new AccelerateDecelerateInterpolator()); //move.setRepeatCount(Animation.INFINITE); //move.setRepeatMode(Animation.REVERSE); startAnimation(move); }}
最后给出项目代码:
https://github.com/DevinShine/MagicCircle
参考文章:
http://www.jianshu.com/p/791d3a791ec2
http://blog.csdn.net/u013831257/article/details/51281136
0 0
- 贝塞尔制作水平移动带弹性的圆
- Android带弹性的View
- Box2d弹性物体的制作
- 带弹性的侧滑菜单
- 实现图片的水平移动
- 贝塞尔曲线练习之弹性的圆
- 比较好用的带弹性和刷新的ScrollView
- 简单自定义水平的ProgressBar带文字
- 垂直-水平导航菜单的制作
- HTML5--javaScript制作的水平下拉菜单
- 移动web页面支持弹性滚动的3个方案
- 适合移动mobile的css3弹性堆叠图片切换特效
- 移动web页面支持弹性滚动的3个方案
- 移动web页面支持弹性滚动的3个方案
- 移动web页面支持弹性滚动的3个方案
- 移动Web支持弹性滚动的3个方案
- HTML5-移动开发常用技巧与弹性布局的使用
- css设置标签的水平与垂直居中,定位与弹性盒布局的的结合
- 修改数据库的数据元素小技巧
- 学习curses图形库(二)
- tensorflow:mnis入门代码注释
- setClickable(点击)、setEnabled(总开关)、setFocusable(焦点)的区别
- svm推导
- 贝塞尔制作水平移动带弹性的圆
- iOS 中的 Promise 设计模式
- DELPHI中的消息处理机制(三种消息处理方法的比较,如何截断消息)
- android接入支付宝移动端支付
- 模板
- spring资源(jar包)官网下载
- 0513
- Servlet
- umask()函数