使用WindowManager添加View——悬浮窗口的基本原理

一、 WindowManager  

  1. 获取WindowManager

     

    wManager = (WindowManager) getApplicationContext().getSystemService(
                    Context.WINDOW_SERVICE);

    在Activity和Service中都可以直接使用这个方法来获得WindowManager。其getSystemService返回的是一个WindowManagerImpl对象,这是一个存在于本地进程中的一个对象。而事实是 WindowManagerImpl 继承了WindowManager,而WindowManger继承了ViewManager。  

  2. 设置WindowManager.LayoutParams

    LayoutParams里面存放着的是窗口的属性,通过这个变量,可以为窗口赋予各式的属性。也可以改变它的属性值,来进行各种各样的操作,像悬浮窗口的拖动,拉伸等操作。

    详细的属性表在:

    http://www.cnblogs.com/shitianzeng/articles/2814050.html  

  3.  

    WindowManager的操作

    (1)窗口添加

       

    public void addView(View view, ViewGroup.LayoutParams params);

    (2)窗口更新

    public void updateViewLayout(View view, ViewGroup.LayoutParams params);

    (3)窗口删除

    public void removeView(View view);

    以上的三个方法都存在于ViewManager中。

二、

悬浮窗实例

例子设计:利用service打开悬浮窗,其中放着一个自定义的View,点击消除悬浮窗。

  1.  

    首先是Service,它是由Activity打开。先获得WindowManager,再配置属性

     

    public class WindowService extends Service implements OnClickListener {  private WindowManager wManager;// 窗口管理者  private WindowManager.LayoutParams mParams;// 窗口的属性  private MyView myView;  private boolean flag = true;  @Override  public IBinder onBind(Intent intent) {    // TODO Auto-generated method stub    return null;  }  @Override  public void onCreate() {    // TODO Auto-generated method stub    wManager = (WindowManager) getApplicationContext().getSystemService(        Context.WINDOW_SERVICE);    mParams = new WindowManager.LayoutParams();    mParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;// 系统提示window    mParams.format = PixelFormat.TRANSLUCENT;// 支持透明    //mParams.format = PixelFormat.RGBA_8888;    mParams.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;// 焦点    mParams.width = 490;//窗口的宽和高    mParams.height = 160;    mParams.x = 0;//窗口位置的偏移量    mParams.y = 0;    //mParams.alpha = 0.1f;//窗口的透明度    myView = new MyView(this);    myView.setOnClickListener(this);    super.onCreate();  }  @Override  public int onStartCommand(Intent intent, int flags, int startId) {    // TODO Auto-generated method stub    if (flag) {      flag = false;      wManager.addView(myView, mParams);//添加窗口    }    return super.onStartCommand(intent, flags, startId);  }  @Override  public void onDestroy() {    // TODO Auto-generated method stub    if (myView.getParent() != null)      wManager.removeView(myView);//移除窗口    super.onDestroy();  }  @Override  public void onClick(View v) {    // TODO Auto-generated method stub    if (v.equals(myView)) {      flag = true;      if (myView.getParent() != null)        wManager.removeView(myView);//移除窗口    }  }
    
    }

  2. 一个自定义的view

    很早以前写的surfaceView,里面包括文字图片的两个显示动画

       

       

    @SuppressLint("WrongCall")public class MyView extends SurfaceView implements SurfaceHolder.Callback {  private static int span = 5;  private MyThread wtf;  private Paint paint;  int sleepSpan = 150; // 动画的时延ms  Bitmap logo_s, logo_l; // logo图片引用  int width_s; // 图片大小  int height_s;  float currentX_s; // 图片位置  float currentY_s;  float currentX_l; // 图片位置  float currentY_l;  private Rect src;  private RectF dst;  private int currentAlpha = 0;  public MyView(Context context) {    super(context);    this.getHolder().addCallback(this);// 设置生命周期回调接口的实现者    paint = new Paint();// 创建画笔    paint.setAntiAlias(true);// 打开抗锯齿  }  @Override  public void surfaceCreated(SurfaceHolder holder) {    logo_s = BitmapFactory        .decodeResource(getResources(), R.drawable.logo_s);    logo_l = BitmapFactory        .decodeResource(getResources(), R.drawable.logo_l);    // TODO Auto-generated method stub    width_s = logo_s.getWidth();    height_s = logo_s.getHeight();    src = new Rect(0, 0, 0, height_s);    // 大图片的位置    currentX_s = 5;    currentY_s = 5;    dst = new RectF(currentX_s, currentY_s, currentX_s, currentY_s        + height_s);    currentX_l = currentX_s + width_s - logo_l.getWidth();    // 小图片的位置    currentY_l = currentY_s + height_s;    currentAlpha = 0;    wtf = new MyThread();    wtf.start();  }  @Override  public void surfaceChanged(SurfaceHolder holder, int format, int width,      int height) {    // TODO Auto-generated method stub  }  @Override  public void surfaceDestroyed(SurfaceHolder holder) {    // TODO Auto-generated method stub  }  @Override  public void onDraw(Canvas canvas) {    // TODO Auto-generated method stub    // 绘制黑填充矩形清背景    super.onDraw(canvas);        paint.setAlpha(120);// 设置不透明度为255    paint.setColor(Color.BLACK);// 设置画笔颜色    canvas.drawColor(Color.BLACK);    // 进行平面贴图    if (logo_s == null || logo_l == null)      return;    src.right += span;    dst.right += span;    canvas.drawBitmap(logo_s, src, dst, paint);    paint.setAlpha(currentAlpha);    canvas.drawBitmap(logo_l, currentX_l, currentY_l, paint);    // canvas.drawBitmap(bitmap, src, dst, paint);    /*     * Rect src = new Rect(x1, y2, cx1,cy1); Rect dst = new Rect(x2, y2,     * cx2, cy2); 第一个矩形,是你想截取的bitmap里面的哪一段。 第二个矩形,是你想显示在屏幕上的什么位置。     * 两个矩形可以不一样大小,在绘制的时候,会自动拉伸。     */  }  class MyThread extends Thread {    public void run() {      SurfaceHolder mholder = MyView.this.getHolder();// 获取回调接口      // 绘制tatans      try {        sleep(500);      } catch (InterruptedException e1) {        // TODO Auto-generated catch block        e1.printStackTrace();      }      for (int i = 0; i <= width_s / span; i++) {        Canvas canvas = mholder.lockCanvas();// 获取画布        try {          synchronized (mholder) // 同步          {            onDraw(canvas);// 进行          }          sleep(20);        } catch (Exception e) {          // TODO Auto-generated catch block          e.printStackTrace();        } finally {          if (canvas != null) {            mholder.unlockCanvasAndPost(canvas);          }        }      }      // 绘制天坦智慧      for (int i = 0; i <= 25; i++) {        currentAlpha = i * 10;        Canvas canvas = mholder.lockCanvas();// 获取画布        try {          synchronized (mholder) // 同步          {            onDraw(canvas);// 进行          }          sleep(25);        } catch (Exception e) {          // TODO Auto-generated catch block          e.printStackTrace();        } finally {          if (canvas != null) {            mholder.unlockCanvasAndPost(canvas);          }        }      }    }  }
    
    }

       看看就行了  

  3. Activity中,点击打开service

      @Override  public boolean onTouchEvent(MotionEvent event) {    // TODO Auto-generated method stub    Log.d("CPACM","onTouchEvent");    Intent intent = new Intent();    intent.setClass(this, WindowService.class);    startService(intent);    this.finish();    return super.onTouchEvent(event);  }

  4. manifest.xml

    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> <!-- 使用SYSTEM_ALERT_WINDOW时必须要加 -->

  5. 效果图
    使用WindowManager添加View——悬浮窗口的基本原理   使用WindowManager添加View——悬浮窗口的基本原理

三、

结束语

学到越深,发现需要学的越多


你可能感兴趣的:(使用WindowManager添加View——悬浮窗口的基本原理)