突然对悬浮窗体感兴趣,查资料做了个小Demo,效果是点击按钮后,关闭当前Activity,显示悬浮窗口,窗口可以拖动,双击后消失。效果图如下:

它的使用原理很简单,就是借用了WindowManager这个管理类来实现的。
1.首先在AndroidManifest.xml中添加使用权限:

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

2.悬浮窗口布局实现

public class DesktopLayout extends LinearLayout {

    public DesktopLayout(Context context) {
super(context);
setOrientation(LinearLayout.VERTICAL);// 水平排列 //设置宽高
this.setLayoutParams( new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT)); View view = LayoutInflater.from(context).inflate(
R.layout.desklayout, null);
this.addView(view);
}

3.在activity中让它显示出来。

        // 取得系统窗体
mWindowManager = (WindowManager) getApplicationContext()
.getSystemService("window"); // 窗体的布局样式
mLayout = new WindowManager.LayoutParams(); // 设置窗体显示类型——TYPE_SYSTEM_ALERT(系统提示)
mLayout.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; // 设置窗体焦点及触摸:
// FLAG_NOT_FOCUSABLE(不能获得按键输入焦点)
mLayout.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; // 设置显示的模式
mLayout.format = PixelFormat.RGBA_8888; // 设置对齐的方法
mLayout.gravity = Gravity.TOP | Gravity.LEFT; // 设置窗体宽度和高度
mLayout.width = WindowManager.LayoutParams.WRAP_CONTENT;
mLayout.height = WindowManager.LayoutParams.WRAP_CONTENT;

详细 MainActivity 代码如下:

package com.yc.yc_suspendingform;

import android.app.Activity;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.os.Bundle;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.WindowManager;
import android.widget.Button;
import com.yc.yc_floatingform.R; public class MainActivity extends Activity {
private WindowManager mWindowManager;
private WindowManager.LayoutParams mLayout;
private DesktopLayout mDesktopLayout;
private long startTime;
// 声明屏幕的宽高
float x, y;
int top; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
createWindowManager();
createDesktopLayout();
Button btn = (Button) findViewById(R.id.btn);
btn.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
showDesk();
}
});
}
/**
* 创建悬浮窗体
*/
private void createDesktopLayout() {
mDesktopLayout = new DesktopLayout(this);
mDesktopLayout.setOnTouchListener(new OnTouchListener() {
float mTouchStartX;
float mTouchStartY; @Override
public boolean onTouch(View v, MotionEvent event) {
// 获取相对屏幕的坐标,即以屏幕左上角为原点
x = event.getRawX();
y = event.getRawY() - top; // 25是系统状态栏的高度
Log.i("startP", "startX" + mTouchStartX + "====startY"
+ mTouchStartY);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// 获取相对View的坐标,即以此View左上角为原点
mTouchStartX = event.getX();
mTouchStartY = event.getY();
Log.i("startP", "startX" + mTouchStartX + "====startY"
+ mTouchStartY);
long end = System.currentTimeMillis() - startTime;
// 双击的间隔在 300ms以下
if (end < 300) {
closeDesk();
}
startTime = System.currentTimeMillis();
break;
case MotionEvent.ACTION_MOVE:
// 更新浮动窗口位置参数
mLayout.x = (int) (x - mTouchStartX);
mLayout.y = (int) (y - mTouchStartY);
mWindowManager.updateViewLayout(v, mLayout);
break;
case MotionEvent.ACTION_UP: // 更新浮动窗口位置参数
mLayout.x = (int) (x - mTouchStartX);
mLayout.y = (int) (y - mTouchStartY);
mWindowManager.updateViewLayout(v, mLayout); // 可以在此记录最后一次的位置 mTouchStartX = mTouchStartY = 0;
break;
}
return true;
}
});
} @Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
Rect rect = new Rect();
// /取得整个视图部分,注意,如果你要设置标题样式,这个必须出现在标题样式之后,否则会出错
getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
top = rect.top;//状态栏的高度,所以rect.height,rect.width分别是系统的高度的宽度 Log.i("top",""+top);
} /**
* 显示DesktopLayout
*/
private void showDesk() {
mWindowManager.addView(mDesktopLayout, mLayout);
finish();
} /**
* 关闭DesktopLayout
*/
private void closeDesk() {
mWindowManager.removeView(mDesktopLayout);
finish();
} /**
* 设置WindowManager
*/
private void createWindowManager() {
// 取得系统窗体
mWindowManager = (WindowManager) getApplicationContext()
.getSystemService("window"); // 窗体的布局样式
mLayout = new WindowManager.LayoutParams(); // 设置窗体显示类型——TYPE_SYSTEM_ALERT(系统提示)
mLayout.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; // 设置窗体焦点及触摸:
// FLAG_NOT_FOCUSABLE(不能获得按键输入焦点)
mLayout.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; // 设置显示的模式
mLayout.format = PixelFormat.RGBA_8888; // 设置对齐的方法
mLayout.gravity = Gravity.TOP | Gravity.LEFT; // 设置窗体宽度和高度
mLayout.width = WindowManager.LayoutParams.WRAP_CONTENT;
mLayout.height = WindowManager.LayoutParams.WRAP_CONTENT; } }

源代码地址:https://github.com/YeXiaoChao/Yc_suspendingform

本文地址:www.cnblogs.com/yc-755909659/p/4281214.html

PS:本文由J灬叶小超原创,如有转载请注明出处,谢谢!

【Android Demo】悬浮窗体实现的更多相关文章

  1. android编程之悬浮窗体

    用过手机360和QQ手机管家等一些软件的朋友,会发现,在这些应用中,会出现一个悬浮窗体,例如QQ手机管家中打电话的场景: 这种窗体除了会显示外,还可以移动它的位置,并且一直显示.除了关闭当前程序外,窗 ...

  2. Android WindowManager悬浮窗:不需要申请权限实现悬浮

     Android WindowManager悬浮窗:不需要申请权限实现悬浮 附录文章1介绍了Android平台上的悬浮窗WindowManager,WindowManager悬浮窗可以悬浮在And ...

  3. Android EditText悬浮在输入法之上

    Android EditText悬浮在输入法之上 使用 android:windowSoftInputMode="adjustResize" 会让界面整体被顶上去,很多时候我们不需 ...

  4. Android -- 桌面悬浮,QQ管家火箭实现

    续上一篇博客<Android -- 桌面悬浮,仿360>,传送门:http://www.cnblogs.com/yydcdut/p/3909888.html,在此代码上继续添加实现. 比起 ...

  5. LeadTools Android 入门教学——运行第一个Android Demo

    LeadTools 有很多Windows平台下的Demo,非常全面,但是目前开发手机应用的趋势也越来越明显,LeadTools也给大家提供了10个Android的Demo,这篇文章将会教你如何运行第一 ...

  6. 【Android】如何快速构建Android Demo

    [Android]如何快速构建Android Demo 简介 在 Android 学习的过程中,经常需要针对某些项目来写一些测试的例子,或者在做一些 demo 的时候,都需要先写 Activity 然 ...

  7. Android 之 悬浮窗

    昨天研究Android的悬浮窗,遇到一个问题,研究了一天,总算找到结症了,原因非常坑人..... 问题是这样的,我想要将悬浮窗展现在桌面或其他应用之上,我的开发机子用的是MIUI,结果发现在机子上无论 ...

  8. 制作Android Demo GIF:程序演示效果GIF图录制

    [转] 制作Android Demo GIF:程序演示效果GIF图录制   在平时写博客或者分享自己写的程序效果的时候经常需要做成GIF图,以下就是介绍几种常用的GIF录制方法: 一.录制工具 1.( ...

  9. Ubuntu TensorFlow 源码 Android Demo的编译运行

    Ubuntu TensorFlow 源码 Android Demo的编译运行 一. 安装 Android 的SDK和NDK SDK 配置 A:下载 国内下载地址选最新的: SDK: https://d ...

随机推荐

  1. c++中stl容器的常用示例

    1. set(集合)——包含了经过排序了的数据,这些数据的值(value)必须是唯一的. 也就是说输入set容器后得到数据,会去重并排序.    s.insert()插入一个元素    s.begin ...

  2. session与cookie的异同

    cookie将数据存储在客户端,建立起用户与服务器之间的联系,通常可以解决很多问题,但是cookie仍然具有一些局限: cookie相对不是太安全,容易被盗用导致cookie欺骗 单个cookie的值 ...

  3. phpcms v9 升级视频云问题推荐位不能添加

    因为使用的是v9的早期版本,后来升级的时候没敢升级数据库,直接使用了老的数据库结构,造成[推荐位]添加不能使用,报告没有thumb列. 查看数据库果然没有,没办法要么添加相关的列,要么禁用上传缩略图. ...

  4. c#多线程生产者消费者(手稿)

    屋舍简陋,隔壁的娃娃哭了一晚,心中无恶意纯中性的想,有病就赶紧带孩子去看医生吧,能哭这么久估计孩子真的不舒服.

  5. Javascript面向对象编程(二)--- 构造函数的继承

    这个系列的第一部分,主要介绍了如何"封装"数据和方法,以及如何从原型对象生成实例 今天要介绍的是,对象之间的"继承"的五种方法. 比如,现在有一个"动 ...

  6. React 初学整理

    1,通过createElement创建元素 HELLO Word ps:切记组建名称首字母大写 2,虚拟DOM 在虚拟DOM上操作 通过render来渲染真是DOM 3,JSX JSX 是对JS的语法 ...

  7. sap透明表、结构、簇介绍以及查找表方法

    sap透明表.结构.簇介绍以及查找表方法 一些人在写开发功能说明书的时候不知道如何去找屏幕字段对应的透明表,下面我来介绍一个比较有效的方法:首先简单介绍一下概念:在SAP中的表的种类有以下三种:Tra ...

  8. SharePoint 2013开发环境准备一些小事项

    开发慢慢向着SharePoint 2013迁移,环境也开始慢慢准备起来了.由于FAST Search的集成,和缓存服务的加入,SharePoint 2013对开发机器要求的不是一般的高.这里介绍一下如 ...

  9. Sql server 2008 R2 配置管理工具服务显示远程过程调用失败:0x800706be

    Sql server 2008 R2 配置管理工具服务显示远程过程调用失败:0x800706be   今天在其他电脑配置 SQl server 2008 R2,安装完成后,发现打开配置管理工具服务 : ...

  10. Jsoup解析Html中文文档

    jsoup 简介Java 程序在解析 HTML 文档时,相信大家都接触过 htmlparser 这个开源项目,我曾经在 IBM DW 上发表过两篇关于 htmlparser 的文章,分别是:从 HTM ...