package com.zzm.ndkandmaterialdesigndemo; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.os.CountDownTimer; import android.util.Log; import android.view.View; import android.view.animation.LinearInterpolator; public class MessageRemindUtil { public static float moveToPosition = -200f; public static int moveDownDuration = 200; public static int moveUpDuration = 200; public static int disappearTime = 4000; public static ObjectAnimator animator; public static CountDownTimer countDownTimer; private static View target; private static MoveUpEndListener moveUpEndListener; private static void moveUp(int moveUpDuration, AnimatorListenerAdapter animatorListenerAdapter) { float start = target.getY(); animator = ObjectAnimator.ofFloat(target, "TranslationY", start, moveToPosition); animator.setDuration(moveUpDuration); animator.setInterpolator(new LinearInterpolator()); if (animatorListenerAdapter != null) { animator.addListener(animatorListenerAdapter); } else { animator.addListener(new NormalMoveUpListener()); } animator.start(); } private static void moveDown(int moveDownDuration) { float start = target.getY(); target.setVisibility(View.VISIBLE); animator = ObjectAnimator.ofFloat(target, "TranslationY", start, 0f); animator.setDuration(moveDownDuration); animator.setInterpolator(new LinearInterpolator()); animator.start(); } public static void initial(View view, float moveToPosition1, int moveDownDuration, int moveUpDuration, int disappearTime1) { target = view; moveToPosition = moveToPosition1; disappearTime = disappearTime1; float start = view.getY(); animator = ObjectAnimator.ofFloat(view, "TranslationY", start, moveToPosition); animator.start(); } public static void messageRemind() { //重置計時器 if (countDownTimer != null) countDownTimer.cancel(); countDownTimer = new MyCountDownTimer(disappearTime, 1000); countDownTimer.start(); //3種狀況 1.正在移動 2.已經隱藏了 3已經顯示 if (animator.isRunning()) { // 1 中止運行 隱藏控件 移動到 原始位置 而後 在 move down animator.cancel(); target.setVisibility(View.GONE); moveUp(0, new UnNormalMoveUpListener()); } else if (target.getVisibility() != View.VISIBLE) { // 2 正常 move down moveDown(moveDownDuration); } else if (target.getVisibility() == View.VISIBLE) { // 3 隱藏 控件 向上移動,而後正常向移動 target.setVisibility(View.GONE); moveUp(0, new UnNormalMoveUpListener()); } } //跳轉到其餘界面時不要顯示消息提醒 public static void cancelMessageRemind() { //取消計時 countDownTimer.cancel(); //2種狀況 1.正在移動 3已經顯示 if (animator.isRunning()) { // 1 中止運行 隱藏控件 移動到 原始位置 animator.cancel(); target.setVisibility(View.GONE); moveUp(0, null); } else if (target.getVisibility() == View.VISIBLE) { // 2 隱藏 控件 向上移動 target.setVisibility(View.GONE); moveUp(0, null); } } //滑動floatView來提早讓他moveup public static void moveOrClickFloatMessageViewToMoveUp() { countDownTimer.cancel(); moveUp(200, new MoveFloatMessageVeiwMoveUpListener()); } public static void setMoveUpEndListener(MoveUpEndListener moveUpEndListener1) { moveUpEndListener = moveUpEndListener1; } //銷燬計時器,和一些對象,避免內存泄露 public static void destroyAnything() { if (countDownTimer != null) { countDownTimer.cancel(); countDownTimer = null; } target = null; animator = null; } public interface MoveUpEndListener { void floatMessageViewContentViewResume(); } private static class UnNormalMoveUpListener extends AnimatorListenerAdapter { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); if (target.getVisibility() == View.VISIBLE) target.setVisibility(View.GONE); moveDown(moveDownDuration); } } private static class NormalMoveUpListener extends AnimatorListenerAdapter { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); if (target.getVisibility() == View.VISIBLE) target.setVisibility(View.GONE); } } private static class MoveFloatMessageVeiwMoveUpListener extends AnimatorListenerAdapter { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); if (target.getVisibility() == View.VISIBLE) target.setVisibility(View.GONE); if (moveUpEndListener != null) moveUpEndListener.floatMessageViewContentViewResume(); } } private static class MyCountDownTimer extends CountDownTimer { /** * @param millisInFuture The number of millis in the future from the call * to {@link #start()} until the countdown is done and {@link #onFinish()} * is called. * @param countDownInterval The interval along the way to receive * {@link #onTick(long)} callbacks. */ public MyCountDownTimer(long millisInFuture, long countDownInterval) { super(millisInFuture, countDownInterval); } @Override public void onTick(long millisUntilFinished) { Log.i("zengzeming", "onTick : " + millisUntilFinished / 1000); } @Override public void onFinish() { moveUp(moveUpDuration, null); } } }
package com.zzm.ndkandmaterialdesigndemo; import android.animation.FloatEvaluator; import android.animation.ObjectAnimator; import android.content.Context; import android.graphics.Point; import android.support.v4.widget.ViewDragHelper; import android.support.v7.widget.CardView; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.widget.TextView; import android.widget.Toast; /** * Date : 2017/12/21 9:28 * Author : 22m * Description : * onFinishInflate * onMeasure * onSizeChanged * onLayout */ public class FloatMessageView extends CardView implements MessageRemindUtil.MoveUpEndListener { private ViewDragHelper viewDragHelper; private View dragedView; private Point dragedViewPositionPoint; private boolean manualMoved; private int dragedViewWidth; private int floatMessageViewWidth; private int paddingLeft; private int paddingRight; public FloatMessageView(Context context) { super(context); initial(); } public FloatMessageView(Context context, AttributeSet attrs) { super(context, attrs); initial(); } public FloatMessageView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initial(); } private void initial() { //初始化viewdraghelper(綁定要反饋的佈局)等 viewDragHelper = ViewDragHelper.create(this, 1.0f, new ViewDragHelperCallback()); MessageRemindUtil.setMoveUpEndListener(this); dragedViewPositionPoint = new Point(); manualMoved = false; dragedViewWidth = 0; floatMessageViewWidth = 0; paddingLeft = 0; paddingRight = 0; } @Override public boolean onTouchEvent(MotionEvent event) { //觸摸事件傳遞給viewdraghelper來處理 viewDragHelper.processTouchEvent(event); return true; } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { //攔截事件交給viewdraghelper來處理 return viewDragHelper.shouldInterceptTouchEvent(ev); } @Override protected void onFinishInflate() { //佈局加載完調用,能夠獲得佈局裏面的控件 super.onFinishInflate(); dragedView = getChildAt(0); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { //第一次佈局分配尺寸的時候調用,以及佈局變化的時候調用 super.onSizeChanged(w, h, oldw, oldh); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { //肯定了佈局位置的時候調用 super.onLayout(changed, left, top, right, bottom); // getTop(getLeft)永遠都是第一次加載佈局控件的原始y值 dragedViewPositionPoint.x = dragedView.getLeft(); dragedViewPositionPoint.y = dragedView.getTop(); dragedViewWidth = dragedView.getMeasuredWidth(); floatMessageViewWidth = getMeasuredWidth(); paddingLeft = getPaddingLeft(); paddingRight = getPaddingRight(); } @Override public void floatMessageViewContentViewResume() { //移動到原位透明度也設置爲原始值 ObjectAnimator animator = ObjectAnimator.ofFloat(dragedView, "TranslationX", 0f, 0f); animator.setDuration(0); animator.start(); dragedView.setAlpha(1f); } public void setDragedViewClickInformation(Object object) { dragedView.setTag(object); ((TextView) dragedView).setText((CharSequence) object); } public void setDragedViewClickListener(OnClickListener onClickListener) { dragedView.setOnClickListener(onClickListener); } @Override public void computeScroll() { //更新滑動的一些相關數據 super.computeScroll(); //判斷是否正在移動 if (viewDragHelper.continueSettling(true)) { invalidate(); } else { if (manualMoved && dragedView.getX() != dragedViewPositionPoint.x) { MessageRemindUtil.moveOrClickFloatMessageViewToMoveUp(); } manualMoved = false; } } private class ViewDragHelperCallback extends ViewDragHelper.Callback { @Override public boolean tryCaptureView(View child, int pointerId) { //能夠肯定哪一個view可以響應手指的觸摸事件 return true; } @Override public int clampViewPositionHorizontal(View child, int left, int dx) { //控制水平移動的響應 return left; } @Override public int clampViewPositionVertical(View child, int top, int dy) { //控制垂直移動的響應 return dragedViewPositionPoint.y; } @Override public int getViewHorizontalDragRange(View child) { return floatMessageViewWidth - paddingLeft - paddingRight; } @Override public int getViewVerticalDragRange(View child) { return super.getViewVerticalDragRange(child); } @Override public void onViewReleased(View releasedChild, float xvel, float yvel) { //當手指觸摸控件後離開控件的時候方法的調用 super.onViewReleased(releasedChild, xvel, yvel); int x = dragedViewPositionPoint.x; int y = dragedViewPositionPoint.y; float dragViewX = releasedChild.getX(); if (releasedChild == dragedView) { if (dragViewX > dragedViewWidth / 3 || (xvel > 500 && dragViewX > 0)) { x = floatMessageViewWidth - paddingLeft - paddingRight; } else if (dragViewX < -dragedViewWidth / 3 || (xvel < -500 && dragViewX < 0)) { x = -dragedViewWidth; } //此方法針對釋放的view,模擬手指拖動的view 的動做(只能在onViewReleased方法中調用) viewDragHelper.settleCapturedViewAt(x, y); //更新繪製的一些數據 invalidate(); } } @Override public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { // drag view 位置改變的時候 能夠設置透明的操做 super.onViewPositionChanged(changedView, left, top, dx, dy); manualMoved = true; FloatEvaluator floatEvaluator = new FloatEvaluator(); float total = floatMessageViewWidth / 2; float current = Math.abs(left); current = current > total ? total : current; float ratio = current / total; float alpha = floatEvaluator.evaluate(ratio, 1, 0); dragedView.setAlpha(alpha); } } /** * 使用步驟: * 1.找到控件 * 2.MessageRemindUtil初始化 * 3.設置DragedView 的點擊監聽器 * 4.設置DragedView的點擊能夠使用的信息 * 5.彈出懸浮view * 6. 4-->5-->4-->5-->4-->5 */ }