顶级窗口会显示在所有视图之上,可以利用此特性用来显示优先级高的业务。
我把它可分为常规式顶级窗口和遮罩式顶级窗口。
常规式顶级窗口不影响其他组件获取焦点(图1);遮罩式顶级窗口顾名思义就是把其他组件都遮住了(图2)。
图1 图2
实现方式:
先启动一个服务(aidl),由该服务去绘制窗口,并对外提供绘制接口(实现见下面代码);
单独写一个应用(如上),用来连接服务并显示顶级窗口。
服务端控制顶级窗口显示与销毁的代码:/**
* 该服务用来测试顶级窗口的设置.
* @author QiShuang
*
*/
public class MService extends Service {
private static final int WRAP = WindowManager.LayoutParams.WRAP_CONTENT;
private static final int FILL = WindowManager.LayoutParams.FILL_PARENT;
/** 常规的顶级窗口--该顶级view下的部件可以继续操作 */
public static final int TYPE_TOPLEVEL_WIN_NORMAL = 1;
/**遮罩式(模式)顶级窗口--该顶级view下的部件被遮住,不可以操作 */
public static final int TYPE_TOPLEVEL_WIN_MODAL = 2;
private WindowManager wm;
private View subView;
@Override
public void onCreate() {
super.onCreate();
showToast("remote service onCreate...");
}
@Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
showToast("remote service onStart...");
}
@Override
public IBinder onBind(Intent intent) {
showToast("remote service onBind...");
return iBinder;
}
@Override
public boolean onUnbind(Intent intent) {
showToast("remote service onUnbind...");
return super.onUnbind(intent);
}
@Override
public void onDestroy() {
super.onDestroy();
showToast("remote service onDestroy...");
}
public void showToast(String msg) {
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
}
private Handler handler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case 1: {// drawTopWindow
wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
subView = getLayout();
WindowManager.LayoutParams mWmlp = getWinLayParams(msg.arg1);
wm.addView(subView, mWmlp);
break;
}
case 2: {// cancelTopWindow
if(wm!=null && subView!=null){
wm.removeViewImmediate(subView);
subView=null;
}
break;
}
}
};
};
private IBinder iBinder = new IService.Stub() {
public void drawTopWin(int type) throws RemoteException {
Message msg = new Message();
msg.what = 1;
msg.arg1 = type;
handler.sendMessage(msg);
//10s后消失
handler.postDelayed(new Runnable() {
public void run() {
handler.sendEmptyMessage(2);
}
}, 10000);
}
public void cancelTopWin() throws RemoteException {
handler.sendEmptyMessage(2);
}
};
// 构造布局View
private View getLayout() {
LinearLayout layout = new LinearLayout(this);
// layout.setLayoutParams(new LinearLayout.LayoutParams(WRAP,WRAP));
layout.setBackgroundColor(Color.YELLOW);
layout.setOrientation(LinearLayout.VERTICAL);
layout.setGravity(Gravity.CENTER);
TextView tx = new TextView(this);
tx.setLayoutParams(new LinearLayout.LayoutParams(200,100));
tx.setTextColor(Color.BLUE);
tx.setGravity(17);
tx.setText("我站在山峰之巅!!!");
Button btn = new Button(this);
btn.setLayoutParams(new LinearLayout.LayoutParams(WRAP,WRAP));
btn.setText("OK");
btn.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
handler.sendEmptyMessage(2);
}
});
layout.addView(tx);
layout.addView(btn);
return layout;
}
private LayoutParams getWinLayParams(int type) {
WindowManager.LayoutParams wlp = new WindowManager.LayoutParams(FILL,WRAP);
wlp.alpha = 0.5f;
wlp.dimAmount = .5f;
if(type==TYPE_TOPLEVEL_WIN_MODAL){//模式顶级窗口
wlp.flags = WindowManager.LayoutParams.FLAG_DIM_BEHIND;//任何部件都在其之下,可以通过dimAmount(0~1.0)设置透明度
}else if(type==TYPE_TOPLEVEL_WIN_NORMAL){//常规顶级窗口
wlp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; // 不抢聚焦点
}
wlp.flags = wlp.flags
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
wlp.flags = wlp.flags
| WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; //allow window to extend outside of the screen
wlp.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; //系统提示类型
wlp.width = WRAP;//WindowManager.LayoutParams.MATCH_PARENT;
wlp.height = WRAP;//WindowManager.LayoutParams.MATCH_PARENT;
wlp.gravity = Gravity.CENTER;
return wlp;
}
}
step1:设置WindowManager.LayoutParams属性(flags、type很重要);
step2:定义要在窗口中显示的view;
step3:将view加入到WindowManager中。
此功能会涉及到以下2个权限,加入到manifest.xml中即可:
<uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />