您的位置:首页 >> 编程开发 >> Android → Android桌面悬浮窗效果实现 仿360手机卫士悬浮窗效果

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

日期:2015-01-03 [ ] 评论: | 我要发表看法

大家好,今天给大家带来一个仿360手机卫士悬浮窗效果的教程,在开始之前请允许我说几句不相干的废话。

不知不觉我发现自己接触 Android已有近三个年头了,期间各种的成长少不了各位高手的帮助,总是有很多高手喜欢把自己的经验写在网上,供大家来学习,我也是从中受惠了很多, 在此我深表感谢。可是我发现我却从来没有将自己平时的一些心得拿出来与大家分享,共同学习,太没有奉献精神了。于是我痛定思痛,决定从今天开始写博客,希 望可以指点在我后面的开发者,更快地进入Android开发者的行列当中。

好了,废话就说这么多,下面开始进入今天的主题吧。

360手机卫士我相信大家都知道,好多人手机上都会装这一款软件,那么我们对它的一个桌面悬浮窗效果想必都不会陌生。请看下图:

                     

首先是一个小的悬浮窗显示的是当前使用了百分之多少的内存,点击一下小悬浮窗,就会弹出一个大的悬浮窗,可以一键加速。好,我们现在就来模拟实现一下类似的效果。

先 谈一下基本的实现原理,这种桌面悬浮窗的效果很类似与Widget,但是它比Widget要灵活的多。主要是通过WindowManager这个类来实现 的,调用这个类的addView方法用于添加一个悬浮窗,updateViewLayout方法用于更新悬浮窗的参数,removeView用于移除悬浮 窗。其中悬浮窗的参数有必要详细说明一下。

WindowManager.LayoutParams这个类用于提供悬浮窗所需的参数,其中有几个经常会用到的变量:

type值用于确定悬浮窗的类型,一般设为2002,表示在所有应用程序之上,但在状态栏之下。

flags值用于确定悬浮窗的行为,比如说不可聚焦,非模态对话框等等,属性非常多,大家可以查看文档。

gravity值用于确定悬浮窗的对齐方式,一般设为左上角对齐,这样当拖动悬浮窗的时候方便计算坐标。

x值用于确定悬浮窗的位置,如果要横向移动悬浮窗,就需要改变这个值。

y值用于确定悬浮窗的位置,如果要纵向移动悬浮窗,就需要改变这个值。

width值用于指定悬浮窗的宽度。

height值用于指定悬浮窗的高度。

创 建悬浮窗这种窗体需要向用户申请权限才可以的,因此还需要在AndroidManifest.xml中加入<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

原理介绍完了,下面我们开始用代码实现。首先在Eclipse中新建一个Android项目,项目名就叫做360FloatWindowDemo。然后写一下布局文件,布局文件非常简单,只有一个按钮,打开或新建activity_main.xml,加入如下代码:

双击代码全选
1
2
3
4
5
6
7
8
9
10
11
12
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    tools:context=".MainActivity"
    <Button
        android:id="@+id/start_float_window"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Start Float Window"
    </Button
</RelativeLayout>

然后再新建一个名为float_window_small.xml的布局文件,用于做为小悬浮窗的布局,在其中加入如下代码:

双击代码全选
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="UTF-8"?> 
<LinearLayout
    android:id="@+id/small_window_layout"
    android:layout_width="60dip"
    android:layout_height="25dip"
    android:background="@drawable/bg_small"
    
    <TextView
        android:id="@+id/percent"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:gravity="center"
        android:textColor="#ffffff"
        /> 
</LinearLayout>

再新建一个名为float_window_big.xml的布局文件,用于做为大悬浮窗的布局,在其中加入如下代码:

双击代码全选
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?xml version="1.0" encoding="UTF-8"?> 
<LinearLayout
    android:id="@+id/big_window_layout"
    android:layout_width="200dip"
    android:layout_height="100dip"
    android:background="@drawable/bg_big"
    android:orientation="vertical"
    
    <Button
        android:id="@+id/close"
        android:layout_width="100dip"
        android:layout_height="40dip"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="12dip"
        android:text="关闭悬浮窗"
        /> 
    <Button
        android:id="@+id/back"
        android:layout_width="100dip"
        android:layout_height="40dip"
        android:layout_gravity="center_horizontal"
        android:text="返回"
        /> 
</LinearLayout>

两个悬浮窗布局文件中用到的图片资源,大家可以随便找点图片来代替,同时我会给出源码,大家也可以从源码中取出。

然后打开或创建MainActivity,这是项目的主界面,在里面加入如下代码:

双击代码全选
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class MainActivity extends Activity { 
    @Override
    protected void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState); 
        setContentView(R.layout.activity_main); 
        Button startFloatWindow = (Button) findViewById(R.id.start_float_window); 
        startFloatWindow.setOnClickListener(new OnClickListener() { 
            @Override
            public void onClick(View arg0) { 
                Intent intent = new Intent(MainActivity.this, FloatWindowService.class); 
                startService(intent); 
                finish(); 
            
        }); 
    
}

这 里可以看到,MainActivity的代码非窗简单,就是对开启悬浮窗的按钮注册了一个点击事件,用于打开一个服务,然后关闭当前Activity。创 建悬浮窗的逻辑都交给服务去做了。好,现在我们来创建这个服务。新建一个名为FloatWindowService的类,这个类继承自Service,在 里面加入如下代码:

双击代码全选
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
public class FloatWindowService extends Service { 
       
    /**
     * 用于在线程中创建或移除悬浮窗。
     */
    private Handler handler = new Handler(); 
       
    /**
     * 定时器,定时进行检测当前应该创建还是移除悬浮窗。
     */
    private Timer timer; 
       
    @Override
    public IBinder onBind(Intent intent) { 
        return null
    
       
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) { 
        // 开启定时器,每隔0.5秒刷新一次 
        if (timer == null) { 
            timer = new Timer(); 
            timer.scheduleAtFixedRate(new RefreshTask(), 0, 500); 
        
        return super.onStartCommand(intent, flags, startId); 
    
       
    @Override
    public void onDestroy() { 
        super.onDestroy(); 
        // Service被终止的同时也停止定时器继续运行 
        timer.cancel(); 
        timer = null
    
       
    class RefreshTask extends TimerTask { 
       
        @Override
        public void run() { 
            // 当前界面是桌面,且没有悬浮窗显示,则创建悬浮窗。 
            if (isHome() && !MyWindowManager.isWindowShowing()) { 
                handler.post(new Runnable() { 
                    @Override
                    public void run() { 
                        MyWindowManager.createSmallWindow(getApplicationContext()); 
                    
                }); 
            
            // 当前界面不是桌面,且有悬浮窗显示,则移除悬浮窗。 
            else if (!isHome() && MyWindowManager.isWindowShowing()) { 
                handler.post(new Runnable() { 
                    @Override
                    public void run() { 
                        MyWindowManager.removeSmallWindow(getApplicationContext()); 
                        MyWindowManager.removeBigWindow(getApplicationContext()); 
                    
                }); 
            
            // 当前界面是桌面,且有悬浮窗显示,则更新内存数据。 
            else if (isHome() && MyWindowManager.isWindowShowing()) { 
                handler.post(new Runnable() { 
                    @Override
                    public void run() { 
                        MyWindowManager.updateUsedPercent(getApplicationContext()); 
                    
                }); 
            
        
       
    
       
    /**
     * 判断当前界面是否是桌面
     */
    private boolean isHome() { 
        ActivityManager mActivityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); 
        List<RunningTaskInfo> rti = mActivityManager.getRunningTasks(1); 
        return getHomes().contains(rti.get(0).topActivity.getPackageName()); 
    
       
    /**
     * 获得属于桌面的应用的应用包名称
     
     * @return 返回包含所有包名的字符串列表
     */
    private List<String> getHomes() { 
        List<String> names = new ArrayList<String>(); 
        PackageManager packageManager = this.getPackageManager(); 
        Intent intent = new Intent(Intent.ACTION_MAIN); 
        intent.addCategory(Intent.CATEGORY_HOME); 
        List<ResolveInfo> resolveInfo = packageManager.queryIntentActivities(intent, 
                PackageManager.MATCH_DEFAULT_ONLY); 
        for (ResolveInfo ri : resolveInfo) { 
            names.add(ri.activityInfo.packageName); 
        
        return names; 
    
}

FloatWindowService 的onStartCommand方法中开启了一个定时器,每隔500毫秒就会执行RefreshTask。在RefreshTask当中,要进行判断,如 果手机当前是在桌面的话,就应该显示悬浮窗,如果手机打开了某一个应用程序,就应该移除悬浮窗,如果手机在桌面的话,还应该更新内存使用百分比的数据。而 当FloatWindowService被销毁的时候,应该将定时器停止,否则它还会一直运行。

从上面的代码我们也可以看出,创建和移除悬浮窗,以及更新悬浮窗内的数据,都是由MyWindowManager这个类来管理的,比起直接把这些代 码写在Activity或Service当中,使用一个专门的工具类来管理要好的多。不过要想创建悬浮窗,还是先要把悬浮窗的View写出来。

新建一个名叫FloatWindowSmallView的类,继承自LinearLayout。新建一个名叫FloatWindowBigView的类,也继承自LinearLayout。

在FloatWindowSmallView中加入如下代码:

双击代码全选
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
Android   360   

阅读本文后您有什么感想? 已有 人给出评价!

  • 0 欢迎喜欢
  • 0 白痴
  • 0 拜托
  • 0 哇
  • 0 加油
  • 0 鄙视

热门评论

最新评论

发表评论 查看所有评论(0)

昵称:
表情: 高兴 可 汗 我不要 害羞 好 下下下 送花 屎 亲亲
字数: 0/500 (您的评论需要经过审核才能显示)
更多>>

视觉焦点

更多>>

相关软件

  • 360二代抢票神器 360抢票王软件 7.1.1.316 官方正式版[2015最新版] 一到春节在他乡工作的亲们就显得特别蛋痛了,一票难求似呼成了一个无解方程,多年来铁老大一直没有得到解决,每年的春运话题从没降温。现在我说说用 360二代抢票神器(360抢票王软件)的一些感受吧,我用360抢票王一年..
  • 360文件恢复器(独立版) 1.0.0.1003 真正的免费文件恢复器 360文件恢复器单文件独立版 360安全卫士想必电脑前的友友十有八九都安装了吧 这款360文件恢复器原本是在安全卫士的功能大全里的组件 有高手将其从安全卫士中剥离了出来 它可以帮助您快速从硬盘、U盘、SD卡等磁盘..
  • apk反编译工具(Android Multitool for Win7/XP)v3.0 绿色免费版 如果不能正常运行,请先安装压缩包中的VB运行环境。 该版本只支持Win XP/Win7系统,Win8系统请下载win8版本,下载地址:http://www.unabc.com/soft/11556.html 这是来自国外安卓论坛的一个反编译apk文件的工具..
  • apk反编译工具(Android Multitool for Win8) v3.0 绿色免费版 该版本仅支持win8系统,Win XP和Win7系统用户请下载:http://www.unabc.com/soft/11557.html 这是来自国外安卓论坛的一个反编译apk文件的工具,工具中集成了编译,编译,签名等选项,对于DIY安卓软件者是必备的工具..
  • Android ADT-22.6.2 最新版 Android ADT目前已经更新到22.6.2,有需要的不要错过。它是在WINDOWS系统平台上SDK环境下用来开发安卓软件所必不可少的本地安装插件。 安装方法: 打开Eclipse中的菜单 “Help”->”InstallNewS..
  • 360安全卫士2014 v9.6.0.2001 官方正式版 360安全卫士9.2 在9.1的基础上,加速球全面升级,新功能、新界面、新体验。网购先赔服务进一步优化。360安全卫士9.2正式版是卫士团队持续创新的结晶。我们倾听每 一位用户的意见,从中挖掘出大家的需求,开发出了诸多..
  • 安卓开发(Google Android SDK) 22.3 官方安装版 Google Android SDK Android是Google自己研发的手机平台操作系统,该平台基于开源软件Linux,由操作系统、中间件、用户界面和应用软件组成,号称是首个为移动终端打造的真正开放和完整的移动软件。 目的: Androi..
  • Android 桌面组件开发 如何在Android 自带的Home应用程序Launcher上进行桌面组件的开发,其中包括了快捷方式、实时文件夹以及桌面部件这三种组件的开发。通过学习将了解到桌面组件的详细开发流程,并且能从中掌握一些实用的桌面组件的开发..
  • 360随身WiFi网络名称修改器 1.0 最新版 如果你是台式机或者比较老的没有无线网卡的笔记本电脑,那么360随身wifi就是一个非常好的wifi热点工具,小巧简单方便,但是360随身 wifi不能自定义修改网络名称。插到电脑上,安装了官方驱动,在96%的时候等待了约2分..
  • Airbind将iTunes媒体库同步到Android上 0.76 官方版 在市场的激烈争夺中,苹果和Android互为敌人,但这并不妨碍用户同时使用双方的产品和服务。苹果打造了很多优秀产品,但使用过程中有很多限制。以 iTunes为例,AAC格式的音乐虽然取得了视听品质上的优势,但在通用性上..