package com.example.gsyvideoplayer.utils.floatUtil; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.animation.PropertyValuesHolder; import android.animation.TimeInterpolator; import android.animation.ValueAnimator; import android.os.Build; import android.view.MotionEvent; import android.view.View; import android.view.animation.DecelerateInterpolator; /** * Created by yhao on 2017/12/22. * https://github.com/yhaolpz */ public class IFloatWindowImpl extends IFloatWindow { private FloatWindow.B mB; private FloatView mFloatView; private FloatLifecycle mFloatLifecycle; private boolean isShow; private boolean once = true; private ValueAnimator mAnimator; private TimeInterpolator mDecelerateInterpolator; private IFloatWindowImpl() { } IFloatWindowImpl(FloatWindow.B b) { mB = b; if (mB.mMoveType == MoveType.fixed) { if (Build.VERSION.SDK_INT >=25) { mFloatView = new FloatPhone(b.mApplicationContext); } else { mFloatView = new FloatToast(b.mApplicationContext); } } else { mFloatView = new FloatPhone(b.mApplicationContext); initTouchEvent(); } mFloatView.setSize(mB.mWidth, mB.mHeight); mFloatView.setGravity(mB.gravity, mB.xOffset, mB.yOffset); mFloatView.setView(mB.mView); mFloatLifecycle = new FloatLifecycle(mB.mApplicationContext, mB.mShow, mB.mActivities, new LifecycleListener() { @Override public void onShow() { show(); } @Override public void onHide() { hide(); } @Override public void onPostHide() { postHide(); } }); } @Override public void show() { if (once) { mFloatView.init(); once = false; isShow = true; } else { if (isShow) return; getView().setVisibility(View.VISIBLE); isShow = true; } } @Override public void hide() { if (once || !isShow) return; getView().setVisibility(View.INVISIBLE); isShow = false; } @Override void dismiss() { mFloatView.dismiss(); isShow = false; } @Override public void updateX(int x) { checkMoveType(); mB.xOffset = x; mFloatView.updateX(x); } @Override public void updateY(int y) { checkMoveType(); mB.yOffset = y; mFloatView.updateY(y); } @Override public void updateX(int screenType, float ratio) { checkMoveType(); mB.xOffset = (int) ((screenType == Screen.width ? Util.getScreenWidth(mB.mApplicationContext) : Util.getScreenHeight(mB.mApplicationContext)) * ratio); mFloatView.updateX(mB.xOffset); } @Override public void updateY(int screenType, float ratio) { checkMoveType(); mB.yOffset = (int) ((screenType == Screen.width ? Util.getScreenWidth(mB.mApplicationContext) : Util.getScreenHeight(mB.mApplicationContext)) * ratio); mFloatView.updateY(mB.yOffset); } @Override public int getX() { return mFloatView.getX(); } @Override public int getY() { return mFloatView.getY(); } @Override public View getView() { return mB.mView; } void postHide() { if (once || !isShow) return; getView().post(new Runnable() { @Override public void run() { getView().setVisibility(View.INVISIBLE); } }); isShow = false; } private void checkMoveType() { if (mB.mMoveType == MoveType.fixed) { throw new IllegalArgumentException("FloatWindow of this tag is not allowed to move!"); } } private void initTouchEvent() { switch (mB.mMoveType) { case MoveType.free: break; default: getView().setOnTouchListener(new View.OnTouchListener() { float lastX, lastY, changeX, changeY; int newX, newY; @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: lastX = event.getRawX(); lastY = event.getRawY(); cancelAnimator(); break; case MotionEvent.ACTION_MOVE: changeX = event.getRawX() - lastX; changeY = event.getRawY() - lastY; newX = (int) (mFloatView.getX() + changeX); newY = (int) (mFloatView.getY() + changeY); mFloatView.updateXY(newX, newY); lastX = event.getRawX(); lastY = event.getRawY(); break; case MotionEvent.ACTION_UP: switch (mB.mMoveType) { case MoveType.slide: int startX = mFloatView.getX(); int endX = (startX * 2 + v.getWidth() > Util.getScreenWidth(mB.mApplicationContext)) ? Util.getScreenWidth(mB.mApplicationContext) - v.getWidth() : 0; mAnimator = ObjectAnimator.ofInt(startX, endX); mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { int x = (int) animation.getAnimatedValue(); mFloatView.updateX(x); } }); startAnimator(); break; case MoveType.back: PropertyValuesHolder pvhX = PropertyValuesHolder.ofInt("x", mFloatView.getX(), mB.xOffset); PropertyValuesHolder pvhY = PropertyValuesHolder.ofInt("y", mFloatView.getY(), mB.yOffset); mAnimator = ObjectAnimator.ofPropertyValuesHolder(pvhX, pvhY); mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { int x = (int) animation.getAnimatedValue("x"); int y = (int) animation.getAnimatedValue("y"); mFloatView.updateXY(x, y); } }); startAnimator(); break; } break; } return false; } }); } } private void startAnimator() { if (mB.mInterpolator == null) { if (mDecelerateInterpolator == null) { mDecelerateInterpolator = new DecelerateInterpolator(); } mB.mInterpolator = mDecelerateInterpolator; } mAnimator.setInterpolator(mB.mInterpolator); mAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { mAnimator.removeAllUpdateListeners(); mAnimator.removeAllListeners(); mAnimator = null; } }); mAnimator.setDuration(mB.mDuration).start(); } private void cancelAnimator() { if (mAnimator != null && mAnimator.isRunning()) { mAnimator.cancel(); } } }