1.1.1. -固定值变成变量
固定值变成成员变量
public class StickyView extends View {
private Paint paint;
public StickyView(Context context) {
this(context, null);
}
public StickyView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public StickyView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
//初始化画笔
paint = new Paint(Paint.ANTI_ALIAS_FLAG);//抗锯齿的画笔
paint.setColor(Color.RED);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//定义固定圆圆心和半径
PointF stickCenter = new PointF(600, 600);
float stickRadius = 30f;
//定义拖拽 圆圆心和半径
PointF dragCenter = new PointF(400, 600);
float dragRadius = 60f;
//画固定圆
canvas.drawCircle(stickCenter.x, stickCenter.y, stickRadius, paint);
//画拖拽圆
canvas.drawCircle(dragCenter.x, dragCenter.y, dragRadius, paint);
//固定圆的两个附属点
PointF[] stickPoints = new PointF[]{
new PointF(600, 570),
new PointF(600, 630)
};
//拖拽圆的两个附属点
PointF[] dragPoints = new PointF[]{
new PointF(400, 540),
new PointF(400, 660)
};
//控制点
PointF contrlPoint = new PointF(500, 600);
//画连接部分
Path path = new Path();
path.moveTo(stickPoints[0].x, stickPoints[0].y);//移动点1,如果不设置,开始点就默认为(0,0)
//1-->2画曲线
path.quadTo(contrlPoint.x, contrlPoint.y, dragPoints[0].x, dragPoints[0].y);//参数:控制点坐标,结束点坐标
//2-->3画直线
path.lineTo(dragPoints[1].x, dragPoints[1].y);
//3-->4画曲线
path.quadTo(contrlPoint.x, contrlPoint.y, stickPoints[1].x, stickPoints[1].y);
canvas.drawPath(path, paint);
}
}
1.1.2. -计算变量
复制老师提供的一个几何类GeometryUtil
//计算四个附着点
float yOffset = stickCenter.y - dragCenter.y;
float xOffset = stickCenter.x - dragCenter.x;
Double lineK = null;//斜线与两圆心连接直线的斜率
if (xOffset != 0) {
lineK = Double.valueOf(yOffset / xOffset);
}
PointF[] dragPoints = GeometryUtil.getIntersectionPoints(dragCenter, dragRadius, lineK);
PointF[] stickPoints = GeometryUtil.getIntersectionPoints(stickCenter, stickRadius, lineK);
//画出四个附着点(检测用的)
paint.setColor(Color.BLUE);//用蓝色画
canvas.drawCircle(dragPoints[0].x, dragPoints[0].y, 3f, paint);
canvas.drawCircle(dragPoints[1].x, dragPoints[1].y, 3f, paint);
canvas.drawCircle(stickPoints[0].x, stickPoints[0].y, 3f, paint);
canvas.drawCircle(stickPoints[1].x, stickPoints[1].y, 3f, paint);
paint.setColor(Color.RED);//恢复原来的颜色
//控制点(两个圆心的中点)
PointF contrlPoint = GeometryUtil.getMiddlePoint(stickCenter, dragCenter);
1.1.3. -根据触摸事件动态绘制
-根据两个圆心的距离,动态计算固定圆的半径
@Override
public boolean onTouchEvent(MotionEvent event) {
float x;
float y;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
x = event.getRawX();
y = event.getRawY();
//更新拖拽圆的圆心
updateDragCenter(x, y);
break;
case MotionEvent.ACTION_MOVE:
x = event.getRawX();
y = event.getRawY();
//更新拖拽圆的圆心
updateDragCenter(x, y);
break;
case MotionEvent.ACTION_UP:
break;
}
return true;//自己消费事件
}
//获取状态栏高度
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
//为了解决手势不同步的问题,需要将画布上移动状态栏的高度
//状态栏的高度
statusBarHeight = Utils.getStatusBarHeight(this);
}
/**
* 更新拖拽圆的圆心
*/
private void updateDragCenter(float x, float y) {
dragCenter.set(x, y);
invalidate();
}
1.1.4. -事件处理
-超出范围断开,松手消失
-超出范围断开,又放回去了,恢复
-没有超出范围,松手,回弹恢复
@Override
public boolean onTouchEvent(MotionEvent event) {
float x;
float y;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
isOutofRange = false;
x = event.getRawX();
y = event.getRawY();
if (!isDisappear) {
//更新拖拽圆的圆心
updateDragCenter(x, y);
}
break;
case MotionEvent.ACTION_MOVE:
x = event.getRawX();
y = event.getRawY();
//更新拖拽圆的圆心
updateDragCenter(x, y);
//超出范围断开
float dt = GeometryUtil.getDistanceBetween2Points(stickCenter, dragCenter);
if (dt > dtMax) {
isOutofRange = true;
invalidate();
}
break;
case MotionEvent.ACTION_UP:
if (isOutofRange) { //超出范围
float dis = GeometryUtil.getDistanceBetween2Points(stickCenter, dragCenter);
if (dis > dtMax) {
Log.e(TAG, "超出范围,松手消失");
isDisappear = true;
invalidate();
} else if (dis <= dtMax) {
Log.e(TAG, "超出范围,又放回去了,松手恢复");
//更新固定圆圆心
updateDragCenter(stickCenter.x, stickCenter.y);
}
} else { //没有超出范围
final PointF startP = new PointF(dragCenter.x, dragCenter.y);
Log.e(TAG, "没有超出范围,松手回弹恢复: ");
ValueAnimator va = ValueAnimator.ofFloat(1.0f);
va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animator) {
float fraction = animator.getAnimatedFraction();
Log.e(TAG, "fraction: " + fraction);
//计算开始点startP到结束点stickCenter之间的所有点
PointF p = GeometryUtil.getPointByPercent(startP, stickCenter, fraction);
updateDragCenter(p.x, p.y);
}
});
//插补器
va.setInterpolator(new OvershootInterpolator(5));
va.setDuration(500);
va.start();
}
break;
}
return true;//自己消费事件
}
在ondraw()里面判断:
没有超出范围才绘制固定圆
没有dispear才绘制拖拽圆
1.1.5. -事件监听回调
//监听事件
public interface OnUpdateListener {
/**
* 让小圆点消失调用的方法
*/
void onDisappear(PointF mDragCenter);
/**
* 根据是否超出了范围来做对应操作的方法
*/
void onReset(boolean isOutofRange);
}
public void setmOnUpdateListener(OnUpdateListener mOnUpdateListener) {
this.mOnUpdateListener = mOnUpdateListener;
}
调用:
if (isOutofRange) { //超出范围
float dis = GeometryUtil.getDistanceBetween2Points(stickCenter, dragCenter);
if (dis > dtMax) {
Log.e(TAG, "超出范围,松手消失");
isDisappear = true;
invalidate();
if (mOnUpdateListener != null) {
mOnUpdateListener.onDisappear(dragCenter);
}
} else if (dis <= dtMax) {
Log.e(TAG, "超出范围,又放回去了,松手恢复");
//更新固定圆圆心
updateDragCenter(stickCenter.x, stickCenter.y);
if (mOnUpdateListener != null) {
mOnUpdateListener.onReset(true);
}
}
} else { //没有超出范围
final PointF startP = new PointF(dragCenter.x, dragCenter.y);
Log.e(TAG, "没有超出范围,松手回弹恢复: ");
ValueAnimator va = ValueAnimator.ofFloat(1.0f);
va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animator) {
float fraction = animator.getAnimatedFraction();
Log.e(TAG, "fraction: " + fraction);
//计算开始点startP到结束点stickCenter之间的所有点
PointF p = GeometryUtil.getPointByPercent(startP, stickCenter, fraction);
updateDragCenter(p.x, p.y);
}
});
va.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
//动画执行完毕了,就调用接口
if (mOnUpdateListener != null) {
mOnUpdateListener.onReset(false);
}
}
});
//插补器
va.setInterpolator(new OvershootInterpolator(5));
va.setDuration(500);
va.start();
}
break;
}