import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.content.Context; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PointF; import android.graphics.Rect; import android.support.annotation.Nullable; import android.support.v7.widget.AppCompatTextView; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.animation.LinearInterpolator;
import com.example.administrator.myqq.R;
public class DragMsgView extends AppCompatTextView {
private DragDotView mDragDotView; private float mWidth, mHeight; private OnDragListener mDragListener;
public DragMsgView(Context context) { this(context, null); }
public DragMsgView(Context context, AttributeSet attrs) { super(context, attrs); }
@Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { mWidth = w; mHeight = h; super.onSizeChanged(w, h, oldw, oldh); }
@Override public boolean onTouchEvent(MotionEvent event) { View rootView = getRootView(); float mRawX = event.getRawX(); float mRawY = event.getRawY(); switch (event.getAction()){ case MotionEvent.ACTION_DOWN: getParent().requestDisallowInterceptTouchEvent(true); 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); } } break; case MotionEvent.ACTION_MOVE: getParent().requestDisallowInterceptTouchEvent(true); if(mDragDotView != null){ mDragDotView.move(mRawX, mRawY); } break; case MotionEvent.ACTION_UP: getParent().requestDisallowInterceptTouchEvent(false); if(mDragDotView != null){ mDragDotView.up(); } break; } return true; }
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; }
public class DragDotView extends View {
private final int BUBBLE_STATE_DEFAULT = 0; private final int BUBBLE_STATE_CONNECT = 1; private final int BUBBLE_STATE_APART = 2; private final int BUBBLE_STATE_DISMISS = 3;
private float mBubbleRadius = dpToPx(10); private int mBubbleColor;
private float mBubbleStillRadius; private float mBubbleMoveRadius; private PointF mBubStillCenter; private PointF mBubMoveCenter;
private Paint mBubblePaint; private Path mBezierPath;
private Paint mBurstPaint; private Rect mBurstRect;
private int mBubbleState = BUBBLE_STATE_DEFAULT; private float mDist; private float mMaxDist; private float MOVE_OFFSET;
private Bitmap mCacheBitmap; private float mWidth, mHeight;
private Bitmap[] mBurstBitmapArray; private boolean mIsBurstAnimStart = false; private int mCurDrawableIndex; private final int[] mBurstDrawablesArray = {R.drawable.explosion_one, R.drawable.explosion_two , R.drawable.explosion_three, R.drawable.explosion_four, R.drawable.explosion_five};
public DragDotView(Context context) { this(context, null); }
public DragDotView(Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); }
public DragDotView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { this(context, attrs, defStyleAttr, 0); }
public DragDotView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); init(context, attrs, defStyleAttr); }
private void init(Context context, AttributeSet attrs, int defStyleAttr){ TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.DragBubbleView, defStyleAttr, 0); mBubbleColor = array.getColor(R.styleable.DragBubbleView_bubbleColor, Color.RED); array.recycle();
mBubblePaint = new Paint(Paint.ANTI_ALIAS_FLAG); mBubblePaint.setColor(mBubbleColor); mBubblePaint.setStyle(Paint.Style.FILL);
mBezierPath = new Path();
mBurstPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mBurstPaint.setFilterBitmap(true); mBurstRect = new Rect(); mBurstBitmapArray = new Bitmap[mBurstDrawablesArray.length]; for (int i = 0; i < mBurstDrawablesArray.length; i++) { Bitmap bitmap = BitmapFactory.decodeResource(getResources(), mBurstDrawablesArray[i]); mBurstBitmapArray[i] = bitmap; } }
@Override protected void onDraw(Canvas canvas) { if(mDist < mMaxDist && mBubbleState == BUBBLE_STATE_CONNECT){ canvas.drawCircle(mBubStillCenter.x, mBubStillCenter.y, mBubbleStillRadius, mBubblePaint);
int controlX = (int) ((mBubStillCenter.x + mBubMoveCenter.x) / 2); int controlY = (int) ((mBubStillCenter.y + mBubMoveCenter.y) / 2);
float sin = (mBubMoveCenter.y - mBubStillCenter.y) / mDist; float cos = (mBubMoveCenter.x - mBubStillCenter.x) / mDist;
float bubbleStillStartX = mBubStillCenter.x + mBubbleStillRadius * sin; float bubbleStillStartY = mBubStillCenter.y - mBubbleStillRadius * cos; float bubbleMoveStartX = mBubMoveCenter.x + mBubbleMoveRadius * sin; float bubbleMoveStartY = mBubMoveCenter.y - mBubbleMoveRadius * cos; float bubbleMoveEndX = mBubMoveCenter.x - mBubbleMoveRadius * sin; float bubbleMoveEndY = mBubMoveCenter.y + mBubbleMoveRadius * cos; float bubbleStillEndX = mBubStillCenter.x - mBubbleStillRadius * sin; float bubbleStillEndY = mBubStillCenter.y + mBubbleStillRadius * cos;
mBezierPath.reset(); mBezierPath.moveTo(bubbleStillStartX, bubbleStillStartY); mBezierPath.quadTo(controlX, controlY, bubbleMoveStartX, bubbleMoveStartY); mBezierPath.lineTo(bubbleMoveEndX, bubbleMoveEndY); mBezierPath.quadTo(controlX, controlY, bubbleStillEndX, bubbleStillEndY); mBezierPath.close(); canvas.drawPath(mBezierPath, mBubblePaint); }
if (mCacheBitmap != null && mBubbleState != BUBBLE_STATE_DISMISS) { canvas.drawBitmap(mCacheBitmap, mBubMoveCenter.x - mWidth / 2, mBubMoveCenter.y - mHeight / 2, mBubblePaint); }
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); } } }
private void startBubbleBurstAnim() { ValueAnimator animator = ValueAnimator.ofInt(0, mBurstDrawablesArray.length); animator.setInterpolator(new LinearInterpolator()); animator.setDuration(500); 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(); }
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(300); animator.setInterpolator(input -> {
float f = 0.571429f; return (float) (Math.pow(2, -4 * input) * Math.sin((input - f / 4) * (2 * Math.PI) / f) + 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(); }
public void setCacheBitmap(Bitmap bitmap){ this.mCacheBitmap = bitmap; mWidth = mCacheBitmap.getWidth(); mHeight = mCacheBitmap.getHeight(); mBubbleRadius = Math.min(mWidth, mHeight) / 2; }
public void setDragPoint(float stillX, float stillY, float moveX, float moveY) { mBubbleStillRadius = mBubbleRadius; mBubbleMoveRadius = mBubbleStillRadius; mMaxDist = mBubbleRadius * 8; MOVE_OFFSET = mMaxDist / 4; if(mBubStillCenter == null){ mBubStillCenter = new PointF(stillX, stillY); }else { mBubStillCenter.set(stillX, stillY); } if(mBubMoveCenter == null){ mBubMoveCenter = new PointF(moveX, moveY); }else { mBubMoveCenter.set(moveX, moveY); } mBubbleState = BUBBLE_STATE_CONNECT; invalidate(); }
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(); }
public void up() { if(mBubbleState == BUBBLE_STATE_CONNECT){ startBubbleRestAnim(); }else if(mBubbleState == BUBBLE_STATE_APART){ if(mDist < 3 * mBubbleRadius){ startBubbleRestAnim(); }else { mBubbleState = BUBBLE_STATE_DISMISS; mIsBurstAnimStart = true; startBubbleBurstAnim(); } } invalidate(); }
private void removeDragView() { ViewGroup viewGroup = (ViewGroup) getParent(); viewGroup.removeView(DragDotView.this); DragMsgView.this.setVisibility(VISIBLE); }
protected int dpToPx(float dp) { DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics(); return (int) (dp * metrics.density + 0.5f); } }
public interface OnDragListener{ void onRestore(); void onDismiss(); }
public void setOnDragListener(OnDragListener listener){ this.mDragListener = listener; } }
|