现在的位置: 首页 > 综合 > 正文

Android常用控件之悬浮窗

2018年04月10日 ⁄ 综合 ⁄ 共 10381字 ⁄ 字号 评论关闭

  悬浮窗可以显示在所有应用程序之上,不管在PC机还是Android设备上都有这个,最常见的是360的“加速球”

来看下在Android设备上的效果

程序的目录结构如下图

创建Activity后启动Service就关闭

[java] view
plain
copy在CODE上查看代码片派生到我的代码片

  1. package com.example.floatwnd;  
  2.   
  3. import android.app.Activity;  
  4. import android.content.Intent;  
  5. import android.os.Bundle;  
  6.   
  7. import com.example.floatwnd.service.FloatService;  
  8.   
  9. public class MainActivity extends Activity {  
  10.   
  11.     @Override  
  12.     protected void onCreate(Bundle savedInstanceState) {  
  13.         super.onCreate(savedInstanceState);  
  14.         Intent intent = new Intent(MainActivity.this, FloatService.class);  
  15.         startService(intent);  
  16.         finish();  
  17.     }  
  18. }  


悬浮窗的主要工作放在Service上处理

[java] view
plain
copy在CODE上查看代码片派生到我的代码片

  1. package com.example.floatwnd.service;  
  2.   
  3. import android.app.Service;  
  4. import android.content.Intent;  
  5. import android.graphics.PixelFormat;  
  6. import android.graphics.Rect;  
  7. import android.os.Handler;  
  8. import android.os.IBinder;  
  9. import android.os.Looper;  
  10. import android.os.Message;  
  11. import android.view.Gravity;  
  12. import android.view.LayoutInflater;  
  13. import android.view.MotionEvent;  
  14. import android.view.View;  
  15. import android.view.View.OnClickListener;  
  16. import android.view.View.OnTouchListener;  
  17. import android.view.WindowManager;  
  18. import android.view.WindowManager.LayoutParams;  
  19. import android.widget.Button;  
  20. import android.widget.TextView;  
  21. import android.widget.Toast;  
  22.   
  23. import com.example.floatwnd.R;  
  24. import com.example.floatwnd.utils.SysInfoUtils;  
  25.   
  26. /** 
  27.  * 悬浮窗Service 该服务会在后台一直运行一个悬浮的透明的窗体 
  28.  *  
  29.  * @author Administrator 
  30.  *  
  31.  */  
  32. public class FloatService extends Service {  
  33.   
  34.     private static final int UPDATE_PIC = 0x100;  
  35.     private int statusBarHeight;// 状态栏高度  
  36.     private View view;// 透明窗体  
  37.     private TextView text = null;  
  38.     private Button hideBtn = null;  
  39.     private Button updateBtn = null;  
  40.     private HandlerUI handler = null;  
  41.     private Thread updateThread = null;  
  42.     private boolean viewAdded = false;// 透明窗体是否已经显示  
  43.     private boolean viewHide = false// 窗口隐藏  
  44.     private WindowManager windowManager;  
  45.     private WindowManager.LayoutParams layoutParams;  
  46.   
  47.     @Override  
  48.     public IBinder onBind(Intent arg0) {  
  49.         // TODO Auto-generated method stub  
  50.         return null;  
  51.     }  
  52.   
  53.     @Override  
  54.     public void onCreate() {  
  55.         // TODO Auto-generated method stub  
  56.         super.onCreate();  
  57.         createFloatView();  
  58.     }  
  59.   
  60.     @Override  
  61.     public void onStart(Intent intent, int startId) {  
  62.         // TODO Auto-generated method stub  
  63.         super.onStart(intent, startId);  
  64.         System.out.println("------------------onStart");  
  65.         viewHide = false;  
  66.         refresh();  
  67.     }  
  68.   
  69.     @Override  
  70.     public void onDestroy() {  
  71.         // TODO Auto-generated method stub  
  72.         super.onDestroy();  
  73.         removeView();  
  74.     }  
  75.   
  76.     /** 
  77.      * 关闭悬浮窗 
  78.      */  
  79.     public void removeView() {  
  80.         if (viewAdded) {  
  81.             windowManager.removeView(view);  
  82.             viewAdded = false;  
  83.         }  
  84.     }  
  85.   
  86.     private void createFloatView() {  
  87.         handler = new HandlerUI();  
  88.         UpdateUI update = new UpdateUI();  
  89.         updateThread = new Thread(update);  
  90.         updateThread.start(); // 开户线程  
  91.   
  92.         view = LayoutInflater.from(this).inflate(R.layout.main, null);  
  93.         text = (TextView) view.findViewById(R.id.usage);  
  94.         hideBtn = (Button) view.findViewById(R.id.hideBtn);  
  95.         updateBtn = (Button) view.findViewById(R.id.updateBtn);  
  96.         windowManager = (WindowManager) this.getSystemService(WINDOW_SERVICE);  
  97.         /* 
  98.          * LayoutParams.TYPE_SYSTEM_ERROR:保证该悬浮窗所有View的最上层 
  99.          * LayoutParams.FLAG_NOT_FOCUSABLE:该浮动窗不会获得焦点,但可以获得拖动 
  100.          * PixelFormat.TRANSPARENT:悬浮窗透明 
  101.          */  
  102.         layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT,  
  103.                 LayoutParams.WRAP_CONTENT, LayoutParams.TYPE_SYSTEM_ERROR,  
  104.                 LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSPARENT);  
  105.         // layoutParams.gravity = Gravity.RIGHT|Gravity.BOTTOM; //悬浮窗开始在右下角显示  
  106.         layoutParams.gravity = Gravity.LEFT | Gravity.TOP;  
  107.   
  108.         /** 
  109.          * 监听窗体移动事件 
  110.          */  
  111.         view.setOnTouchListener(new OnTouchListener() {  
  112.             float[] temp = new float[] { 0f, 0f };  
  113.   
  114.             public boolean onTouch(View v, MotionEvent event) {  
  115.                 layoutParams.gravity = Gravity.LEFT | Gravity.TOP;  
  116.                 int eventaction = event.getAction();  
  117.                 switch (eventaction) {  
  118.                 case MotionEvent.ACTION_DOWN: // 按下事件,记录按下时手指在悬浮窗的XY坐标值  
  119.                     temp[0] = event.getX();  
  120.                     temp[1] = event.getY();  
  121.                     break;  
  122.   
  123.                 case MotionEvent.ACTION_MOVE:  
  124.                     refreshView((int) (event.getRawX() - temp[0]),  
  125.                             (int) (event.getRawY() - temp[1]));  
  126.                     break;  
  127.   
  128.                 }  
  129.                 return true;  
  130.             }  
  131.         });  
  132.   
  133.         hideBtn.setOnClickListener(new OnClickListener() {  
  134.   
  135.             @Override  
  136.             public void onClick(View v) {  
  137.                 // TODO Auto-generated method stub  
  138.                 viewHide = true;  
  139.                 removeView();  
  140.                 System.out.println("----------hideBtn");  
  141.             }  
  142.         });  
  143.   
  144.         updateBtn.setOnClickListener(new OnClickListener() {  
  145.   
  146.             @Override  
  147.             public void onClick(View v) {  
  148.                 // TODO Auto-generated method stub  
  149.                 Toast.makeText(getApplicationContext(), "you click UpdateBtn",  
  150.                         Toast.LENGTH_SHORT).show();  
  151.                 System.out.println("mom "  
  152.                         + SysInfoUtils  
  153.                                 .getUsedPercentValue(getApplicationContext()));  
  154.             }  
  155.         });  
  156.     }  
  157.   
  158.     /** 
  159.      * 刷新悬浮窗 
  160.      *  
  161.      * @param x 
  162.      *            拖动后的X轴坐标 
  163.      * @param y 
  164.      *            拖动后的Y轴坐标 
  165.      */  
  166.     private void refreshView(int x, int y) {  
  167.         // 状态栏高度不能立即取,不然得到的值是0  
  168.         if (statusBarHeight == 0) {  
  169.             View rootView = view.getRootView();  
  170.             Rect r = new Rect();  
  171.             rootView.getWindowVisibleDisplayFrame(r);  
  172.             statusBarHeight = r.top;  
  173.         }  
  174.   
  175.         layoutParams.x = x;  
  176.         // y轴减去状态栏的高度,因为状态栏不是用户可以绘制的区域,不然拖动的时候会有跳动  
  177.         layoutParams.y = y - statusBarHeight;// STATUS_HEIGHT;  
  178.         refresh();  
  179.     }  
  180.   
  181.     /** 
  182.      * 添加悬浮窗或者更新悬浮窗 如果悬浮窗还没添加则添加 如果已经添加则更新其位置 
  183.      */  
  184.     private void refresh() {  
  185.         // 如果已经添加了就只更新view  
  186.         if (viewAdded) {  
  187.             windowManager.updateViewLayout(view, layoutParams);  
  188.         } else {  
  189.             windowManager.addView(view, layoutParams);  
  190.             viewAdded = true;  
  191.         }  
  192.     }  
  193.   
  194.     /** 
  195.      * 接受消息和处理消息 
  196.      *  
  197.      * @author Administrator 
  198.      *  
  199.      */  
  200.     class HandlerUI extends Handler {  
  201.         public HandlerUI() {  
  202.   
  203.         }  
  204.   
  205.         public HandlerUI(Looper looper) {  
  206.             super(looper);  
  207.         }  
  208.   
  209.         /** 
  210.          * 接收消息 
  211.          */  
  212.         @Override  
  213.         public void handleMessage(Message msg) {  
  214.             // TODO Auto-generated method stub  
  215.             // 根据收到的消息分别处理  
  216.             if (msg.what == UPDATE_PIC) {  
  217.                 text.setText(SysInfoUtils  
  218.                         .getUsedPercentValue(getApplicationContext())  
  219.                         + "  t = "  
  220.                         + SysInfoUtils.getTotalMemory(getApplicationContext())  
  221.                         + "  a = "  
  222.                         + SysInfoUtils  
  223.                                 .getAvailableMemoryString(getApplicationContext()));  
  224.                 if (!viewHide)  
  225.                     refresh();  
  226.             } else {  
  227.                 super.handleMessage(msg);  
  228.             }  
  229.   
  230.         }  
  231.   
  232.     }  
  233.   
  234.     /** 
  235.      * 更新悬浮窗的信息 
  236.      *  
  237.      * @author Administrator 
  238.      *  
  239.      */  
  240.     class UpdateUI implements Runnable {  
  241.   
  242.         @Override  
  243.         public void run() {  
  244.             // TODO Auto-generated method stub  
  245.             // 如果没有中断就一直运行  
  246.             while (!Thread.currentThread().isInterrupted()) {  
  247.                 Message msg = handler.obtainMessage();  
  248.                 msg.what = UPDATE_PIC; // 设置消息标识  
  249.                 handler.sendMessage(msg);  
  250.                 // 休眠1s  
  251.                 try {  
  252.                     Thread.sleep(1000);  
  253.                 } catch (InterruptedException e) {  
  254.                     // TODO Auto-generated catch block  
  255.                     e.printStackTrace();  
  256.                 }  
  257.             }  
  258.         }  
  259.     }  
  260. }  


为悬浮窗创建布局文件

[html] view
plain
copy在CODE上查看代码片派生到我的代码片

  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="wrap_content"  
  4.     android:layout_height="wrap_content"  
  5.     android:background="@drawable/background" >  
  6.   
  7.     <!-- android:updatePeriodMillis="10000"> -->  
  8.   
  9.     <TextView  
  10.         android:id="@+id/flowspeed"  
  11.         android:layout_width="wrap_content"  
  12.         android:layout_height="wrap_content"  
  13.         android:layout_alignParentTop="true"  
  14.         android:layout_centerInParent="true"  
  15.         android:text="@string/float_text"  
  16.         android:textColor="#000000" />  
  17.   
  18.     <Button  
  19.         android:id="@+id/hideBtn"  
  20.         android:layout_width="wrap_content"  
  21.         android:layout_height="wrap_content"  
  22.         android:layout_below="@id/flowspeed"  
  23.         android:layout_centerInParent="true"  
  24.         android:layout_marginTop="15dp"  
  25.         android:background="@drawable/hide"  
  26.         android:contentDescription="@string/hide"  
  27.         android:text="@string/hide" />  
  28.   
  29.     <Button  
  30.         android:id="@+id/updateBtn"  
  31.         android:layout_width="wrap_content"  
  32.         android:layout_height="wrap_content"  
  33.         android:layout_below="@id/hideBtn"  
  34.         android:layout_centerInParent="true"  
  35.         android:background="@drawable/update"  
  36.         android:contentDescription="@string/update"  
  37.         android:paddingTop="15dp"  
  38.         android:text="@string/update" />  
  39.   
  40.     <TextView  
  41.         android:id="@+id/usage"  
  42.         android:layout_width="wrap_content"  
  43.         android:layout_height="wrap_content"  
  44.         android:layout_below="@id/updateBtn"  
  45.         android:layout_centerInParent="true"  
  46.         android:paddingTop="15dp"  
  47.         android:text="@string/float_text"  
  48.         android:textColor="#000000" />  
  49.   
  50. </RelativeLayout>  


悬浮窗上的控件就跟Activity上一样使用

悬浮窗上显示的一些内存信息,通过工具类:SysInfoUtils.java来读取

完整的Demo可以从以下地址下载:

点击打开链接

抱歉!评论已关闭.