公司需要这个效果,看了很多博客,根据自己项目的需要写出来的一个完整的过程.
拖拽控件代码
根据手势拖动的位置利用贝塞尔曲线算法画出控件
package cn.stike.bubble.stickbubbledemo.view;
import android.content.Context;
import android.graphics.PixelFormat;
import android.graphics.PointF;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.WindowManager;
public class StickBubble extends LLBBubble {
private LRBubble mInnerStickBall;
// 手抬起时的回调
private OnDragUpListener mOnDragUpListener;
private WindowManager mWindowManager;
private float getCurrentX;
private float getCurrentY;
public float getGetCurrentX() {
return getCurrentX;
}
public void setGetCurrentX(float getCurrentX) {
this.getCurrentX = getCurrentX;
}
public float getGetCurrentY() {
return getCurrentY;
}
public void setGetCurrentY(float getCurrentY) {
this.getCurrentY = getCurrentY;
}
public StickBubble(Context context) {
this(context, null);
}
public StickBubble(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public StickBubble(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
mLTPoint.set(getPaddingLeft() + mContentHeight / 2, getPaddingTop());
mRBPoint.set(mLTPoint.x + mContentWidth - mContentHeight, mLTPoint.y + mContentHeight);
mBaseLinePoint.set(getPaddingLeft() + (mContentWidth - mBounds.width()) / 2, getPaddingTop() + (mContentHeight + mBounds.height()) / 2);
widthMeasureSpec = MeasureSpec.makeMeasureSpec(mContentWidth + getPaddingLeft() + getPaddingRight(), MeasureSpec.getMode(widthMeasureSpec));
heightMeasureSpec = MeasureSpec.makeMeasureSpec(mContentHeight + getPaddingTop() + getPaddingBottom(), MeasureSpec.getMode(heightMeasureSpec));
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if (mHasDown) {
return true;
}
mHasDown = true;
setVisibility(INVISIBLE);
showDragView();
return true;
case MotionEvent.ACTION_MOVE:
mInnerStickBall.performTouchEvent(event);
return true;
case MotionEvent.ACTION_UP:
/**
*记录bubble气泡爆炸应出现的坐标值
*/
setGetCurrentX(event.getRawX());
setGetCurrentY(event.getRawY());
mInnerStickBall.performTouchEvent(event);
return true;
}
return super.onTouchEvent(event);
}
int[] outSize;
private void showDragView() {
outSize = new int[2];
getLocationOnScreen(outSize);
mInnerStickBall = new LRBubble(getContext(),
new PointF(mLTPoint.x + outSize[0], mLTPoint.y + outSize[1]),
new PointF(mRBPoint.x + outSize[0], mRBPoint.y + outSize[1]),
mMaxDistance, getText(), mTextColor, mBallColor, getPaint());
mInnerStickBall.setOnDragUpListener(new OnDragUpListener() {
@Override
public void onDragUp(boolean overstep) {
if (mWindowManager != null) {
mWindowManager.removeView(mInnerStickBall);
}
if (!overstep) {
setVisibility(VISIBLE);
}
if (mOnDragUpListener != null) {
mOnDragUpListener.onDragUp(overstep);
}
mHasDown = false;
}
});
if (mWindowManager == null) {
return;
}
WindowManager.LayoutParams params = new WindowManager.LayoutParams();
params.format = PixelFormat.TRANSLUCENT;
params.type |= WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
mWindowManager.addView(mInnerStickBall, params);
}
/**
* 设置判定超出范围的最大距离
*
* @param maxDistance
*/
public void setMaxDistance(double maxDistance) {
mMaxDistance = maxDistance;
}
public void setOnDragUpListener(OnDragUpListener onDragUpListener) {
mOnDragUpListener = onDragUpListener;
}
/**
* 手指抬起时的回调
*/
public interface OnDragUpListener {
/**
* @param overstep true表示超过最大范围,粘性球消失,false表示未超过范围,粘性球未消失
*/
void onDragUp(boolean overstep);
}
}
Activity代码
使用帧动画将气泡爆炸的效果展现出来,帧动画是用xml实现的,很简单,这里就不贴代码了
package cn.stike.bubble.stickbubbledemo;
import android.content.Context;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.graphics.drawable.AnimationDrawable;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.ImageView;
import cn.stike.bubble.stickbubbledemo.view.BubbleLayout;
import cn.stike.bubble.stickbubbledemo.view.StickBall;
public class MainActivity extends TabActivity {
private TabHost tabHost;
int CurrentPage;
int setlanguage;
TabHost.TabSpec spec;
private StickBall mybragballview;
private WindowManager mWm;
private WindowManager.LayoutParams mParams;
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mWm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
mParams = new WindowManager.LayoutParams();
mParams.format = PixelFormat.TRANSLUCENT;//使窗口支持透明度
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
mParams.flags = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
}
mybragballview = (StickBall) findViewById(R.id.mybragballview);
mybragballview.setOnDragUpListener(new StickBall.OnDragUpListener() {
@Override
public void onDragUp(boolean overstep) {
if (overstep) {//气泡消失 在此气泡爆炸的动画开始出现
showDisapearBubble();
}
}
});
}
public void showDisapearBubble() {
if (mWm != null && mybragballview.getParent() != null) {
//播放气泡爆炸动画
ImageView imageView = new ImageView(MainActivity.this);
imageView.setImageResource(R.drawable.anim_bubble_pop);
AnimationDrawable mAnimDrawable = (AnimationDrawable) imageView
.getDrawable();
final BubbleLayout bubbleLayout = new BubbleLayout(MainActivity.this);
//获取bubble气泡爆炸出现的坐标值 显示
int x = (int) mybragballview.getGetCurrentX();
int y = (int) mybragballview.getGetCurrentY();
bubbleLayout.setCenter(x, y);
bubbleLayout.addView(imageView, new FrameLayout.LayoutParams(
android.widget.FrameLayout.LayoutParams.WRAP_CONTENT,
android.widget.FrameLayout.LayoutParams.WRAP_CONTENT));
mWm.addView(bubbleLayout, mParams);
mAnimDrawable.start();
// 播放结束后,删除该bubbleLayout
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
mWm.removeView(bubbleLayout);
}
}, 501);
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
//更新界面把所有消息变成已读
}
}, 510);
}
}
}
bubble爆炸布局
package cn.stike.bubble.stickbubbledemo.view;
import android.content.Context;
import android.view.View;
import android.widget.FrameLayout;
/**
* Created by Administrator on 2018/9/19.
* 播放爆炸动画的layout
*/
public class BallLayout extends FrameLayout {
Context context;
public BallLayout(Context context) {
super(context);
this.context = context;
}
private int mCenterX, mCenterY;
public void setCenter(int x, int y) {
mCenterX = x;
mCenterY = y;
requestLayout();
}
@Override
protected void onLayout(boolean changed, int left, int top, int right,
int bottom) {
View child = getChildAt(0);
// 设置View到指定位置
if (child != null && child.getVisibility() != GONE) {
final int width = child.getMeasuredWidth();
final int height = child.getMeasuredHeight();
child.layout((int) (mCenterX - width / 2.0f), (int) (mCenterY - height / 2.0f)
, (int) (mCenterX + width / 2.0f), (int) (mCenterY + height / 2.0f));
}
}
}
demo下载网址:https://download.csdn.net/download/congcongguniang/10676281