Android-仿QQ/微信-全局新消息提示

最近趕項目比較忙,趁週末補點文章。

效果預覽:

效果預覽

開發需求:

  • 這個彈窗一般用於新消息展示,需要是全局的,所以採用WindowManager來做,可以顯示在其他應用之上。
  • 一般消息彈窗會在幾秒內消息,否則會影響用戶體驗,所以還需要延時關閉。
  • 消息彈出後要給用戶選擇的機會,所以用戶可以手動移除彈窗,這裏採用手勢來達到取消顯示的目的。

擼碼:

1.先擼一個類,構造傳入上下文,因爲待會會用。
public class TitleTextWindow {

    private Context mContext;

    public TitleTextWindow(Context context) {
        mContext = context;
    }

}
2.抽取幾個必要的方法,然後進行代碼編寫。
    /**
     * 向外部暴露顯示的方法
     */
    public void show(){

    }
    /**
     * 向外部暴露關閉的方法
     */
    public void dismiss(){

    }

    /**
     * 視圖創建方法
     */
    private void createTitleView(){

    }
3.將僞代碼功能實現。
    /**
     * 向外部暴露顯示的方法
     */
    public void show(){
        createTitleView();
        animShow();
        //3S後自動關閉
        mHander.sendEmptyMessageDelayed(20, 3000);
    }

    /**
     * 向外部暴露關閉的方法
     */
    public void dismiss(){
        animDismiss();
    }

    /**
     * 視圖創建方法
     */
    private void createTitleView(){
        //準備Window要添加的View
        linearLayout = new LinearLayout(mContext);
        final LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
        linearLayout.setLayoutParams(layoutParams);
        View titleView = View.inflate(mContext, R.layout.header_toast, null);//這裏是你彈窗的UI
        // 爲titleView設置Touch事件
        linearLayout.setOnTouchListener(this);
        linearLayout.addView(titleView);
        // 定義WindowManager 並且將View添加到WindowManagar中去
        wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
        WindowManager.LayoutParams wm_params = new WindowManager.LayoutParams();
        wm_params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                | WindowManager.LayoutParams.FLAG_FULLSCREEN
                | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
        //這裏需要注意,因爲不同系統版本策略不一,所以需要根據版本判斷設置type,否則會引起崩潰。
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1) {//大於android SDK 7.1.1
            wm_params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
        } else {
            wm_params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
        }
        wm_params.gravity =  Gravity.TOP;
        wm_params.x = 0;
        wm_params.y = 0;
        wm_params.format = -3;  // 會影響Toast中的佈局消失的時候父控件和子控件消失的時機不一致,比如設置爲-1之後就會不同步
        wm_params.alpha = 1f;
        linearLayout.measure(0, 0);
        wm_params.height = linearLayout.getMeasuredHeight();
        wm.addView(linearLayout, wm_params);
    }
4.處理手勢,讓用戶可以手指上撥,劃出屏幕。
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                downY = (int) event.getRawY();
                break;
            case MotionEvent.ACTION_MOVE:
                int moveY = (int) event.getRawY();
                if (moveY - downY < 0) {//如果是向上滑動
                    linearLayout.setTranslationY(moveY - downY);
                }
                break;
            case MotionEvent.ACTION_UP:
                //達到一定比例後,鬆開手指將關閉彈窗
                if (Math.abs(linearLayout.getTranslationY()) > linearLayout.getMeasuredHeight() / 1.5) {
                    Log.e("TAG", "回彈");
                    animDismiss();
                } else {
                    linearLayout.setTranslationY(0);
                }
                break;
            default:
                break;
        }
        return true;
    }
5.調用。
        TitleTextWindow textWindow=new TitleTextWindow(this);
        textWindow.show();
6.完整代碼:
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.os.Build;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.LinearLayout;

import view.peakchao.view.R;

/**
 * Created by Chao on 2018-09-08.
 */

public class TitleTextWindow implements View.OnTouchListener {

    private Context mContext;
    private WindowManager wm;
    private LinearLayout linearLayout;
    private int downY;

    public TitleTextWindow(Context context) {
        mContext = context;
    }

    private android.os.Handler mHander = new android.os.Handler(Looper.myLooper()) {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
                animDismiss();
        }
    };

    /**
     * 動畫,從頂部彈出
     */
    private void animShow(){
        //使用動畫從頂部彈出
        ObjectAnimator animator = ObjectAnimator.ofFloat(linearLayout, "translationY", -linearLayout.getMeasuredHeight(), 0);
        animator.setDuration(600);
        animator.start();
    }

    /**
     * 動畫,從頂部收回
     */
    private void animDismiss(){
        if (linearLayout == null || linearLayout.getParent() == null) {
            return;
        }
        ObjectAnimator animator = ObjectAnimator.ofFloat(linearLayout, "translationY", linearLayout.getTranslationY(), -linearLayout.getMeasuredHeight());
        animator.setDuration(600);
        animator.start();
        animator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationCancel(Animator animation) {
                super.onAnimationCancel(animation);
            }

            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                //移除HeaderToast  (一定要在動畫結束的時候移除,不然下次進來的時候由於wm裏邊已經有控件了,所以會導致卡死)
                if (null != linearLayout && null != linearLayout.getParent()) {
                    wm.removeView(linearLayout);
                }
            }

            @Override
            public void onAnimationRepeat(Animator animation) {
                super.onAnimationRepeat(animation);
            }

            @Override
            public void onAnimationStart(Animator animation) {
                super.onAnimationStart(animation);
            }

            @Override
            public void onAnimationPause(Animator animation) {
                super.onAnimationPause(animation);
            }

            @Override
            public void onAnimationResume(Animator animation) {
                super.onAnimationResume(animation);
            }
        });
    }

    /**
     * 向外部暴露顯示的方法
     */
    public void show(){
        createTitleView();
        animShow();
        //3S後自動關閉
        mHander.sendEmptyMessageDelayed(20, 3000);
    }
    /**
     * 向外部暴露關閉的方法
     */
    public void dismiss(){
        animDismiss();
    }


    /**
     * 視圖創建方法
     */
    private void createTitleView(){
        //準備Window要添加的View
        linearLayout = new LinearLayout(mContext);
        final LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
        linearLayout.setLayoutParams(layoutParams);
        View titleView = View.inflate(mContext, R.layout.header_toast, null);//這裏是你彈窗的UI
        // 爲titleView設置Touch事件
        linearLayout.setOnTouchListener(this);
        linearLayout.addView(titleView);
        // 定義WindowManager 並且將View添加到WindowManagar中去
        wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
        WindowManager.LayoutParams wm_params = new WindowManager.LayoutParams();
        wm_params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                | WindowManager.LayoutParams.FLAG_FULLSCREEN
                | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
        //這裏需要注意,因爲不同系統版本策略不一,所以需要根據版本判斷設置type,否則會引起崩潰。
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1) {//大於android SDK 7.1.1
            wm_params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
        } else {
            wm_params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
        }
        wm_params.gravity =  Gravity.TOP;
        wm_params.x = 0;
        wm_params.y = 0;
        wm_params.format = -3;  // 會影響Toast中的佈局消失的時候父控件和子控件消失的時機不一致,比如設置爲-1之後就會不同步
        wm_params.alpha = 1f;
        linearLayout.measure(0, 0);
        wm_params.height = linearLayout.getMeasuredHeight();
        wm.addView(linearLayout, wm_params);
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                downY = (int) event.getRawY();
                break;
            case MotionEvent.ACTION_MOVE:
                int moveY = (int) event.getRawY();
                if (moveY - downY < 0) {//如果是向上滑動
                    linearLayout.setTranslationY(moveY - downY);
                }
                break;
            case MotionEvent.ACTION_UP:
                //達到一定比例後,鬆開手指將關閉彈窗
                if (Math.abs(linearLayout.getTranslationY()) > linearLayout.getMeasuredHeight() / 1.5) {
                    Log.e("TAG", "回彈");
                    animDismiss();
                } else {
                    linearLayout.setTranslationY(0);
                }
                break;
            default:
                break;
        }
        return true;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章