Android 模擬消息懸浮通知(只適用於應用內--ViewDragHelper,不須要權限的懸浮Notification)

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
     */

}
相關文章
相關標籤/搜索