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

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/c__chao/article/details/82528094

最近赶项目比较忙,趁周末补点文章。

效果预览:

效果预览

开发需求:

  • 这个弹窗一般用于新消息展示,需要是全局的,所以采用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;
    }
}

猜你喜欢

转载自blog.csdn.net/c__chao/article/details/82528094