欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

自定义Toast(悬浮窗口)

程序员文章站 2022-07-13 23:47:54
...

写在开头

或许你会遇到一个需求,就是在app的界面之上显示一个类似toast的按钮,来开展一些我们的逻辑实现,今天就来写写这个。

实现步骤

首先我们定义一个类(传入上下文,难免会用到)

    public class AddrToast implements OnTouchListener {
    private Context context;
    private View mView;// 显示的view
    private WindowManager mWM;//窗口管理者
    private int startX;//坐标
    private int startY;//坐标
    private WindowManager.LayoutParams params;
    public AddrToast(Context context) {
        super();
        this.context = context;
    }

显示的toast布局

可以自定义我们的布局满足我们各自需求
    //自定义显示的方法,根据需求传入需要的参数,这里我传入一个String。
    public void showToast(String addr) {
        // 每次显示之前 先隐藏(确保界面只有一个view)
        hide();
        // 要显示的view(可以任意,根据需求来定)
        mView = View.inflate(context, R.layout.addr_bg_normal, null);
        // 显示内容的view(简单的一个展示,数据是我传入的String)
        TextView tvAddr = (TextView) mView.findViewById(R.id.tv_addr);
        tvAddr.setText(addr);
        // 设置背景(简单的设置背景,其实你可以任意操作)
        mView.setBackgroundResource(R.drawable.bg_addr_normal_shape);
        // 设置触摸监听(因为我们一会要拖动他,当然类要实现这个接口)
        mView.setOnTouchListener(this);

        // 获取窗口管理器
        // window 窗口 其实我们的activity dialog toast ...都是显示在窗口上
        mWM =(WindowManager)context.getSystemService(Context.WINDOW_SERVICE);

        // 布局参数 在布局里,以layout_开头的属性都是可以可以在代码里设置
        //下面代码是从toast源码拷贝出来,并做了修改。有兴趣可以自己去看看
        params = new WindowManager.LayoutParams();
        params.height = WindowManager.LayoutParams.WRAP_CONTENT;
        params.width = WindowManager.LayoutParams.WRAP_CONTENT;
        params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
        // | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE 注释掉 因为我们要实现拖动的功能
                | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
        params.format = PixelFormat.TRANSLUCENT;
        // 更改显示级别 需要权限 <uses-permission
        // android:name="android.permission.SYSTEM_ALERT_WINDOW" />
        params.type = WindowManager.LayoutParams.TYPE_PRIORITY_PHONE;
        params.setTitle("Toast");
        // 给窗口添加一个*的布局(显示在所有布局之上)(mView我们自己的view)
        mWM.addView(mView, params);
    }

隐藏自定义toast的方法

public void hide() {
        if (mView != null) {
            // note: checking parent() just to make sure the view has
            // been added... i have seen cases where we get here when
            // the view isn't yet added, so let's try not to crash.
            //英文意思就是判断之前有没有add,就是有没有显示过自定义的view
            if (mView.getParent() != null) {
                mWM.removeView(mView);
            }
            //增加严谨性
            mView = null;
        }
    }

这里我们增加了个需求,view可以随意拖动,其实你也可以有自己的逻辑

    // 触摸事件 
    // 参1 触摸的view 参2 触摸事件的对象
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        // 获取动作
        int action = event.getAction();
        switch (action) {
        case MotionEvent.ACTION_DOWN:
            // System.out.println("按下");
            // event.getX();//原点是自己的左上角
            // 获取起始点的坐标 原点是屏幕的左上角
            startX = (int) event.getRawX();
            startY = (int) event.getRawY();
            break;
        case MotionEvent.ACTION_MOVE:
            // System.out.println("移动");
            // 获取移动后的坐标
            int moveX = (int) event.getRawX();
            int moveY = (int) event.getRawY();
            // 获取移动的距离
            int disX = moveX - startX;
            int disY = moveY - startY;
            // 改变view的布局参数里的位置
            params.x += disX;
            params.y += disY;
            // 更新view的布局参数(用来更新view在窗口的位置)
            mWM.updateViewLayout(mView, params);
            // 每次移动后更改起始点的位置(作为下次的参考起点)
            startX = moveX;
            startY = moveY;
            break;
        case MotionEvent.ACTION_UP:
            // System.out.println("抬起");
            break;
        default:
            break;
        }
        return false;
    }

关于这些,就先写到这,大家有什么需求,或者问题留言探讨,共同努力。