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() { // reset the timer if (countDownTimer != null) countDownTimer.cancel(); countDownTimer = new MyCountDownTimer(disappearTime, 1000); countDownTimer.start(); //3 cases 1. is moving 2. has been hidden 3 has been displayed if (animator.isRunning()) { // 1 stop running the hidden control and move it to the original position and then move down animator.cancel(); target.setVisibility(View.GONE); moveUp(0, new UnNormalMoveUpListener()); } else if (target.getVisibility() != View.VISIBLE) { // 2 normal move down moveDown(moveDownDuration); } else if (target.getVisibility() == View.VISIBLE) { // 3 The hidden control moves up, then moves normally target.setVisibility(View.GONE); moveUp(0, new UnNormalMoveUpListener()); } } //Don't display message reminder when jumping to other interface public static void cancelMessageRemind() { // cancel the timer countDownTimer.cancel(); //2 cases 1. is moving 3 has been displayed if (animator.isRunning()) { // 1 stop running the hidden control and move it to the original position animator.cancel(); target.setVisibility(View.GONE); moveUp (0, null); } else if (target.getVisibility() == View.VISIBLE) { // 2 hide the control to move up target.setVisibility(View.GONE); moveUp (0, null); } } //Slide floatView to let him moveup in advance public static void moveOrClickFloatMessageViewToMoveUp() { countDownTimer.cancel(); moveUp(200, new MoveFloatMessageVeiwMoveUpListener()); } public static void setMoveUpEndListener(MoveUpEndListener moveUpEndListener1) { moveUpEndListener = moveUpEndListener1; } //Destroy the timer, and some objects, to avoid memory leaks 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() { //Initialize viewdraghelper (bind the layout to be fed back), etc. 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) { //The touch event is passed to viewdraghelper to handle viewDragHelper.processTouchEvent(event); return true; } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { //The interception event is handed over to viewdraghelper to handle return viewDragHelper.shouldInterceptTouchEvent(ev); } @Override protected void onFinishInflate() { //The layout is loaded and called, you can get the controls in the layout super.onFinishInflate(); dragedView = getChildAt(0); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { //Called when the layout allocates the size for the first time, and when the layout changes super.onSizeChanged(w, h, oldw, oldh); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { //Called when the layout position is determined super.onLayout(changed, left, top, right, bottom); // getTop(getLeft) is always the original y value of the layout control when it was first loaded dragedViewPositionPoint.x = dragedView.getLeft(); dragedViewPositionPoint.y = dragedView.getTop(); dragedViewWidth = dragedView.getMeasuredWidth(); floatMessageViewWidth = getMeasuredWidth(); paddingLeft = getPaddingLeft(); paddingRight = getPaddingRight(); } @Override public void floatMessageViewContentViewResume() { //Move to the original position and the transparency is also set to the original value 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() { //Update some related data of sliding super.computeScroll(); // Determine if it is moving 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) { //You can determine which view can respond to the touch event of the finger return true; } @Override public int clampViewPositionHorizontal(View child, int left, int dx) { //Control the response of horizontal movement return left; } @Override public int clampViewPositionVertical(View child, int top, int dy) { //Control the response of vertical movement 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) { //The method is called when the finger touches the control and leaves the control 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; } //This method simulates the action of the view dragged by the finger for the released view (can only be called in the onViewReleased method) viewDragHelper.settleCapturedViewAt(x, y); //Update some data drawn invalidate(); } } @Override public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { // When the position of the drag view changes, transparent operations can be set 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); } } /** * Steps for usage: * 1. Find the controls * 2.MessageRemindUtil initialization * 3. Set the click listener of DragedView * 4. Set the information that can be used by clicking on DragedView * 5. Pop up the floating view * 6. 4-->5-->4-->5-->4-->5 */ }