Android系统中的“窗口”类型虽然很多,但只有两大类是经常使用的:一是由系统进程管理的,称之为“系统窗口”;第二个就是由应用程序产生的,用于显示UI界面的“应用窗口”。如果大家熟悉WindowManagerService(窗口管理机制WMS)的话,那么一切都很简单。它是一个负责统筹管理所有窗口的一个服务,从始到终一直在运作。之所以扯上WMS,因为它才是大Boss,所有的窗口变化都要通知到它。而WindowManager虽然与它没有之间的关系,但是对它负责,所有信息会经过一定的途径传回到WMS中。额,跑题了,我们说的是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. 效果图
     

三、结束语
学到越深,发现需要学的越多

========================================

作者:cpacm
出处:(http://www.cnblogs.com/cpacm/p/4087690.html

使用WindowManager添加View——悬浮窗口的基本原理的更多相关文章

  1. Android添加系统级顶层窗口 和 WindowManager添加view的动画问题

    当Dialog有编辑框时如果选择会弹菜单窗口就不要用 Context applicationContext = mainActivity.getApplicationContext(); AlertD ...

  2. Android视频悬浮窗口实现

    前言 本文例子实现了点击显示悬浮窗口,同时窗口可播放视频,拖动位置,点击关闭及返回APP页面,通过例子来讲述悬浮窗口实现原理及细节处理,效果图如下所示: 原理 WindowManager对View视图 ...

  3. Android之悬浮窗口实现(WindowManager)

    工作中遇到一些项目需要把窗体显示在最上层,像来电弹窗显示电话号码等信息.拦截短信信息显示给用户或者游戏中实现声音的调节,我们想这些数据放在最上层,activity就满足不了我们的需求了,有些开发者使用 ...

  4. Android WindowManager和WindowManager.LayoutParams的使用以及实现悬浮窗口的方法

    1.理清概念 我们使用过Dialog和PopupWindow,还有Toast,它们都显示在Activity之上.那么我们首先需要理解的是android中是如何去绘制这些UI的呢?这里我只讲我所理解的, ...

  5. WindowManager和WindowManager.LayoutParams的使用以及实现悬浮窗口的方法

    写Android程序的时候一般用WindowManager就是去获得屏幕的宽和高,来布局一些小的东西.基本上没有怎么看他的其他的接口. 这两天想写一个简单的类似于Toast的东西,自定义布局,突然发现 ...

  6. Android悬浮窗口的实现

    效果图:(悬浮框可拖动) 在项目开发中有一个需求:弹出悬浮窗后,响应悬浮窗的事件再弹出对话框,但是对话框怎么也不显示.也就是说在弹出悬浮框的同时,不能再弹出对话框,可能的原因: 1.悬浮框的焦点在最前 ...

  7. Android中悬浮窗口

    调用WindowManager,并设置WindowManager.LayoutParams的相关属性,通过WindowManager的addView方法创建View,这样产生出来的View根据Wind ...

  8. Android中悬浮窗口的实现原理和示例代码

    用了我一个周末的时间,个中愤懑就不说了,就这个问题,我翻遍全球网络没有一篇像样的资料,现在将实现原理简单叙述如下: 调用WindowManager,并设置WindowManager.LayoutPar ...

  9. Android 悬浮窗口

    Android 悬浮窗口 一.创建悬浮窗口步骤    1.实现一个ViewGroup类,作为悬浮窗口的界面类,以便在里面重写onInterceptTouchEvent和onTouchEvent方法,实 ...

随机推荐

  1. [leetcode-648-Replace Words]

    In English, we have a concept called root, which can be followed by some other words to form another ...

  2. 前端开发神器Sublime Text2/3之安装使用(windows7/Mac)

    一,到官方网站下载神器 地址:http://www.sublimetext.com/3 Sublime Text 3 配置解释(默认){// 设置主题文件“color_scheme”: “Packag ...

  3. scrapy学习-爬取天天基金网基金列表

    目录 描述 环境描述 步骤记录 创建scrapy项目 设置在pycharm下运行scrapy项目 分析如何获取数据 编写代码 step 1:设置item step 2:编写spider step 3: ...

  4. Ext.net中TreePanel动态生成

    这个问题可以参考官网例子:http://examples2.ext.net/#/TreePanel/Basic/Built_in_CodeBehind/ 贴一段本人程序中用到的动态生成核心代码: Ex ...

  5. WebService使用介绍(一)

    Socket实现 javaSocket通信原理 第一步:服务端创建serverSocket,启动服务.监听端口 /** * 天气查询服务端 * @author SMN * @version V1.0 ...

  6. 使用ExecutorService实现线程池

    ExecutorService是java提供的用于管理线程池的类. 线程池的作用: - 控制线程数量 - 重用线程 当一个程序中创建了许多线程,并在任务结束后销毁,会给系统带来过度消耗资源,以及过度切 ...

  7. BZOJ4320 ShangHai2006 Homework(分块+并查集)

    考虑根号分块.对于<√3e5的模数,每加入一个数就暴力更新最小值:对于>√3e5的模数,由于最多被分成√3e5块,查询时对每一块找最小值,这用一些正常的DS显然可以做到log,但不太跑得过 ...

  8. Eclipse打不开,闪退

    自己编写了个程序,运行巨慢..无语,输出太多,后来冒出一个错误,不知什么原因啊,再后来Eclipse就打不开了,到workbench闪退... 百度后解决方案: 进入目录:workspace/.met ...

  9. 【Linux】线程池

    首先,线程池是什么?顾名思义,就是把一堆开辟好的线程放在一个池子里统一管理,就是一个线程池. 其次,为什么要用线程池,难道来一个请求给它申请一个线程,请求处理完了释放线程不行么?也行,但是如果创建线程 ...

  10. CF762E Radio Stations

    题目戳这里. 我还以为是KDtree呢,但是KDtree应该也可以做吧. 这是一道数据结构好题.考虑到由于\(K \le 10\),所以我们用两个大vector--\(Left,Right\),\(L ...