展开菜单
首页 精品内容 本月促销 装机必备 Windows PDF教程 macOS软件 IOS软件 Android AI 专题
全部分类

当前位置:

首页 > 系统应用 > 10.7 WindowManager(窗口管理服务)

10.7 WindowManager(窗口管理服务)

本节引言: 本节给大家带来的Android给我们提供的系统服务中的——WindowManager(窗口管理服务), 它是显示View的最底层,Toast,Activity,Dialog的底层都用到了这个WindowManager, 他是全局的!该类的核心无非:调用addView,removeView

本文目录

    本节引言:

    本节给大家带来的Android给我们提供的系统服务中的——WindowManager(窗口管理服务), 它是显示View的最底层,Toast,Activity,Dialog的底层都用到了这个WindowManager, 他是全局的!该类的核心无非:调用addView,removeView,updateViewLayout这几个方法 来显示View以及通过WindowManager.LayoutParams这个API来设置相关的属性!

    本节我们就来探讨下这个WindowManager在实际开发中的一些应用实例吧~

    官方API文档:WindowManager

    1.WindowManager的一些概念:

    1)WindowManager介绍

    Android 提供了一套专门用来和窗口管理器打交道的 API。说白了,App 的界面本质上就是由一个个 Activity 组成的,而 Activity 里面承载的又是各种 View。于是,当需要把一个界面展示出来时,大家脑子里最先蹦出来的,通常就是 Activity,对吧?当然,也可能会想到 Dialog 或者 Toast。

    但是有些情况下,前面这三者可能满足不了我们的需求,比如我们仅仅是一个简单的显示 用Activity显得有点多余了,而Dialog又需要Context对象,Toast又不可以点击... 对于以上的情况我们可以利用WindowManager这个东东添加View到屏幕上, 或者从屏幕上移除View!他就是管理Android窗口机制的一个接口,显示View的最底层!

    2)如何获得WindowManager实例

    ①获得WindowManager对象:

    WindowManager wManager = getApplicationContext().getSystemService(Context. WINDOW_ SERVICE);

    ②获得WindowManager.LayoutParams对象,为后续操作做准备

    WindowManager.LayoutParams wmParams=new WindowManager.LayoutParams();

    2.WindowManager使用实例:

    实例1:获取屏幕宽高

    在Android 4.2前我们可以用下述方法获得屏幕宽高:

    public static int[] getScreenHW(Context context) {
        WindowManager manager = (WindowManager)context
        .getSystemService(Context.WINDOW_SERVICE);
        Display display = manager.getDefaultDisplay();
        int width = display.getWidth();
        int height = display.getHeight();
        int[] HW = new int[] { width, height };
        return HW;
    }

    而上述的方法在Android 4.2以后就过时了,我们可以用另一种方法获得屏幕宽高:

    public static int[] getScreenHW2(Context context) {
        WindowManager manager = (WindowManager) context.
        getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics dm = new DisplayMetrics();
        manager.getDefaultDisplay().getMetrics(dm);
        int width = dm.widthPixels;
        int height = dm.heightPixels;
        int[] HW = new int[] { width, height };
        return HW;
    }

    然后我们可以再另外写两个获取宽以及高的方法,这里以第二种获得屏幕宽高为例:

    public static int getScreenW(Context context) {
        return getScreenHW2(context)[0];
    }
    public static int getScreenH(Context context) {
        return getScreenHW2(context)[1];
    }

    当然,假如你不另外写一个工具类的话,你可以直接直接获取,比如:

    public class MainActivity extends AppCompatActivity {
        @Override
        protected void onCreate(Bundle sa vedInstanceState) {
            super.onCreate(sa vedInstanceState);
            setContentView(R.layout.activity_main);
            WindowManager wManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
            DisplayMetrics dm = new DisplayMetrics();
            wManager.getDefaultDisplay().getMetrics(dm);
            Toast.makeText(MainActivity.this, "当前手机的屏幕宽高:" + dm.widthPixels + "*" +
                    dm.heightPixels, Toast.LENGTH_SHORT).show();
        }
    }

    运行结果:

    实例2:设置窗口全屏显示

    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                    WindowManager.LayoutParams.FLAG_FULLSCREEN);
            getSupportActionBar().hide();

    运行结果:

    实例3:保持屏幕常亮

    public void setKeepScreenOn(Activity activity,boolean keepScreenOn)  
    {  
        if(keepScreenOn)  
        {  
            activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);  
        }else{  
            activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);  
        }  
    } 

    实例4:简单悬浮框的实现

    运行效果图:

    实现代码:

    首先我们需要一个后台的Service在后台等待我们的操作,比如完成悬浮框的绘制移除等, 于是乎我们定义一个Service:MyService.ja va: 我们需要一个创建悬浮框View的一个方法:

    private void createWindowView() {
        btnView = new Button(getApplicationContext());
        btnView.setBackgroundResource(R.mipmap.ic_launcher);
        windowManager = (WindowManager) getApplicationContext()
                .getSystemService(Context.WINDOW_SERVICE);
        params = new WindowManager.LayoutParams();
    // 设置Window Type
        params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
        // 设置悬浮框不可触摸
        params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
        // 悬浮窗不可触摸,不接受任何事件,同时不影响后面的事件响应
        params.format = PixelFormat.RGBA_8888;
        // 设置悬浮框的宽高
        params.width = 200;
        params.height = 200;
        params.gra vity = Gra vity.LEFT;
        params.x = 200;
        params.y = 000;
        // 设置悬浮框的Touch监听
        btnView.setOnTouchListener(new View.OnTouchListener() {
            //保存悬浮框最后位置的变量
            int lastX, lastY;
            int paramX, paramY;
    @Override
            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;
                        // 更新悬浮窗位置
                        windowManager.updateViewLayout(btnView, params);
                        break;
                }
                return true;
            }
        });
        windowManager.addView(btnView, params);
        isAdded = true;
    }

    然后我们只需在OnCreate( )方法中调用上述的createWindowView( )方法即可启动加载悬浮框, 但是我们发现了一点:这玩意貌似关不掉啊,卧槽,好吧,接下来我们就要分析下需求了!

    当处于手机的普通界面,即桌面的时候,这玩意才显示,而当我们启动其他App时,这个悬浮框应该 消失不见,当我们推出app又回到桌面,这个悬浮框又要重新出现!

    那么我们首先需要判断App是否位于桌面,于是乎我们再加上下述代码:

    /**  
     * 判断当前界面是否是桌面  
     */    
    public boolean isHome(){    
        if(mActivityManager == null) {  
            mActivityManager = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);    
        }  
        List rti = mActivityManager.getRunningTasks(1);    
        return homeList.contains(rti.get(0).topActivity.getPackageName());    
    }  
    /**  
     * 获得属于桌面的应用的应用包名称  
     * @return 返回包含所有包名的字符串列表  
     */  
    private List getHomes() {  
        List names = new ArrayList();    
        PackageManager packageManager = this.getPackageManager();    
        // 属性    
        Intent intent = new Intent(Intent.ACTION_MAIN);    
        intent.addCategory(Intent.CATEGORY_HOME);    
        List resolveInfo = packageManager.queryIntentActivities(intent,    
                PackageManager.MATCH_DEFAULT_ONLY);    
        for(ResolveInfo ri : resolveInfo) {    
            names.add(ri.activityInfo.packageName);    
        }  
        return names;    
    }  

    好了,接下来我们需要每隔一段时间来进行一系列的判断,比如:是否在桌面,是否已加载悬浮框, 否则加载;否则,如果加载了,就将这个悬浮框移除!这里我们使用handler~,因为不能在子线程直接 更新UI,所以,你懂的,所以我们自己写一个handler来完成上述的操作:

    //定义一个更新界面的Handler  
    private Handler mHandler = new Handler() {  
        @Override  
        public void handleMessage(Message msg) {  
            switch(msg.what) {  
            case HANDLE_CHECK_ACTIVITY:  
                if(isHome()) {  
                    if(!isAdded) {  
                        windowManager.addView(btnView, params);  
                        isAdded = true;  
                    new Thread(new Runnable() {  
                        public void run() {  
                            for(int i=0;i<10;i++){  
                                try {  
                                    Thread.sleep(1000);  
                                } catch (InterruptedException e) {e.printStackTrace();}  
                                Message m = new Message();  
                                m.what=2;  
                                mHandler.sendMessage(m);  
                            }  
                        }  
                    }).start();}  
                } else {  
                    if(isAdded) {  
                        windowManager.removeView(btnView);  
                        isAdded = false;  
                    }  
                }  
                mHandler.sendEmptyMessageDelayed(HANDLE_CHECK_ACTIVITY, 0);  
                break;  
            }  
        }  
    }; 

    最后要做的一件事,就是重写Service的onStartCommand( )方法了,就是做判断,取出Intent中的 数据,判断是需要添加悬浮框,还是要移除悬浮框!

    @Override  
    public int onStartCommand(Intent intent, int flags, int startId) {  
        int operation = intent.getIntExtra(OPERATION, OPERATION_SHOW);  
        switch(operation) {  
        case OPERATION_SHOW:  
            mHandler.removeMessages(HANDLE_CHECK_ACTIVITY);  
            mHandler.sendEmptyMessage(HANDLE_CHECK_ACTIVITY);  
            break;  
        case OPERATION_HIDE:  
            mHandler.removeMessages(HANDLE_CHECK_ACTIVITY);  
            break;  
        }  
        return super.onStartCommand(intent, flags, startId);  
    } 

    好的,至此,主要的工作就完成了,接下来就是一些零碎的东西了,用一个Activity 来启动这个Service:MainActivity.ja va:

    public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private Button btn_on;
    @Override
        protected void onCreate(Bundle sa vedInstanceState) {
            super.onCreate(sa vedInstanceState);
            setContentView(R.layout.activity_main);
            bindViews();
        }
    private void bindViews() {
            btn_on = (Button) findViewById(R.id.btn_on);
            btn_on.setOnClickListener(this);
        }
    @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.btn_on:
                    Intent mIntent = new Intent(MainActivity.this, MainService.class);
                    mIntent.putExtra(MainService.OPERATION, MainService.OPERATION_SHOW);
                    startService(mIntent);
                    Toast.makeText(MainActivity.this, "悬浮框已开启~", Toast.LENGTH_SHORT).show();
                    break;
            }
        }
    }

    接着AndroidManifest.xml加上权限,以及为MainService进行注册:

    
    
    

    好了,逻辑还是比较容易理解的~大家自己再看看吧~

    3.文献扩展:

    从第四个实例中,你可能留意到了:WindowManager.LayoutParams这个东东,这是一个标记, 比如全屏~时间关系就不一一列举出来了,可以到官网或者下述链接中查看:

    官方文档:WindowManager.LayoutParams

    Android系统服务-WindowManager

    另外,假如你对上述的悬浮框有兴趣,想更深入的研究,可见郭大叔(郭霖)的博客:

    Android桌面悬浮窗效果实现,仿360手机卫士悬浮窗效果

    Android桌面悬浮窗进阶,QQ手机管家小火箭效果实现

    4.本节代码示例下载:

    WindowManagerDemo2.zip

    本节小结:

    这一节主要梳理了 Android 系统服务里的 WindowManager。前面三个示例在实际开发里会更常用一些,尤其第一个,比较适合顺手封装成一个工具类,毕竟获取屏幕宽高这类需求,基本隔三差五就会碰到。至于悬浮框那部分,能看明白当然更好;一时没完全吃透,其实也不用太有压力,毕竟在日常开发场景里,真正需要单独去做悬浮框的情况并不算多。好了,这一节先讲到这里。

    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
    作者最新文章
    系统应用 浏览器
    相关文章 更多
    精品专题 更多
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    PDF教程

    正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

    macOS软件

    正软商城macOS软件专区,精选适用于Mac电脑的办公、设计、影音、效率、开发和系统工具,提供软件功能介绍、macOS兼容版本、正版授权及购买下载服务。

    IOS软件

    正软商城iOS软件专区,精选适用于iPhone和iPad的办公、学习、影音、设计、效率及AI应用,提供功能介绍、适用设备、系统要求和正版获取方式等信息。

    AI

    正软商城AI软件专区,汇集AI写作、AI绘画、AI视频、AI办公、AI编程、AI翻译、智能客服和数据分析等人工智能工具,提供功能介绍、适用平台、收费方式及正版购买信息。

    Mac软件 更多
    Aperty macOS版
    Aperty macOS版

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    火山引擎 网页版
    火山引擎 网页版

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    立刻MV 网页版
    立刻MV 网页版

    立刻MV 面向音乐人、内容创作者和品牌团队,帮助用户低成本完成歌曲 MV、歌词视频、AI 分镜、图生视频与最终合成。

    蛙蛙写作 网页版
    蛙蛙写作 网页版

    蛙蛙写作 AI 创作工具,覆盖小说、剧本、文案,一键生成文稿,打通文字转视频全流程,高效解决创作难题。

    讯飞智作 网页版
    讯飞智作 网页版

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    超级简历WonderCV 网页版
    超级简历WonderCV 网页版

    超级简历WonderCV是面向应届生和AI小白的智能求职平台,覆盖简历、面试与职业规划。

    音述AI 网页版
    音述AI 网页版

    音述AI,是一个以“用声音述说故事”为核心的 AI 音乐创作与声音分享社区。

    AionClaw macOS版
    AionClaw macOS版

    AionClaw 是可在桌面端运行的任务型 AI 助手,通过数字专家与技能市场组合办公、创作、数据和开发能力。

    Loomy macOS版
    Loomy macOS版

    Loomy 是科大讯飞推出的桌面 AI 助手,可通过对话、任务与工作目录协助处理办公、内容创作和资料整理。

    AirBuddy 3 macOS版
    AirBuddy 3 macOS版

    AirBuddy 3 是面向 macOS 的蓝牙外设增强工具,可集中查看 AirPods、Beats 与苹果设备电量,提供快速连接、播放控制、电量提醒、桌面小组件和多台 Mac 外设接力等功能。

    AirServer macOS版
    AirServer macOS版

    AirServer macOS版可把 Mac 转换为无线投屏接收端,通过 AirPlay 或 Google Cast 接收手机、平板和电脑画面,并支持多设备同时连接、高清镜像及会话录制,适合家庭娱乐、课堂教学、会议演示和应用展示。

    AnyDesk macOS版
    AnyDesk macOS版

    AnyDesk macOS版是一款适用于远程办公、设备维护和客户支持的远程桌面工具,可连接并操作异地计算机,支持文件传输、无人值守访问、会话权限控制及跨平台协作。

    WINDOWS 更多
    讯飞绘文 网页版
    讯飞绘文 网页版

    讯飞绘文网页版是科大讯飞推出的AI图文创作与内容运营工具,覆盖热点选题、文章生成、稿件校对、智能配图、排版发布和数据复盘等环节,适合自媒体创作者及内容团队在线使用。

    Maya(Autodesk Maya) Windows版
    Maya(Autodesk Maya) Windows版

    Autodesk Maya 是面向影视、电视、动画和游戏行业的专业三维制作软件,集多边形与 NURBS 建模、角色绑定、关键帧和动作捕捉动画、Bifrost 特效模拟、材质开发及 Arnold 渲染于一体,

    Aperty Windows版
    Aperty Windows版

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    火山引擎 网页版
    火山引擎 网页版

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    立刻MV 网页版
    立刻MV 网页版

    立刻MV 面向音乐人、内容创作者和品牌团队,帮助用户低成本完成歌曲 MV、歌词视频、AI 分镜、图生视频与最终合成。

    蛙蛙写作 网页版
    蛙蛙写作 网页版

    蛙蛙写作 AI 创作工具,覆盖小说、剧本、文案,一键生成文稿,打通文字转视频全流程,高效解决创作难题。

    讯飞智作 网页版
    讯飞智作 网页版

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    超级简历WonderCV 网页版
    超级简历WonderCV 网页版

    超级简历WonderCV是面向应届生和AI小白的智能求职平台,覆盖简历、面试与职业规划。

    音述AI 网页版
    音述AI 网页版

    音述AI,是一个以“用声音述说故事”为核心的 AI 音乐创作与声音分享社区。

    AionClaw Windows版
    AionClaw Windows版

    AionClaw 是可在桌面端运行的任务型 AI 助手,通过数字专家与技能市场组合办公、创作、数据和开发能力。

    Loomy Windows版
    Loomy Windows版

    Loomy 是科大讯飞推出的桌面 AI 助手,可通过对话、任务与工作目录协助处理办公、内容创作和资料整理。

    AirServer Windows版
    AirServer Windows版

    AirServer Windows版可把电脑变成AirPlay、Google Cast和Miracast无线投屏接收端,适合会议演示、课堂教学及家庭大屏分享。发送设备通常无需另装客户端,并可同时接收和智能排列多个镜像会话。