package com.dk.view.drop;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff.Mode;
import android.os.Build.VERSION;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
public class DropCover extends SurfaceView implements SurfaceHolder.Callback {
private static final int EXPLOSION_SIZE = 200;
private int mMaxDistance = 100;
private ExplosionUpdateThread mThread;
private Explosion mExplosion;
private float mBaseX;
private float mBaseY;
private float mTargetX;
private float mTargetY;
private Bitmap mDest;
private Paint mPaint = new Paint();
private float targetWidth;
private float targetHeight;
private float mRadius = 0;
private float mStrokeWidth = 20;
private boolean isDraw = true;
private float mStatusBarHeight = 0;
private OnDragCompeteListener mOnDragCompeteListener;
public interface OnDragCompeteListener {
void onDrag();
}
@SuppressLint("NewApi")
public DropCover(Context context) {
super(context);
this.setBackgroundColor(Color.TRANSPARENT);
this.setZOrderOnTop(true);
getHolder().setFormat(PixelFormat.TRANSPARENT);
getHolder().addCallback(this);
setFocusable(false);
setClickable(false);
mPaint.setAntiAlias(true);
if (VERSION.SDK_INT > 11) {
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return false;
}
/**
* draw drop and line
*/
private void drawDrop() {
Canvas canvas = getHolder().lockCanvas();
if (canvas != null) {
canvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);
if (isDraw) {
double distance = Math.sqrt(Math.pow(mBaseX - mTargetX, 2) + Math.pow(mBaseY - mTargetY, 2));
mPaint.setColor(0xffff0000);
if (distance < mMaxDistance) {
mStrokeWidth = (float) ((1f - distance / mMaxDistance) * mRadius);
mPaint.setStrokeWidth(mStrokeWidth);
canvas.drawCircle(mBaseX, mBaseY, mStrokeWidth / 2, mPaint);
// canvas.drawLine(mBaseX, mBaseY, mTargetX + targetWidth /
// 2, mTargetY + targetHeight / 2, mPaint);
drawBezier(canvas);
}
canvas.drawBitmap(mDest, mTargetX, mTargetY, mPaint);
}
getHolder().unlockCanvasAndPost(canvas);
}
}
private void drawBezier(Canvas canvas) {
mPaint.setStyle(Paint.Style.STROKE);
Point[] points = calculate(new Point(mBaseX, mBaseY), new Point(mTargetX + mDest.getWidth() / 2f, mTargetY + mDest.getHeight() / 2f));
float centerX = (points[0].x + points[1].x + points[2].x + points[3].x) / 4f;
float centerY = (points[0].y + points[1].y + points[2].y + points[3].y) / 4f;
Path path1 = new Path();
path1.moveTo(points[0].x, points[0].y);
path1.quadTo((points[2].x + points[3].x) / 2, (points[2].y + points[3].y) / 2, points[1].x, points[1].y);
canvas.drawPath(path1, mPaint);
Path path2 = new Path();
path2.moveTo(points[2].x, points[2].y);
path2.quadTo((points[0].x + points[1].x) / 2, (points[0].y + points[1].y) / 2, points[3].x, points[3].y);
canvas.drawPath(path2, mPaint);
}
/**
* ax=by=0 x^2+y^2=s/2
*
* ==>
*
* x=a^2/(a^2+b^2)*s/2
*
* @param start
* @param end
* @return
*/
private Point[] calculate(Point start, Point end) {
float a = end.x - start.x;
float b = end.y - start.y;
float x = (float) Math.sqrt(a * a / (a * a + b * b) * (mStrokeWidth / 2f) * (mStrokeWidth / 2f));
float y = -b / a * x;
System.out.println("x:" + x + " y:" + y);
Point[] result = new Point[4];
result[0] = new Point(start.x + x, start.y + y);
result[1] = new Point(end.x + x, end.y + y);
result[2] = new Point(start.x - x, start.y - y);
result[3] = new Point(end.x - x, end.y - y);
return result;
}
public void setTarget(Bitmap dest) {
mDest = dest;
targetWidth = dest.getWidth();
targetHeight = dest.getHeight();
mRadius = dest.getWidth() / 2;
mStrokeWidth = mRadius;
}
public void init(float x, float y) {
mBaseX = x + mDest.getWidth() / 2f;
mBaseY = y - mDest.getWidth() / 2f;
mTargetX = x;
mTargetY = y - mStatusBarHeight;
isDraw = true;
drawDrop();
}
/**
* move the drop
*
* @param x
* @param y
*/
public void update(float x, float y) {
mTargetX = x;
mTargetY = y - mStatusBarHeight;
drawDrop();
}
/**
* reset datas
*/
public void clearDatas() {
mBaseX = -1;
mBaseY = -1;
mTargetX = -1;
mTargetY = -1;
mDest = null;
}
/**
* remove DropCover
*/
public void clearViews() {
if (getParent() != null) {
CoverManager.getInstance().getWindowManager().removeView(this);
}
}
/**
* finish drag event and start explosion
*
* @param target
* @param x
* @param y
*/
public void finish(View target, float x, float y) {
double distance = Math.sqrt(Math.pow(mBaseX - mTargetX, 2) + Math.pow(mBaseY - mTargetY, 2));
clearDatas();
Canvas canvas = getHolder().lockCanvas();
if (canvas != null) {
canvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);
getHolder().unlockCanvasAndPost(canvas);
}
if (distance > mMaxDistance) {
if (mOnDragCompeteListener != null)
mOnDragCompeteListener.onDrag();
initExplosion(x, y);
clearViews();
} else {
clearViews();
target.setVisibility(View.VISIBLE);
}
isDraw = false;
}
public void setStatusBarHeight(int statusBarHeight) {
mStatusBarHeight = statusBarHeight;
}
public void setOnDragCompeteListener(OnDragCompeteListener onDragCompeteListener) {
mOnDragCompeteListener = onDragCompeteListener;
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
drawDrop();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
if (mThread != null) {
mThread.setRunning(false);
mThread = null;
}
}
/**
* init the explosion whit start position
*
* @param x
* @param y
*/
public void initExplosion(float x, float y) {
if (mExplosion == null || mExplosion.getState() == Explosion.STATE_DEAD) {
mExplosion = new Explosion(EXPLOSION_SIZE, (int) x, (int) y);
}
}
/**
* call it to draw explosion
*
* @param canvas
* @return isAlive
*/
public boolean render(Canvas canvas) {
boolean isAlive = false;
canvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);
canvas.drawColor(Color.argb(0, 0, 0, 0)); // To make canvas transparent
// render explosions
if (mExplosion != null) {
isAlive = mExplosion.draw(canvas);
}
return isAlive;
}
/**
* update explosion
*/
public void update() {
// update explosions
if (mExplosion != null && mExplosion.isAlive()) {
mExplosion.update(getHolder().getSurfaceFrame());
}
}
// private void displayFps(Canvas canvas, String fps) {
// if (canvas != null && fps != null) {
// Paint paint = new Paint();
// paint.setARGB(255, 255, 255, 255);
// canvas.drawText(fps, this.getWidth() - 50, 20, paint);
// }
// }
/**
* please call it before animation start
*
* @param maxDistance
*/
public void setMaxDragDistance(int maxDistance) {
mMaxDistance = maxDistance;
}
class Point {
float x, y;
public Point(float x, float y) {
this.x = x;
this.y = y;
}
}
}