1.贝塞尔曲线分析图
贝塞尔.jpg2.效果图
所有view拖拽.gif好了,这就是我们今天要写的内容。
3.效果分析
看过我上一篇文章的同学,就知道,我们要画拖拽点,需要画两个点,一个是固定点,一个是拖拽点。
这里的固定点就是view的中心点
int[] location = new int[2];
mView.getLocationOnScreen(location);
Bitmap bitmap = getBitmapByView(mView);
mDragView.initPoint(location[0] + bitmap.getWidth()/2,location[1] + bitmap.getHeight()/2 - getStatusBarHeight(v.getContext()));
这是初始化的时候要设置的点。拖拽点会随着滑动而移动,然后不断的绘制
case MotionEvent.ACTION_MOVE:
mDragView.updatePoint(event.getRawX(),event.getRawY() - getStatusBarHeight(v.getContext()));
break;
/**
* 更新座标点
* @param moveX
* @param moveY
*/
public void updatePoint(float moveX, float moveY) {
mDragPointF.x = moveX;
mDragPointF.y = moveY;
invalidate();
}
不断的取更新试图就可以了。
在绑定试图的时候,创建覆盖view
public class MainActivity extends AppCompatActivity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DragView.bindDragView(findViewById(R.id.tv), new DragViewTouchListener.DragViewListener() {
@Override
public void dismiss(View view) {
Log.d("TAG","dismiss");
}
});
DragView.bindDragView(findViewById(R.id.iv), new DragViewTouchListener.DragViewListener() {
@Override
public void dismiss(View view) {
Log.d("TAG","dismiss");
}
});
}
}
在 DragViewTouchListener 的构造函数里面,通过windowmanager创建可拖拽的view,并保存原始的view
//记录自己的view
private View mView;
private WindowManager mWindowManager;
//构造的view
private DragView mDragView;
private WindowManager.LayoutParams mParams;
//爆炸容器
private FrameLayout mBombLayout;
private ImageView mBombImage;
private DragViewListener mDragViewListener;
public DragViewTouchListener(View view, DragViewListener dragViewListener){
mDragViewListener = dragViewListener;
mView = view;
mWindowManager = (WindowManager) view.getContext().getSystemService(Context.WINDOW_SERVICE);
mDragView = new DragView(view.getContext());
mDragView.setDragViewCallBackListener(this);
//全屏拖动
mParams = new WindowManager.LayoutParams();
//设置背景透明
mParams.format = PixelFormat.TRANSLUCENT;
mBombLayout = new FrameLayout(view.getContext());
mBombImage = new ImageView(view.getContext());
mBombLayout.addView(mBombImage);
}
然后在onTouch事件的 down事件里面 把自己的view隐藏 把拖拽view添加到windowManager中而且要是在原始view的位置。把原始view转中bitmap设置到拖拽view上,这样就看不出来了。
/**
* 从一个view中获取bitmap
* @param mView
* @return
*/
private Bitmap getBitmapByView(View mView) {
mView.buildDrawingCache();
Bitmap bitmap = mView.getDrawingCache();
return bitmap;
}
/**
* 设置bitmao
* @param bitmap
*/
public void setDragBitmap(Bitmap bitmap) {
this.mDragBitmap = bitmap;
invalidate();
}
4.onDraw 绘制
如果mDragBitmap不空记得绘制这个bitmap
@Override
protected void onDraw(Canvas canvas) {
if (mDragPointF == null || mDragPaint == null) {
return;
}
if(this.mDragBitmap != null){
int width = mDragBitmap.getWidth() > mDragBitmap.getHeight() ? mDragBitmap.getWidth() : mDragBitmap.getHeight();
mDragRadius = width / 4;
}
//画拖拽圆
canvas.drawCircle(mDragPointF.x, mDragPointF.y, mDragRadius, mDragPaint);
//画一个固定的圆 根据拖拽距离改固定圆的半径
canvas.drawCircle(mFixationPointF.x, mFixationPointF.y, mFixationRadius, mFixationPaint);
Path bezierPath = getBezierPath();
if(bezierPath != null){
canvas.drawPath(bezierPath,mFixationPaint);
}
if(this.mDragBitmap != null){
canvas.drawBitmap(mDragBitmap,mDragPointF.x - mDragBitmap.getWidth()/2,mDragPointF.y-mDragBitmap.getHeight()/2,null);
}
}
5.绘制贝塞尔曲线的path
/**
* 获取贝塞尔曲线的 path
* @return
*/
private Path getBezierPath(){
double distance = calculateDistance();
//比例 这个数可以自己随便定义一个数 比如 14 主要是看效果是否符合自己的效果 测试就知道了
int bili = mDragRadius;
mFixationRadius = (int) (mFixationMaxRadius - distance / bili);
if (mFixationRadius < mFixationMinRadius) {
return null;
}
Path bezierPath = new Path();
float dy = mDragPointF.y - mFixationPointF.y;
float dx = mDragPointF.x - mFixationPointF.x;
float tanA = dy / dx;
//求角A 反tanA
double arcTanA = Math.atan(tanA);
//p0
float p0x = (float) (mFixationPointF.x + mFixationRadius * Math.sin(arcTanA));
float p0y = (float)(mFixationPointF.y - mFixationRadius * Math.cos(arcTanA));
//p1
float p1x = (float)(mDragPointF.x + mDragRadius * Math.sin(arcTanA));
float p1y = (float)(mDragPointF.y - mDragRadius * Math.cos(arcTanA));
//p2
float p2x = (float)(mDragPointF.x - mDragRadius * Math.sin(arcTanA));
float p2y = (float)(mDragPointF.y + mDragRadius * Math.cos(arcTanA));
//p3
float p3x = (float) (mFixationPointF.x - mFixationRadius * Math.sin(arcTanA));
float p3y = (float)(mFixationPointF.y + mFixationRadius * Math.cos(arcTanA));
//拼装 贝塞尔曲线
bezierPath.moveTo(p0x,p0y);
//获取控制点座标 定在 两点的中心点
PointF controllerPointF = getControllerPointF();
//画第一条
bezierPath.quadTo(controllerPointF.x,controllerPointF.y,p1x,p1y);
//画第二条
bezierPath.lineTo(p2x,p2y);
bezierPath.quadTo(controllerPointF.x,controllerPointF.y,p3x,p3y);
bezierPath.close();
return bezierPath;
}
6.拖拽view的回弹动画
/**
* 处理手指松开
*/
public void handleActionUp() {
//回弹
if(mFixationRadius > mFixationMinRadius){
ValueAnimator animator = ObjectAnimator.ofFloat(1);
animator.setDuration(350);
final PointF start = new PointF(mDragPointF.x,mDragPointF.y);
final PointF end = new PointF(mFixationPointF.x,mFixationPointF.y);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float animatedValue = (float) animation.getAnimatedValue();
PointF pointByPercent = getPointByPercent(start, end, animatedValue);
updatePoint(pointByPercent.x,pointByPercent.y);
}
});
//差值器 回到原来的位置都向前甩 然后回到原来位置
animator.setInterpolator(new OvershootInterpolator(3f));
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
if(mDragViewCallBackListener!=null){
mDragViewCallBackListener.restore();
}
}
});
animator.start();
}else {
//爆炸
if(mDragViewCallBackListener!=null){
mDragViewCallBackListener.dismiss();
}
}
}
根据三角函数的算法,已知两个点的座标根据移动百分比计算第三个点的座标
/**
* 根据百分比计算点的座标
* @param start
* @param end
* @param percent
* @return
*/
private PointF getPointByPercent(PointF start,PointF end,float percent){
return new PointF(evaluateValue(start.x,end.x,percent),evaluateValue(start.y,end.y,percent));
}
private float evaluateValue(Number start,Number end,float fraction){
return start.floatValue() + (end.floatValue() - start.floatValue()) * fraction;
}
这个可以作为一个工具栏单独拿出来坐记录。
难点也就这么些。有问题随时提问
网友评论