这篇文章主要介绍了Android 实现仿QQ拖拽气泡效果的示例,帮助大家更好的理解和学习使用Android,感兴趣的朋友可以了解下
根据图中所标注的信息得知,∠a=∠d,∠b=∠c,∠a=∠θ,由此可知,我们求出∠θ所在的直角三角形的sin和cos值,就可以计算出A点、B点、C点、D点的坐标。
sin值可以通过移动圆的y坐标减去固定圆的y坐标,再除以两圆心的距离,也就是O1到O2的距离。
cos值可以通过移动圆的x坐标减去固定圆的x坐标,再除以两圆心的距离。
float sin = (mBubMoveCenter.y - mBubStillCenter.y) / mDist;
float cos = (mBubMoveCenter.x - mBubStillCenter.x) / mDist;
有了sin和cos值,对应的A点、B点、C点、D点的坐标就好计算了
// A点
float bubbleStillStartX = mBubStillCenter.x + mBubbleStillRadius * sin;
float bubbleStillStartY = mBubStillCenter.y - mBubbleStillRadius * cos;
// B点
float bubbleMoveStartX = mBubMoveCenter.x + mBubbleMoveRadius * sin;
float bubbleMoveStartY = mBubMoveCenter.y - mBubbleMoveRadius * cos;
// C点
float bubbleMoveEndX = mBubMoveCenter.x - mBubbleMoveRadius * sin;
float bubbleMoveEndY = mBubMoveCenter.y + mBubbleMoveRadius * cos;
// D点
float bubbleStillEndX = mBubStillCenter.x - mBubbleStillRadius * sin;
float bubbleStillEndY = mBubStillCenter.y + mBubbleStillRadius * cos;
接下来就是把这些贝塞尔曲线和直线连起来,就实现了两气泡相连的效果。
两气泡分离状态:当拖拽的移动圆超出固定圆一定范围时,就进入了两气泡分离状态,此时我们只需要绘制移动圆即可。当拖拽的移动圆回到固定圆一定范围时,此时会进入两气泡相连状态,并且需要实现一个气泡还原的效果。(这里会有个难点,就是移动圆我们可以在屏幕上任意拖动而不被遮挡,这里放到后面来实现。)
public void move(float curX, float curY) {
mBubMoveCenter.x = curX;
mBubMoveCenter.y = curY;
mDist = (float) Math.hypot(curX - mBubStillCenter.x, curY - mBubStillCenter.y);
if(mBubbleState == BUBBLE_STATE_CONNECT){
if(mDist < mMaxDist - MOVE_OFFSET){
mBubbleStillRadius = mBubbleRadius - mDist / 10;
}else {
mBubbleState = BUBBLE_STATE_APART;
}
}
invalidate();
}
mDist就是两圆心的距离。
/**
* 气泡还原动画
*/
private void startBubbleRestAnim() {
mBubbleStillRadius = mBubbleRadius;
ValueAnimator animator = ValueAnimator.ofObject(new PointEvaluator(), new PointF(mBubMoveCenter.x, mBubMoveCenter.y), new PointF(mBubStillCenter.x, mBubStillCenter.y));
animator.setDuration(200);
animator.setInterpolator(input -> {
float factor = 0.4f;
return (float) (Math.pow(2, -10 * factor) * Math.sin((input - factor / 4) * (2 * Math.PI) / factor) + 1);
});
animator.addUpdateListener(animation -> {
mBubMoveCenter = (PointF) animation.getAnimatedValue();
invalidate();
});
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mBubbleState = BUBBLE_STATE_DEFAULT;
removeDragView();
if(mDragListener != null){
mDragListener.onRestore();
}
}
});
animator.start();
}
分享一个可视化插值器的网站,其中内置了一些插值器公式,还可以查看动画演示效果。http://inloop.github.io/interpolator/
气泡消失状态:当拖拽的移动圆超出一定范围时,并且松开了手指后,此时进入气泡消失状态,此时我们需要实现一个爆炸的动画。
爆炸的动画通过绘制一组图片来实现
if(mBubbleState == BUBBLE_STATE_DISMISS){
if(mIsBurstAnimStart){
mBurstRect.set((int)(mBubMoveCenter.x - mBubbleMoveRadius), (int)(mBubMoveCenter.y - mBubbleMoveRadius),
(int)(mBubMoveCenter.x + mBubbleMoveRadius), (int)(mBubMoveCenter.y + mBubbleMoveRadius));
canvas.drawBitmap(mBurstBitmapArray[mCurDrawableIndex], null, mBurstRect, mBurstPaint);
}
}
mCurDrawableIndex是图片的索引,是通过属性动画来改变
/**
* 气泡爆炸动画
*/
private void startBubbleBurstAnim() {
ValueAnimator animator = ValueAnimator.ofInt(0, mBurstDrawablesArray.length);
animator.setInterpolator(new LinearInterpolator());
animator.setDuration(1000);
animator.addUpdateListener(animation -> {
mCurDrawableIndex = (int) animator.getAnimatedValue();
invalidate();
});
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mIsBurstAnimStart = false;
if(mDragListener != null){
mDragListener.onDismiss();
}
}
});
animator.start();
}
三、全屏拖拽效果实现
首先在DOWN事件中获取当前触摸位置在全屏所在位置,然后将当前view缓存为bitmap,并把此bitmap添加到rootview中,拖动的时候直接绘制此bitmap。
//获得当前View在屏幕上的位置
int[] cLocation = new int[2];
getLocationOnScreen(cLocation);
if(rootView instanceof ViewGroup){
mDragDotView = new DragDotView(getContext());
//设置固定圆和移动圆的圆心坐标
mDragDotView.setDragPoint(cLocation[0] + mWidth / 2, cLocation[1] + mHeight / 2, mRawX, mRawY);
Bitmap bitmap = getBitmapFromView(this);
if(bitmap != null){
mDragDotView.setCacheBitmap(bitmap);
((ViewGroup) rootView).addView(mDragDotView);
setVisibility(INVISIBLE);
}
}
/**
* 将当前view缓存为bitmap,拖动的时候直接绘制此bitmap
* @param view
* @return
*/
public Bitmap getBitmapFromView(View view)
{
Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
view.draw(canvas);
return bitmap;
}
至此,整个消息气泡拖拽效果的核心部分就实现了
源码地址:
https://github.com/loren325/CustomerView
以上就是Android 实现仿QQ拖拽气泡效果的示例的详细内容,更多关于Android 实现仿QQ拖拽气泡效果的资料请关注编程学习网其它相关文章!
本文标题为:Android 实现仿QQ拖拽气泡效果的示例
- SurfaceView播放视频发送弹幕并实现滚动歌词 2023-01-02
- Flutter实现底部和顶部导航栏 2022-08-31
- Android MaterialButton使用实例详解(告别shape、selector) 2023-06-16
- 作为iOS开发,这道面试题你能答出来,说明你基础很OK! 2023-09-14
- Android实现轮询的三种方式 2023-02-17
- Android studio实现动态背景页面 2023-05-23
- iOS 对当前webView进行截屏的方法 2023-03-01
- Android实现监听音量的变化 2023-03-30
- 详解flutter engine 那些没被释放的东西 2022-12-04
- 最好用的ios数据恢复软件:PhoneRescue for Mac 2023-09-14
