Android_贝塞尔曲线
来源:互联网 发布:网络语言粗鄙化的原因 编辑:程序博客网 时间:2024/06/07 02:59
一、贝塞尔函数
使用贝塞尔函数可以画平滑的曲线,经常使用的是二阶的贝塞尔函数
//二阶贝赛尔 //参数中(x1,y1)是控制点坐标,(x2,y2)是终点坐标public void quadTo(float x1, float y1, float x2, float y2)
//dx1:控制点X坐标,表示相对上一个终点X坐标的位移坐标,可为负值,正值表示相加,负值表示相减;//dy1:控制点Y坐标,相对上一个终点Y坐标的位移坐标。同样可为负值,正值表示相加,负值表示相减;//dx2:终点X坐标,同样是一个相对坐标,相对上一个终点X坐标的位移值,可为负值,正值表示相加,负值表示相减;//dy2:终点Y坐标,同样是一个相对,相对上一个终点Y坐标的位移值。可为负值,正值表示相加,负值表示相减;public void rQuadTo(float dx1, float dy1, float dx2, float dy2)
使用二阶的贝塞尔函数 quadTo 方法画如下的曲线
这是再简单不过的代码,参照注释可以理解
public class MyBezier extends View {Context mContext;Path mPath;Paint mPaint;public MyBezier(Context context) {this(context,null);}public MyBezier(Context context, AttributeSet attrs) { super(context, attrs); mContext=context; init(mContext);}public void init(Context context){ mPath=new Path(); mPaint=new Paint(); mPaint.setColor(0xffff0000); //设置抗锯齿 mPaint.setAntiAlias(true); mPaint.setStyle(Paint.Style.STROKE);}//这个是核心的方法@Overrideprotected void onDraw(Canvas canvas) { super.onDraw(canvas); //这个方法中填起点坐标,也就是图中的P0 mPath.moveTo(100,300); //参数1和参数2:表示控制点,也就是图中的P1 //参数3和参数4:表示终点,也就是图中的P2 mPath.quadTo(200,100,300,300); //参数的含义和上面的一样 mPath.quadTo(400,500,500,300); canvas.drawPath(mPath,mPaint); }}
整条线的起始点是通过Path.moveTo(x,y)来指定的,而如果我们连续调用quadTo(),前一个quadTo()的终点,就是下一个quadTo()函数的起点,参照上面的代码可以看出,两个quadTo()之间并没有moveTo()方法,来指定起点,这是因为quadTo()连续调用,系统默认为下一个quadTo()方法的起点是上一个quadTo()的终点。
如果初始没有调用Path.moveTo(x,y)来指定起始点,则默认以控件左上角(0,0)为起始点
二、用手指划没有棱角的曲线
一,有棱角的曲线
如果不使用贝塞尔曲线去画一条曲线,你会发现曲线有棱角,代码和效果如如下
,仔细观察效果图,可以发现,曲线部分有很明显的棱角,使用贝塞尔曲线,就可以消除这种棱角
两个地方需要注意:
第一:有关在case MotionEvent.ACTION_DOWN时return true的问题:return true表示当前控件已经消费了下按动作,之后的ACTION_MOVE、ACTION_UP动作也会继续传递到当前控件中;如果我们在case MotionEvent.ACTION_DOWN时return false,那么后序的ACTION_MOVE、ACTION_UP动作将不会再传递该控件
第二:这里重绘控件使用的是invalidate();当然也可以使用postInvalidate()函数的。这两个函数的作用都是用来重绘控件的,但区别是invalidate()一定要在UI线程执行,如果不是在UI线程就会报错。而postInvalidate()则没有那么多讲究,它可以在任何线程中执行,而不必一定要是主线程。其实在postInvalidate()就是利用handler给主线程发送刷新界面的消息来实现的,所以它是可以在任何线程中执行,而不会出错。而正是因为它是通过发消息来实现的,所以它的界面刷新可能没有直接调Invalidate()刷的那么快
所以在我们确定当前线程是主线程的情况下,还是以invalide()函数为主。当我们不确定当前要刷新页面的位置所处的线程是不是主线程的时候,还是用postInvalidate为好
二,没有棱角的曲线(使用qaudTo方法)
代码如下,代码不是很多,主要理解其中的核心思想.代码中的核心是onTouchEvent方法中逻辑,我们来分析一下
画线分为两个部分,一个是画直线,一个是画曲线,所以代码中的逻辑要符合这两个部分,不能只画曲线,而代码的逻辑不符合画直线的思想.
1.画直线的分析(主要分析onTouchEvent的中的代码)
假设我们的起始点在(0,0),向终点(10,10)画直线(直线上的其它点省略)
mPreX=0,mPreY=0; endX=5,endY=5;
quadTo的参数为quadTo(0,0,5,5); 也就是说控制点是(0,0),终点是(5,5),起点也是(0,0),所以简单的分析,就可以得出,图形为直线
2.画曲线的分析(主要分析onTouchEvent的中的代码)
假设我们的起始点在(0,0),在(10,10)处拐了个弯,终点是(20,10)(直线上的其它点省略)
大致图形如下
(1)moveTo方法中的参数:moveTo(0,0),但是mPreX和mPreY并不是(0,0),因为在执行MotionEvent.ACTION_MOVE方法的时候已经将mPreX和mPreY的点改为了(10,10),也就是图中的B.当到达C点时,画曲线就结束了,这时候个方法的参数如下
mPath.moveTo(0,0)mPath.quadTo(10,10,20,10);
三、动态的水波
下面的代码实现了水波的效果,主要是属性动画和贝塞尔函数的结合
下面这几篇是关于属性动画(Animator)的使用
http://blog.csdn.net/iispring/article/details/50322625
http://blog.csdn.net/guolin_blog/article/details/43536355
http://blog.csdn.net/guolin_blog/article/details/43536355
public class MyView5 extends View { Path mPath; Context mContext; Paint mPaint; // 单个波的长度 int mWaveLength = 900; // 波的高度 int mWaveHeight = 700; // 水平漂移 int distanceX = 0; // 动画 ValueAnimator mValueAnimator;public MyView5(Context context) { this(context, null);}public MyView5(Context context, AttributeSet attrs) { super(context, attrs); init(context);}//这句话的意思是只有在level大于21的版本才能使用@TargetApi(Build.VERSION_CODES.LOLLIPOP)private void init(Context context) {mPath = new Path();mPaint = new Paint();mPaint.setColor(Color.BLUE);mPaint.setAntiAlias(true);mPaint.setStyle(Paint.Style.FILL);mContext = context;//设置动画为颜色的变化//从0xffff0000渐变到0xff00ff00,再到0xff0000ff//周期为6s,匀速变化mValueAnimator = ValueAnimator.ofArgb(0xffff0000, 0xff00ff00, 0xff0000ff);mValueAnimator.setDuration(6000);mValueAnimator.setInterpolator(new LinearInterpolator());//动画的监听,在这个例子中也就是颜色改变,就实现下面的回调mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float fraction = animation.getAnimatedFraction(); // 计算漂移量 distanceX = (int) (mWaveLength * fraction * 10); // 画笔颜色 mPaint.setColor((Integer) animation.getAnimatedValue()); // 重绘 invalidate(); }});startAnim();}@Overrideprotected void onDraw(Canvas canvas) {// 1/4水波宽度int halfWaveLength = mWaveLength / 2;//将mPath清空mPath.reset();//在这里需要注意,比较容易懵逼//distanceX % mWaveLength的值不会大于一个波长//所以-mWaveLength + distanceX % mWaveLength的值不会大于零mPath.moveTo(-mWaveLength + distanceX % mWaveLength, mWaveHeight++);// 绘制n个波,每个波由两个二阶曲线组成for (int i = -mWaveLength; i <= getWidth() + mWaveLength; i += mWaveLength) {mPath.rQuadTo(halfWaveLength / 2, -100, halfWaveLength, 0);mPath.rQuadTo(halfWaveLength / 2, 100, halfWaveLength, 0);}// 封闭水波之下的区域mPath.lineTo(getWidth(), getHeight());mPath.lineTo(0, getHeight());mPath.close();canvas.drawPath(mPath, mPaint);} //暂时用不到public void reset() { mPath.reset(); distanceX = 0; mWaveHeight = 700; invalidate(); } //动画的开启public void startAnim() { mValueAnimator.start(); }}
- Android_贝塞尔曲线
- 曲线平滑-贝塞尔曲线
- 贝塞尔曲线
- 贝塞尔曲线
- 贝塞尔曲线
- 贝塞尔曲线
- 贝塞尔曲线
- 贝塞尔曲线
- 贝塞尔曲线
- 贝塞尔曲线
- 贝塞尔曲线
- 贝塞尔曲线
- 贝塞尔曲线
- 贝塞尔曲线
- 贝塞尔曲线
- 贝塞尔曲线
- 贝塞尔曲线
- 贝塞尔曲线
- 欢迎使用CSDN-markdown编辑器
- Android编程规范
- Android 闹钟AlarmManager简略使用说明
- 域名解析过程和域名劫持、域名污染
- 暑期集训之Trailing Zeroes (III)
- Android_贝塞尔曲线
- HDU 2612 Find a way 简单BFS
- ERROR:../../gi/pygi-argument.c:1586:
- 计算机网络、OSI模型、TCP\IP族
- lua 创建二维数组
- svn 拉分支
- google代理服务器设置
- Python中如何使用以及去除时间序列数据中的趋势信息
- 记录下CSDN博客排上名,嘻嘻,不再是千里之外了