自定义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;
}
关于这些,就先写到这,大家有什么需求,或者问题留言探讨,共同努力。
上一篇: 单例模式的示例代码