Android 實現頂層窗口、浮動窗口(附Demo)


  做過Window程序開發的朋友應該都知道,我們要把程序窗口置頂很簡單,只要設置一些窗口屬性即可。但是到了Android,你無法簡單設置一個屬性,就讓Android的Activity置頂。因為只要有新的Activity啟動,你的Activity界面就會被擋住。今天介紹一下如何把一個窗口置頂。

  也許會有人說:你的窗口置頂了,就會破壞系統的穩定性,影響其他程序使用,這是流氓行為o(╯□╰)o 。對於這個問題,如果你的頂層窗口沒有處理好,的確會有這個問題。不過對於一些定制系統來說,這個功能可以實現很有用的功能,例如:對於一些需要長時間提示用戶的危險警告。例如下面效果圖,在瀏覽圖片的時候,系統彈出一個警告框,會一直提示用戶注意安全,就算切換到其他程序,這個提示框也會一直在頂層。

 

(PS:新建的QQ群,有興趣可以加入一起討論:Android群:322599434)

 

1、WindowManager介紹

  全部Android的窗口機制是基於一個叫做WindowManager實現,這個接口可以添加view到屏幕,也可以從屏幕刪除view。它面向的對象一端是屏幕,另一端就是View,直接忽視我們以前的Activity或者Dialog之類的元素。其實我們的Activity或者Diolog底層的實現也是經過WindowManager,WindowManager是全局的,整個系統只有一個WindowManager。它是顯示View的最底層了。WindowManager主要用來管理窗口的一些狀態、屬性、view增加、刪除、更新、窗口順序、消息收集和處理等。通過Context.getSystemService(Context.WINDOW_SERVICE)的方式可以獲得WindowManager的實例.WindowManager繼承自ViewManager,里面涉及到窗口管理的三個重要方法,分別是

  • addView(); 
  • updateViewLayout();
  • removeView();

  在WindowManager中還有一個重要的靜態類LayoutParams。通過它可以設置和獲得當前窗口的一些屬性。我們先來看看addView()方法,在addView中,會利用LayoutParams獲得window的View屬性,並為每個window創ViewRoot,ViewRoot是View和WindowManager之間的橋梁,真正把View傳遞給WindowManager的是通過ViewRoot的setView()方法,ViewRoot實現了View和WindowManager之間的消息傳遞。在將主窗口添加到WindowManger時,它首先會建立一個代理對象:

wm=(WindowManagerImpl)context.getSystemService(Context.WINDOW_SERVICE)

並且打開會話(IWindowSession),之后Window將通過該會話與WindowManager建立聯系。

 

 

2、使用WindowManager實現浮動窗口

    

//Edited by mythou
//http://www.cnblogs.com/mythou/
  private void createFloatView() { Button btn_floatView = new Button() btn_floatView = new Button(getApplicationContext()); btn_floatView.setText("懸浮窗"); wm = (WindowManager) getApplicationContext().getSystemService( Context.WINDOW_SERVICE); params = new WindowManager.LayoutParams(); // 設置window type params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; /* * 如果設置為params.type = WindowManager.LayoutParams.TYPE_PHONE; 那么優先級會降低一些, * 即拉下通知欄不可見 */ params.format = PixelFormat.RGBA_8888; // 設置圖片格式,效果為背景透明 // 設置Window flag params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; /* * 下面的flags屬性的效果形同“鎖定”。 懸浮窗不可觸摸,不接受任何事件,同時不影響后面的事件響應。 * wmParams.flags=LayoutParams.FLAG_NOT_TOUCH_MODAL | * LayoutParams.FLAG_NOT_FOCUSABLE | LayoutParams.FLAG_NOT_TOUCHABLE; */ // 設置懸浮窗的長得寬 params.width = 100; params.height = 100; // 設置懸浮窗的Touch監聽 btn_floatView.setOnTouchListener(new OnTouchListener() { int lastX, lastY; int paramX, paramY; public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: lastX = (int) event.getRawX(); lastY = (int) event.getRawY(); paramX = params.x; paramY = params.y; break; case MotionEvent.ACTION_MOVE: int dx = (int) event.getRawX() - lastX; int dy = (int) event.getRawY() - lastY; params.x = paramX + dx; params.y = paramY + dy; // 更新懸浮窗位置 wm.updateViewLayout(btn_floatView, params); break; } return true; } }); wm.addView(btn_floatView, params); isAdded = true; }

  上面是一段創建一個浮動窗口的代碼,主要就是使用了WindowManager的addView方法,把我們創建的一個View添加到WindowManager里面去。除了使用上面的代碼動態創建一個View,我們也可以直接加載某個XML文件,然后生成一個View,我們平常使用的XML布局文件解析完,都是能生成一個View對象,因此我們可以直接編寫一個布局文件然后使用LayoutInflater來加載對應的View。例如下面的代碼:


//Edited by mythou
//http://www.cnblogs.com/mythou/
LayoutInflater inflater = LayoutInflater.from(getApplicationContext());
//加載需要的XML布局文件 RelativeLayout mInView
= (RelativeLayout)inflater.inflate(R.layout.in_vedio, null, false);

//......
//添加到WindowManager里面
wm.addView(btn_floatView, params);

  如果需要實現一個全屏置頂的窗口,只要編寫一個全屏的XML配置文件即可,跟我們在Activity里面使用的XML配置界面一樣。 

 

3、注意事項

  在使用WindowManager的時候有一點需要注意的是,你只能把父節點的View添加到WindowManager里面,也就是說,你要添加的View不能是已經有父節點的某個子節點,否則會出現下面的問題:

 

4、結語

  上面就是創建一個頂層窗口或者浮動窗口的大致流程。之所以研究這個,我並不是為了做浮動窗口,而是為了做浮動視頻播放,這個下次有空,再寫一篇如何做浮動視頻播放的文章。

  最后補充一點,不要輕易使用全屏置頂的方法,因為這個會影響你系統其它程序的運行。特別是你的View設置為透明和全屏置頂,會導致界面無法操作。

 

給出一個浮動窗口的DemoFloating_window2013-8-7.rar

 

Edited by mythou

原創博文,轉載請標明出處:http://www.cnblogs.com/mythou/p/3244208.html 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM