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


来看下在Android设备上的效果


程序的目录结构如下图


创建Activity后启动Service就关闭

package com.example.floatwnd;import android.app.Activity;import android.content.Intent;import android.os.Bundle;import com.example.floatwnd.service.FloatService;public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);Intent intent = new Intent(MainActivity.this, FloatService.class);startService(intent);finish();}}

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

package com.example.floatwnd.service;import android.app.Service;import android.content.Intent;import android.graphics.PixelFormat;import android.graphics.Rect;import android.os.Handler;import android.os.IBinder;import android.os.Looper;import android.os.Message;import android.view.Gravity;import android.view.LayoutInflater;import android.view.MotionEvent;import android.view.View;import android.view.View.OnClickListener;import android.view.View.OnTouchListener;import android.view.WindowManager;import android.view.WindowManager.LayoutParams;import android.widget.Button;import android.widget.TextView;import android.widget.Toast;import com.example.floatwnd.R;import com.example.floatwnd.utils.SysInfoUtils;/** * 悬浮窗Service 该服务会在后台一直运行一个悬浮的透明的窗体 *  * @author Administrator *  */public class FloatService extends Service {private static final int UPDATE_PIC = 0x100;private int statusBarHeight;// 状态栏高度private View view;// 透明窗体private TextView text = null;private Button hideBtn = null;private Button updateBtn = null;private HandlerUI handler = null;private Thread updateThread = null;private boolean viewAdded = false;// 透明窗体是否已经显示private boolean viewHide = false; // 窗口隐藏private WindowManager windowManager;private WindowManager.LayoutParams layoutParams;@Overridepublic IBinder onBind(Intent arg0) {// TODO Auto-generated method stubreturn null;}@Overridepublic void onCreate() {// TODO Auto-generated method stubsuper.onCreate();createFloatView();}@Overridepublic void onStart(Intent intent, int startId) {// TODO Auto-generated method stubsuper.onStart(intent, startId);System.out.println("------------------onStart");viewHide = false;refresh();}@Overridepublic void onDestroy() {// TODO Auto-generated method stubsuper.onDestroy();removeView();}/** * 关闭悬浮窗 */public void removeView() {if (viewAdded) {windowManager.removeView(view);viewAdded = false;}}private void createFloatView() {handler = new HandlerUI();UpdateUI update = new UpdateUI();updateThread = new Thread(update);updateThread.start(); // 开户线程view = LayoutInflater.from(this).inflate(R.layout.main, null);text = (TextView) view.findViewById(R.id.usage);hideBtn = (Button) view.findViewById(R.id.hideBtn);updateBtn = (Button) view.findViewById(R.id.updateBtn);windowManager = (WindowManager) this.getSystemService(WINDOW_SERVICE);/* * LayoutParams.TYPE_SYSTEM_ERROR:保证该悬浮窗所有View的最上层 * LayoutParams.FLAG_NOT_FOCUSABLE:该浮动窗不会获得焦点,但可以获得拖动 * PixelFormat.TRANSPARENT:悬浮窗透明 */layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT, LayoutParams.TYPE_SYSTEM_ERROR,LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSPARENT);// layoutParams.gravity = Gravity.RIGHT|Gravity.BOTTOM; //悬浮窗开始在右下角显示layoutParams.gravity = Gravity.LEFT | Gravity.TOP;/** * 监听窗体移动事件 */view.setOnTouchListener(new OnTouchListener() {float[] temp = new float[] { 0f, 0f };public boolean onTouch(View v, MotionEvent event) {layoutParams.gravity = Gravity.LEFT | Gravity.TOP;int eventaction = event.getAction();switch (eventaction) {case MotionEvent.ACTION_DOWN: // 按下事件,记录按下时手指在悬浮窗的XY坐标值temp[0] = event.getX();temp[1] = event.getY();break;case MotionEvent.ACTION_MOVE:refreshView((int) (event.getRawX() - temp[0]),(int) (event.getRawY() - temp[1]));break;}return true;}});hideBtn.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {// TODO Auto-generated method stubviewHide = true;removeView();System.out.println("----------hideBtn");}});updateBtn.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {// TODO Auto-generated method stubToast.makeText(getApplicationContext(), "you click UpdateBtn",Toast.LENGTH_SHORT).show();System.out.println("mom "+ SysInfoUtils.getUsedPercentValue(getApplicationContext()));}});}/** * 刷新悬浮窗 *  * @param x *            拖动后的X轴坐标 * @param y *            拖动后的Y轴坐标 */private void refreshView(int x, int y) {// 状态栏高度不能立即取,不然得到的值是0if (statusBarHeight == 0) {View rootView = view.getRootView();Rect r = new Rect();rootView.getWindowVisibleDisplayFrame(r);statusBarHeight = r.top;}layoutParams.x = x;// y轴减去状态栏的高度,因为状态栏不是用户可以绘制的区域,不然拖动的时候会有跳动layoutParams.y = y - statusBarHeight;// STATUS_HEIGHT;refresh();}/** * 添加悬浮窗或者更新悬浮窗 如果悬浮窗还没添加则添加 如果已经添加则更新其位置 */private void refresh() {// 如果已经添加了就只更新viewif (viewAdded) {windowManager.updateViewLayout(view, layoutParams);} else {windowManager.addView(view, layoutParams);viewAdded = true;}}/** * 接受消息和处理消息 *  * @author Administrator *  */class HandlerUI extends Handler {public HandlerUI() {}public HandlerUI(Looper looper) {super(looper);}/** * 接收消息 */@Overridepublic void handleMessage(Message msg) {// TODO Auto-generated method stub// 根据收到的消息分别处理if (msg.what == UPDATE_PIC) {text.setText(SysInfoUtils.getUsedPercentValue(getApplicationContext())+ "  t = "+ SysInfoUtils.getTotalMemory(getApplicationContext())+ "  a = "+ SysInfoUtils.getAvailableMemoryString(getApplicationContext()));if (!viewHide)refresh();} else {super.handleMessage(msg);}}}/** * 更新悬浮窗的信息 *  * @author Administrator *  */class UpdateUI implements Runnable {@Overridepublic void run() {// TODO Auto-generated method stub// 如果没有中断就一直运行while (!Thread.currentThread().isInterrupted()) {Message msg = handler.obtainMessage();msg.what = UPDATE_PIC; // 设置消息标识handler.sendMessage(msg);// 休眠1stry {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}}

为悬浮窗创建布局文件

<?xml version="1.0" encoding="UTF-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="wrap_content"    android:layout_height="wrap_content"    android:background="@drawable/background" >    <!-- android:updatePeriodMillis="10000"> -->    <TextView        android:id="@+id/flowspeed"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_alignParentTop="true"        android:layout_centerInParent="true"        android:text="@string/float_text"        android:textColor="#000000" />    <Button        android:id="@+id/hideBtn"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_below="@id/flowspeed"        android:layout_centerInParent="true"        android:layout_marginTop="15dp"        android:background="@drawable/hide"        android:contentDescription="@string/hide"        android:text="@string/hide" />    <Button        android:id="@+id/updateBtn"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_below="@id/hideBtn"        android:layout_centerInParent="true"        android:background="@drawable/update"        android:contentDescription="@string/update"        android:paddingTop="15dp"        android:text="@string/update" />    <TextView        android:id="@+id/usage"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_below="@id/updateBtn"        android:layout_centerInParent="true"        android:paddingTop="15dp"        android:text="@string/float_text"        android:textColor="#000000" /></RelativeLayout>

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

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


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

点击打开链接







更多相关文章

  1. Android常用控件之悬浮窗
  2. android > layout > SeekBar (拉动条)
  3. Android(安卓)图片拖动 放大
  4. Android的window类的常用方法
  5. Android之SeekBar
  6. 进度条及拖动条背景颜色设置(progressDrawable)
  7. Android(安卓)使用WindowManager打造通用悬浮菜单,兼容Android(安
  8. [Android(安卓)Studio] Android(安卓)Studio如何提示函数用法
  9. 让Android自带的Gallery实现多点缩放,拖动和边界回弹效果,效果流畅

随机推荐

  1. Android测试用例执行线程和UI线程
  2. Android开发时提示Your project contains
  3. android文件系统
  4. android input及简单am命令
  5. Android 网络框架学习之Retrofit
  6. Android(安卓)SSL BKS证书的生成过程
  7. Android(安卓)where 长度限制
  8. 使用大量checkbox的时候可能出现的小问题
  9. [cocos2d-x 学习] Windows下环境配置
  10. Android访问中央气象台的天气预报API得到