贝塞尔曲线的应用
本文参考了
http://blog.csdn.net/qq_21430549/article/details/50040241
本文以QQ消息气泡的拖拉为demo来讲解 保证代码简单暴力 有不足的地方希望大家可以指出
demo的github地址 https://github.com/zhangdt/Bezier
效果图:
代码就重写一个View而已 代码如下:
**
* Created by abner on 2016/8/6.
*/
public class BubbleView extends View {
private Paint paint; //定义一个画笔
private float startX=100 ; //默认开始的位置
private float startY =100;
private float moveX ; //手指移动时的位置
private float moveY ;
private float anchorX; //贝塞尔的控制点位置
private float anchorY;
private float radius = 50; //默认圆的半径大小
private float radius2 = 50;
private boolean isMove = false;
private Path path;
public BubbleView(Context context) {
super(context);
init();
}
public BubbleView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public BubbleView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
//初始化
private void init() {
path = new Path();
paint = new Paint();
paint.setColor(Color.RED);
paint.setStyle(Paint.Style.FILL);
}
@Override
protected void onDraw(Canvas canvas) {
// super.onDraw(canvas);
if (!isMove)
canvas.drawCircle(startX, startY, radius2, paint);
if (isMove)
{
//关键代码 单独解释
Log.d(“TAG”,”———————draw”);
anchorX = (moveX+ startX)/2;
anchorY = (moveY + startY)/2;
float offsetX = (float) (radius*Math.sin(Math.atan((moveY - startY) / (moveX - startX))));
float offsetY = (float) (radius*Math.cos(Math.atan((moveY - startY) / (moveX - startX))));
float distance = (float) Math.sqrt(Math.pow(moveY-startY, 2) + Math.pow(moveX-startX, 2));
radius2 = -distance/15+50;
float offsetX2 = (float) (radius2*Math.sin(Math.atan((moveY - startY) / (moveX - startX))));
float offsetY2 = (float) (radius2*Math.cos(Math.atan((moveY - startY) / (moveX - startX))));
float x1 = startX - offsetX2;
float y1 = startY + offsetY2;
float x2 = moveX - offsetX;
float y2 = moveY + offsetY;
float x3 = moveX + offsetX;
float y3 = moveY - offsetY;
float x4 = startX + offsetX2;
float y4 = startY - offsetY2;
// Log.d(“TAG”, “anchorX :”+anchorX+”\n”+
// “anchorY: “+anchorY +”\n”+
// “x1:”+x1+”\n”+
// “y1:”+y1+”\n”+
// “x2:”+x2+”\n”+
// “y2:”+y2+”\n”+
// “x3:”+x3+”\n”+
// “y3:”+y3+”\n”+
// “x4:”+x4+”\n”+
// “y4:”+y4+”\n”+””
//
// );
if (!(radius2<=10)) {
canvas.drawCircle(startX, startY, radius2, paint);
path.reset();
path.moveTo(x1, y1);
path.quadTo(anchorX, anchorY, x2, y2);
path.lineTo(x3, y3);
path.quadTo(anchorX, anchorY, x4, y4);
path.lineTo(x1, y1);
canvas.drawPath(path, paint);
}
canvas.drawCircle(moveX, moveY, radius, paint);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
// Log.d(“TAG”,”Event:+++++++++++++++++++”);
//监听触摸事件 在不同的事件中给不同的属性赋值 并刷新界面
if (event.getAction() == MotionEvent.ACTION_DOWN) {
startX = event.getX();
startY = event.getY();
isMove = true;
Log.d(“TAG”,”downX:”+startX);
Log.d(“TAG”,”downY:”+startY);
} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
moveX = event.getX();
moveY = event.getY();
Log.d("TAG","MoveX:"+moveX);
Log.d("TAG","MoveY:"+moveY);
invalidate();
} else if (event.getAction() == MotionEvent.ACTION_UP) {
isMove = false;
radius2 = 50;
invalidate();
}
return true;
}
}
关键内容:
所以我们要画2条二介的曲线来达到这种效果 就必须有6个点
因为贝塞尔的quadTo(控制点x,控制点y,最后的位置 x ,最后的位置 y);
所以要 2个起点 2个终点 和2个控制点 但2个控制点是一样的
控制点:
anchorX = (moveX + startX) / 2;
anchorY = (moveY + startY) / 2;
这个是控制点 由 移动的位置加开始的位置/2 得到的就是2点中间的那个点 自己计算下就知道了
2个起点 和2个终点要怎么计算呢
这是计算4个点的代码
float offsetX = (float) (radius * Math.sin(Math.atan((moveY - startY) / (moveX - startX))));
float offsetY = (float) (radius * Math.cos(Math.atan((moveY - startY) / (moveX - startX))));
float distance = (float) Math.sqrt(Math.pow(moveY - startY, 2) + Math.pow(moveX - startX, 2));
radius2 = -distance / 15 + 50;
float offsetX2 = (float) (radius2 * Math.sin(Math.atan((moveY - startY) / (moveX - startX))));
float offsetY2 = (float) (radius2 * Math.cos(Math.atan((moveY - startY) / (moveX - startX))));
float x1 = startX - offsetX2;
float y1 = startY + offsetY2;
float x2 = moveX - offsetX;
float y2 = moveY + offsetY;
float x3 = moveX + offsetX;
float y3 = moveY - offsetY;
float x4 = startX + offsetX2;
float y4 = startY - offsetY2;
这里有2个radius 是用来实现拉伸时原先那个圆的大小会改变 这个不是我们要讲的重点 可以忽略
加上自己手画的一张图 那些三角函数如果不理解自己百度一下
图丑—————————————-
然后接下来就利用这几个点来画曲线了
canvas.drawCircle(startX, startY, radius2, paint);
path.reset();
path.moveTo(x1, y1);
path.quadTo(anchorX, anchorY, x2, y2);
path.lineTo(x3, y3);
path.quadTo(anchorX, anchorY, x4, y4);
path.lineTo(x1, y1);
canvas.drawPath(path, paint);
如果有不理解或者不足不好的地方的地方 可以评论下 互相学习互相进步 感谢你的阅览