高级UI-Path贝塞尔曲线以及练习Demo 水波纹效果

1、rLineTo，rMoveTo 带r开头

LineTo，MovoTo 不带r开头的，传的是我们的绝对位置

Path.Direction.CCW,点击进去看源码,发现一个单词clockwise,意思是顺时针方向,



https://github.com/venshine/BezierMaker — 可以参考

//二阶贝赛尔
public void quadTo(float x1, float y1, float x2, float y2)
public void rQuadTo(float dx1, float dy1, float dx2, float dy2)
//三阶贝赛尔
public void cubicTo(float x1, float y1, float x2, float y2,float x3, float y3)
public void rCubicTo(float x1, float y1, float x2, float y2,float x3, float y3)


https://www.cnblogs.com/wjtaigwh/p/6647114.html

https://segmentfault.com/a/1190000000721127

贝塞尔曲线入门Demo

二阶贝塞尔曲线demo


package android.mybzdemo;

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

/**
* @author liuml
* @explain
* @time 2018/2/6 16:55
*/

public class MyBzView1 extends View {

private Paint paint;
private Path bzPath;
private Point controlPoint = new Point(200, 200);

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

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

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

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
paint = new Paint();
paint.setStyle(Paint.Style.STROKE);
paint.setColor(Color.RED);
paint.setStrokeWidth(10);
paint.setAntiAlias(true);

bzPath = new Path();

bzPath.moveTo(50, 500);

//绘制路径
canvas.drawPath(bzPath, paint);
//绘制控制点
canvas.drawPoint(controlPoint.x, controlPoint.y, paint);

paint.setTextSize(100);
paint.setStrokeWidth(5);
canvas.drawText("二阶贝塞尔曲线", 50, 400, paint);

}

@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
controlPoint.x = (int) event.getX();
controlPoint.y = (int) event.getY();
invalidate();
break;
}

return true;

}
}



三阶贝塞尔曲线Demo

demo效果

package android.mybzdemo;

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

/**
* @author liuml
* @explain
* @time 2018/2/6 16:55
*/

public class MyBzView2 extends View {

private Paint paint;
private Path bzPath;
private Point controlPoint1 = new Point(200, 200);
private Point controlPoint2 = new Point(500, 800);
private int pointDown = 0;// 1 是在第一个控制点2 是在第二个控制点 0 是什么都不在

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

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

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

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
paint = new Paint();
paint.setStyle(Paint.Style.STROKE);
paint.setColor(Color.RED);
paint.setStrokeWidth(10);
paint.setAntiAlias(true);

bzPath = new Path();

//起始点
bzPath.moveTo(50, 500);
bzPath.cubicTo(controlPoint1.x, controlPoint1.y, controlPoint2.x, controlPoint2.y, 700, 500);
//        bzPath.rCubicTo()
//绘制路径
canvas.drawPath(bzPath, paint);

//绘制控制点
canvas.drawCircle(controlPoint1.x, controlPoint1.y, 20, paint);
canvas.drawCircle(controlPoint2.x, controlPoint2.y, 20, paint);
//        canvas.drawPoint(controlPoint1.x, controlPoint1.y, paint);
//        canvas.drawPoint(controlPoint2.x, controlPoint2.y, paint);

paint.setTextSize(100);
paint.setStrokeWidth(5);
canvas.drawText("三阶贝塞尔曲线", 50, 700, paint);
paint.reset();

}

@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//判断按下的点是否在控制点上
int x = (int) event.getX();
int y = (int) event.getY();
if (controlPoint1.x - 20 < x && x < controlPoint1.x + 20
&& controlPoint1.y - 20 < y && y < controlPoint1.y + y) {
//在控制点1上
pointDown = 1;
}
if (controlPoint2.x - 20 < x && x < controlPoint2.x + 20
&& controlPoint2.y - 20 < y && y < controlPoint2.y + y) {
//在控制点2上
pointDown = 2;
}

case MotionEvent.ACTION_MOVE:
if (pointDown == 1) {
controlPoint1.x = (int) event.getX();
controlPoint1.y = (int) event.getY();
}
if (pointDown == 2) {
controlPoint2.x = (int) event.getX();
controlPoint2.y = (int) event.getY();
}

invalidate();
break;
case MotionEvent.ACTION_UP:
pointDown = 0;
break;
}

return true;

}
}



三阶贝塞尔曲线,水波纹效果(失败记录)

===


package android.mybzdemo;

import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

/**
* @author liuml
* @explain 水波纹
* @time 2018/2/6 16:55
*/

public class MyBzView3 extends View {

private static final String TAG = "MyBzView3";
private Paint paint;
private Path bzPath;
//水波纹有四个控制点
private Point controlPoint1 = new Point(200, 200);
private Point controlPoint2 = new Point(500, 800);
private int pointDown = 0;// 1 是在第一个控制点2 是在第二个控制点 0 是什么都不在
int waterHeight = 200;

private boolean controlVisible = true;
int screenWidth;
int screenHeight;
private ValueAnimator animator;
private int curValue;

public MyBzView3(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
DisplayMetrics dm = new DisplayMetrics();
dm = getResources().getDisplayMetrics();
float density = dm.density; // 屏幕密度（像素比例：0.75/1.0/1.5/2.0）
int densityDPI = dm.densityDpi; // 屏幕密度（每寸像素：120/160/240/320）
screenWidth = dm.widthPixels; // 屏幕宽（像素，如：3200px）
screenHeight = dm.heightPixels; // 屏幕高（像素，如：1280px）

controlPoint1.x = screenWidth / 4;

controlPoint1.y = screenHeight / 2 + waterHeight;

controlPoint2.x = screenWidth / 4 * 3;
controlPoint2.y = screenHeight / 2 - waterHeight;

}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);

paint = new Paint();
paint.setColor(Color.GREEN);
paint.setStrokeWidth(10);
paint.setAntiAlias(true);

bzPath = new Path();
//起始点
bzPath.moveTo(-screenWidth+curValue, screenHeight / 2);
//        bzPath.moveTo(-800, 500);
//        bzPath.moveTo(0, screenHeight / 2);
//左边的
bzPath.cubicTo(-controlPoint1.x+curValue, controlPoint1.y, -controlPoint2.x+curValue, controlPoint2.y, curValue, screenHeight / 2);
//        bzPath.cubicTo(-100, 500, -200, 600, 300, 800);
canvas.drawPath(bzPath, paint);
bzPath.cubicTo(controlPoint1.x+curValue, controlPoint1.y, controlPoint2.x+curValue, controlPoint2.y, screenWidth+curValue, screenHeight / 2);
//绘制路径
canvas.drawPath(bzPath, paint);
//        paint.setColor(Color.RED);
//画矩形 从水平线往下
canvas.drawRect(0, screenHeight / 2, screenWidth, screenHeight, paint);
paint.setColor(Color.BLUE);
//绘制控制点
if (controlVisible) {
canvas.drawCircle(controlPoint1.x, controlPoint1.y, 20, paint);
canvas.drawCircle(controlPoint2.x, controlPoint2.y, 20, paint);
}
paint.reset();
}

public void setControlVisible(boolean visible) {
this.controlVisible = visible;
invalidate();
}

public boolean controlVisible() {
return controlVisible;
}

@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//判断按下的点是否在控制点上
int x = (int) event.getX();
int y = (int) event.getY();
if (controlPoint1.x - 20 < x && x < controlPoint1.x + 20
&& controlPoint1.y - 20 < y && y < controlPoint1.y + y) {
//在控制点1上
pointDown = 1;
}
if (controlPoint2.x - 20 < x && x < controlPoint2.x + 20
&& controlPoint2.y - 20 < y && y < controlPoint2.y + y) {
//在控制点2上
pointDown = 2;
}

case MotionEvent.ACTION_MOVE:
if (pointDown == 1) {
controlPoint1.x = (int) event.getX();
controlPoint1.y = (int) event.getY();
}
if (pointDown == 2) {
controlPoint2.x = (int) event.getX();
controlPoint2.y = (int) event.getY();
}
invalidate();
break;
case MotionEvent.ACTION_UP:
pointDown = 0;
break;
}

return true;
}

/**
* 开启动画
*/
public void startAnimator() {
animator = ValueAnimator.ofInt(0, screenHeight / 2, screenWidth, screenHeight / 2);
animator.setDuration(3000);
@Override
public void onAnimationUpdate(ValueAnimator animation) {
curValue = (int) animation.getAnimatedValue();
Log.d(TAG, "onAnimationUpdate: curValue=" + curValue);
Log.d(TAG, "===============================================================" );
postInvalidate();
}
});

animator.setRepeatCount(ValueAnimator.INFINITE);
animator.setRepeatMode(ValueAnimator.RESTART);
animator.start();
//        animator1 = ObjectAnimator.ofFloat(mMybz3,"translationX",0,screenWidth);
//        animator1.setDuration(2000);
//        animator1.setRepeatCount(ValueAnimator.INFINITE);
////        animator1.setRepeatMode();
//        animator1.start();
}

public void stopanimator() {

animator.cancel();
//        animator1.cancel();
}
}



二阶贝塞尔曲线,波浪效果

package android.mybzdemo;

import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.LinearInterpolator;

/**
* @author liuml
* @explain 水波纹
* @time 2018/2/6 16:55
*/

public class MyBzView3 extends View {
private static final String TAG = "MyBzView3";
ValueAnimator animator;
private Path mPath;
private Paint mPaint;
private static final int INT_WAVE_LENGTH = 1000;//波长
private int waveHeight = 60;
private int mDeltax;

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

mPaint = new Paint();
mPaint.setColor(Color.BLUE);
//用这种风格绘制的几何图形和文本将会被填充
//在同一时间抚摸，尊重与中风相关的领域
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);

mPath = new Path();
}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);

//清除路径上的任何线条和曲线，使其为空。 这不会改变文件类型的设置。
mPath.reset();

int orgin = 800;
int halfLength = INT_WAVE_LENGTH / 2;
//起始点移动到左边屏幕的左边,根据不断改变起始点 动态的改变位置
mPath.moveTo(-INT_WAVE_LENGTH + mDeltax, orgin);
//从起始点开始
for (int i = -INT_WAVE_LENGTH; i < getWidth() + INT_WAVE_LENGTH;
i += INT_WAVE_LENGTH) {
mPath.rQuadTo(halfLength / 2, waveHeight, halfLength, 0);
mPath.rQuadTo(halfLength / 2, -waveHeight, halfLength, 0);
}
//上面是画曲线

//下面是画出界面左边和右边的一条线 这样就可以闭合
mPath.lineTo(getWidth(), getHeight());
mPath.lineTo(0, getHeight());
mPath.close();//让线闭合

//把线画出来
canvas.drawPath(mPath, mPaint);
}

/**
* 开启动画
*/
public void startAnimator() {
animator = ValueAnimator.ofInt(0, INT_WAVE_LENGTH);
animator.setDuration(1000);
//设置为线性的
animator.setInterpolator(new LinearInterpolator());
animator.setRepeatCount(ValueAnimator.INFINITE);//无限循环
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mDeltax = (int) animation.getAnimatedValue();
//根据不断改变起始点 动态的改变位置
postInvalidate();
}
});

animator.start();

}

public void stopanimator() {

animator.cancel();
}
}



1、垃圾桶效果

2、充电水波纹效果