Window表示一个窗口的概念,在日常开发中直接接触Window的机会并不多,但是在某些特殊的时候我们需要在桌面上显示一个类似悬浮窗的东西,那么这种效果就需要用到window来实现。Window是一个抽象类,它的具体实现是PhoneWindow。创建一个window是一个很简单的事,只需要通过WindowManager即可完成。WindowManager是外界访问Window的入口,Window的具体实现位于WindowManagerService中,WindowManager和WindowManagerService的交互是一个IPC过程。Android中所有的视图都是通过Window来呈现的,不管是Activity、Dialog还是Toast,他们的视图实际上都是附加在Window上的,因此Window实际是View的直接管理者。单击事件由Window传递给DecorView,然后再由DecorView传递给我们的View,就连Activity的设置视图的方法setContentView在底层也是通过Window来完成的.
自定义吐司类 NewToast.java
public class NewToast implements View.OnTouchListener {
private Context mContext;
// 用来往顶层布局加或删视图
private WindowManager mWm;
// 吐司展示的布局
private View mView;
// 布局参数对象
private WindowManager.LayoutParams mParams;
public NewToast(Context context) {
super();
this.mContext = context;
mWm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
mParams = new WindowManager.LayoutParams();
// layout_width
mParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
// layout_height
mParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
// gravity
mParams.gravity = Gravity.LEFT | Gravity.TOP;
// 背景透明
mParams.format = PixelFormat.TRANSPARENT;//
// 坐标
mParams.x = 100;
mParams.y = 100;
// 类型
mParams.type = WindowManager.LayoutParams.TYPE_PRIORITY_PHONE;
// 特殊属性
mParams.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON// 屏幕高亮
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;// 不支持点击
// |WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;//不支持拖动
}
/***
* 方法
*
* @param msg
*/
public void show(String msg) {
dismiss();
mView = View.inflate(mContext, R.layout.view_toast, null);
mView.setBackgroundResource(R.drawable.shape_address_toast_normal);
mView.setOnTouchListener(this);
// 处理拖动事件OnTouchListener 例:公交车上的xx事件
TextView tvTitle = (TextView) mView.findViewById(R.id.view_toast_tv_title);
tvTitle.setText(msg);
mWm.addView(mView, mParams);// 1.布局 2.布局参数对象
long delayMillis = 3000;// 延时发消息
Runnable r = new Runnable() {
@Override
public void run() {
dismiss();
}
};
// 设置5000自动消失
new Handler().postDelayed(r, delayMillis);
}
/***
* 方法
*
*/
public void dismiss() {
if (mView != null) {
mWm.removeView(mView);
mView = null;
}
}
/***
* 方法 MotionEvent事件的参数 x,y 与操作状态action
* mParams.type=WindowManager.LayoutParams.TYPE_PRIORITY_PHONE;
*
* 还要求权限<!-- 添加窗口优先级的权限 -->
* <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
* //特殊属性 mParams.flags=WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON//屏幕高亮
* |WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;//不支持点击
* //|WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;//不支持拖动
*
* @param v
* @param event
* @return
*/
private int mStartX;
private int mStartY;
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// e1
mStartX = (int) event.getRawX();
mStartY = (int) event.getRawY();
break;
case MotionEvent.ACTION_MOVE:
// e2
int newX = (int) event.getRawX();
int newY = (int) event.getRawY();
// off
int offX = newX - mStartX;
int offY = newY - mStartY;
// 更新控件
mParams.x = mParams.x + offX;
mParams.y = mParams.y + offY;
int xMin=0;
int yMin=0;
//获取显示对象 可以获取屏幕的参数 宽高 屏幕密度
Display display=mWm.getDefaultDisplay();
int xMax=display.getWidth()-mView.getWidth();
int yMax=display.getHeight()-mView.getHeight();
if (mParams.x <= xMin) {
mParams.x = xMin;
}
if (mParams.x >= xMax) {
mParams.x = xMax;
}
if (mParams.y <= yMin) {
mParams.y = yMin;
}
if (mParams.y >= yMax) {
mParams.y = yMax;
}
System.out.println(" mParams.x "+ mParams.x+" mParams.y"+ mParams.y);
// 控件刷新 因为params.x params.y
mWm.updateViewLayout(mView, mParams);// 1当前布局 2.更新后LayoutParams
// 更新e1的位置
mStartX = (int) event.getRawX();
mStartY = (int) event.getRawY();
break;
case MotionEvent.ACTION_UP:
break;
}
return true;// 需要自己处理并消费这个整件
}
}
布局文件view_toast.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="8dp" >
<TextView
android:drawableLeft="@drawable/location"
android:id="@+id/view_toast_tv_title"
android:layout_width="wrap_content"
android:gravity="left|center_vertical"
android:layout_centerInParent="true"
android:drawablePadding="5dp"
android:layout_height="wrap_content"
android:text="归属地:"
android:textColor="#FFFFFF" />
</RelativeLayout>
自定义吐司背景 shape_address_toast_normal.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<!-- 填充色 -->
<solid android:color="#ADAAAD" />
<!-- 圆角 -->
<corners android:radius="5dp" />
<!-- 内边距 -->
<padding android:left="8dp"
android:top="8dp"
android:right="8dp"
android:bottom="8dp"/>
<!-- 最小的宽高 -->
<size android:width="20dp"
android:height="20dp"/>
</shape>