WindowManager实现悬浮窗口

来源:互联网 发布:品控好的手机 知乎 编辑:程序博客网 时间:2024/04/30 23:39

调用WindowManager,并设置WindowManager.LayoutParams的相关属性,通过WindowManager的addView方法创建View,这样产生出来的View根据WindowManager.LayoutParams属性不同,效果也就不同了。比如创建系统顶级窗口,实现悬浮窗口效果! 需要特别说明的是,在MIUI系统上面,悬浮框默认是不显示的,需要到设置-应用程序里面找到应用信息,打开显示悬浮窗选项。
WindowManager的方法很简单,基本用到的就三个addView,removeView,updateViewLayout。 


而WindowManager.LayoutParams的属性就多了,非常丰富,具体请查看SDK文档。这里给出Android中的WindowManager.java源码,可以具体看一下。 
WindowManager 的源码地址: 
http://www.netmite.com/android/mydroid/frameworks/base/core/java/android/view/WindowManager.java 

public class myFloatView extends Activity {      /** Called when the activity is first created. */      @Override      public void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState);          setContentView(R.layout.main);          Button bb=new Button(getApplicationContext());          WindowManager wm=(WindowManager)getApplicationContext().getSystemService("window");          WindowManager.LayoutParams wmParams = new WindowManager.LayoutParams();          //wmParams.type=2002;  //type是关键,这里的2002表示系统级窗口,你也可以试试2003。 wmParams.type=LayoutParams.TYPE_PHONE;//wmParams.format=PixelFormat.RGBA_8888;   //设置图片格式,效果为背景透明        wmParams.format=1;         wmParams.flags=LayoutParams.FLAG_NOT_TOUCH_MODAL                               | LayoutParams.FLAG_NOT_FOCUSABLE;         /*         * 下面的flags属性的效果形同“锁定”。         * 悬浮窗不可触摸,不接受任何事件,同时不影响后面的事件响应。         wmParams.flags=LayoutParams.FLAG_NOT_TOUCH_MODAL                                | LayoutParams.FLAG_NOT_FOCUSABLE                               | LayoutParams.FLAG_NOT_TOUCHABLE;        */      /**          *这里的flags也很关键          *代码实际是wmParams.flags |= FLAG_NOT_FOCUSABLE;          *40的由来是wmParams的默认属性(32)+ FLAG_NOT_FOCUSABLE(8)          */          //wmParams.flags=40;          wmParams.width=40;          wmParams.height=40;          wm.addView(bb, wmParams);//创建View      }  }   

另外别忘了在AndroidManifest.xml文件中加入如下权限: 
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> 

关于代码中wmParams.type的值的问题,下面给出一些数值参考:

/**          * Window type: the status bar.  There can be only one status bar          * window; it is placed at the top of the screen, and all other          * windows are shifted down so they are below it.          */         public static final int TYPE_STATUS_BAR         = FIRST_SYSTEM_WINDOW;             /**          * Window type: the search bar.  There can be only one search bar          * window; it is placed at the top of the screen.          */         public static final int TYPE_SEARCH_BAR         = FIRST_SYSTEM_WINDOW+1;             /**          * Window type: phone.  These are non-application windows providing          * user interaction with the phone (in particular incoming calls).          * These windows are normally placed above all applications, but behind          * the status bar.          */         public static final int TYPE_PHONE              = FIRST_SYSTEM_WINDOW+2;             /**          * Window type: system window, such as low power alert. These windows          * are always on top of application windows.          */         public static final int TYPE_SYSTEM_ALERT       = FIRST_SYSTEM_WINDOW+3; 

这个FIRST_SYSTEM_WINDOW的值就是2000。2003和2002的区别就在于2003类型的View比2002类型的还要top,能显示在系统下拉状态栏之上! 


   可以看出来,2002的值的含义其实就是2000+2。数值2000的含义就是系统级窗口,2002和2003的区别就是 2003 比 2002还要更上一层!比如,type为2003的view,能显示在手机下拉状态栏之上! 
   而关于flags等其他的属性请参考SDK文档
   
   
   下面给出实现可以移动的悬浮窗步骤:
   1、通过覆写悬浮View中onTouchEvent方法实现自由移动悬浮窗口。 


2、悬浮窗口坐标的移动实际是windowMananager.LayoutParams中x和y的变换,但是要注意设置相应的gravity。 


3、用windowManager创建的View,当不需要时,务必记住使用windowManager的removeView方法来移除,请在Activity相关生命周期中自行添加扫尾工作。
public class MyFloatView extends ImageView {private float mTouchStartX;    private float mTouchStartY;    private float x;    private float y;        private WindowManager wm=(WindowManager)getContext().getApplicationContext().getSystemService("window");    private WindowManager.LayoutParams wmParams = ((MyApplication)getContext().getApplicationContext()).getMywmParams();public MyFloatView(Context context) {super(context);// TODO Auto-generated constructor stub} @Override public boolean onTouchEvent(MotionEvent event) {   //获取相对屏幕的坐标,即以屏幕左上角为原点      x = event.getRawX();        y = event.getRawY()-25;   //25是系统状态栏的高度     Log.i("currP", "currX"+x+"====currY"+y);     switch (event.getAction()) {        case MotionEvent.ACTION_DOWN:        //获取相对View的坐标,即以此View左上角为原点        mTouchStartX =  event.getX();                  mTouchStartY =  event.getY();                            Log.i("startP", "startX"+mTouchStartX+"====startY"+mTouchStartY);                        break;        case MotionEvent.ACTION_MOVE:                        updateViewPosition();            break;        case MotionEvent.ACTION_UP:        updateViewPosition();        mTouchStartX=mTouchStartY=0;        break;        }        return true;}  private void updateViewPosition(){//更新浮动窗口位置参数wmParams.x=(int)( x-mTouchStartX);wmParams.y=(int) (y-mTouchStartY);    wm.updateViewLayout(this, wmParams);     }}


0 0