Android -- 使用WindowManager实现悬浮框效果
1,原文在这里http://blog.csdn.net/qq_17250009/article/details/52908791,我只是把里面的关键步骤给注释了一下,首先来看一下我们的效果,如图(电脑太卡,截图有问题,见谅):
2,来看一下我们的实现步骤,首先创建一个service,用于将我们的布局悬浮到我们的Android系统上去,然后通过activity来启动这个service,所以代码如下:
MainActivity.java
package com.qianmo.suspendcircle; import android.content.Intent;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Button; import static android.icu.lang.UCharacter.GraphemeClusterBreak.V;
import static android.os.Build.VERSION_CODES.M; public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Button btn_start;
private Button btn_end; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
btn_start = (Button) findViewById(R.id.btn_start);
btn_end = (Button) findViewById(R.id.btn_end);
btn_start.setOnClickListener(this);
btn_end.setOnClickListener(this);
setSupportActionBar(toolbar); FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
} @Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
} @Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId(); //noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
} return super.onOptionsItemSelected(item);
} @Override
public void onClick(View v) {
switch (v.getId()) {
//启动服务
case R.id.btn_start:
Intent intent = new Intent(MainActivity.this, WindowService.class);
startService(intent);
break;
//停止服务
case R.id.btn_end:
Intent intent1 = new Intent(MainActivity.this, WindowService.class);
stopService(intent1);
break;
}
}
}
MainActivity这个没什么好说的,就是启动service和关闭service而已,主要是那个Service,代码如下:
WindowService.java
package com.qianmo.suspendcircle; import android.app.ActivityManager;
import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.TextView; import java.util.List; /**
* Created by Administrator on 2017/2/9 0009.
* E-Mail:543441727@qq.com
*/ public class WindowService extends Service {
private final String TAG = this.getClass().getSimpleName(); private WindowManager.LayoutParams wmParams;
private WindowManager mWindowManager;
private View mWindowView;
private TextView mPercenrTv; private int mStartX;
private int mStartY;
private int mEndX;
private int mEndY; @Override
public void onCreate() {
super.onCreate();
Log.i(TAG, "Create");
initWindowParams();
initView();
addWindowViewZWindow();
initClick();
} /**
* 点击事件和拖拽事件
*/
private void initClick() {
mPercenrTv.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
//按下鼠标的时候记录下屏幕的位置
case MotionEvent.ACTION_DOWN:
mStartX = (int) event.getRawX();
mStartY = (int) event.getRawY(); break;
case MotionEvent.ACTION_MOVE:
mEndX = (int) event.getRawX();
mEndY = (int) event.getRawY();
if (needIntercept()) {
//getRawX是触摸位置相对于整个屏幕的位置,getX是控触摸点相对于控件最左边的位置
wmParams.x = (int) event.getRawX() - mWindowView.getMeasuredWidth() / 2;
wmParams.y = (int) event.getRawY() - mWindowView.getMeasuredHeight() / 2;
mWindowManager.updateViewLayout(mWindowView, wmParams);
return true;
}
break;
case MotionEvent.ACTION_UP:
if (needIntercept()) {
return true;
}
break;
} return false;
}
}); mPercenrTv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.i(TAG, "点击了");
if (isAppAtBackground(WindowService.this)) {
Intent intent = new Intent(WindowService.this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
}
}); } /**
* 判断当前应用是前台还是后台
*/
private boolean isAppAtBackground(final Context context) {
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> tasks = am.getRunningTasks(1);
if (!tasks.isEmpty()) {
ComponentName topActivity = tasks.get(0).topActivity;
if (!topActivity.getPackageName().equals(context.getPackageName())) {
return true;
}
}
return false;
} /**
* 判断是否拦截,根据滑动的距离
*
* @return
*/
private boolean needIntercept() {
if (Math.abs(mStartX - mEndX) > 30 || Math.abs(mStartY - mEndY) > 30) {
return true;
}
return false;
} /**
* 添加View到桌面Window界面上
*/
private void addWindowViewZWindow() {
mWindowManager.addView(mWindowView, wmParams);
} /**
* 初始化加速球控件
*/
private void initView() {
mWindowView = LayoutInflater.from(getApplication()).inflate(R.layout.layout_window, null);
mPercenrTv = (TextView) mWindowView.findViewById(R.id.percentTv);
} /**
* 初始化Window对象的参数
*/
private void initWindowParams() {
//1,获取系统级别的WindowManager
mWindowManager = (WindowManager) getApplication().getSystemService(getApplication().WINDOW_SERVICE);
wmParams = new WindowManager.LayoutParams(); //2,添加系统参数,确保悬浮框能显示到手机上 //电话窗口。它用于电话交互(特别是呼入)。它置于所有应用程序之上,状态栏之下。
wmParams.type = WindowManager.LayoutParams.TYPE_PHONE;
//期望的位图格式。默认为不透明
wmParams.format = PixelFormat.TRANSLUCENT;
//不许获得焦点
wmParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
//窗口停靠位置
wmParams.gravity = Gravity.LEFT | Gravity.TOP;
wmParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
wmParams.height = WindowManager.LayoutParams.WRAP_CONTENT; } @Override
public void onDestroy() {
super.onDestroy();
if (mWindowView != null) {
//移除悬浮窗口
Log.i(TAG, "removeView");
mWindowManager.removeView(mWindowView);
}
Log.i(TAG, "onDestroy");
} @Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
由于注释很详细了,就不给大家说代码了
最后附上源码地址: https://github.com/543441727/SuspendWindow.git
Android -- 使用WindowManager实现悬浮框效果的更多相关文章
- C# 鼠标悬停在datagridview的某单元格,显示悬浮框效果
今天在做项目时,看到一软件做的悬浮框效果不错,从网上搜罗了一些资料,未见到有十分好的解决办法,只能自已动手,利用datagridview 的ToolTipText 来达到此效果. 以下是我简单实现的代 ...
- android自定义listview实现header悬浮框效果
之前在使用iOS时,看到过一种分组的View,每一组都有一个Header,在上下滑动的时候,会有一个悬浮的Header,这种体验觉得很不错,请看下图: 上图中标红的1,2,3,4四张图中,当向上滑动时 ...
- android适配全机型悬浮框、视频APP项目、手势操作、Kotlin妹子App、相机图片处理等源码
Android精选源码 图片滤镜处理,相机滤镜实时处理,相机拍照录制 android仿爱壁纸App更换壁纸效果源码 基于Kotlin+MVP+Retrofit+RxJava+Glide 等架构实现短视 ...
- Android悬浮框,在Service中打开悬浮窗;在Service中打开Dialog;
文章介绍了如何在Service中显示悬浮框,在Service中弹出Dialog,在Service中做耗时的轮询操作: 背景需求: 公司的项目现在的逻辑是这样的:发送一个指令,然后3秒一次轮询去查询这个 ...
- uni-app悬浮框模板
1. uni-app悬浮框模板 1.1. 目标 模仿饿了吗app的悬浮框效果,即上移过程中,中间的某个组件框到顶部后不再上移,呈类似置顶的效果 1.2. 问题 中间遇到fixed固定组件导致flex失 ...
- Android音视频通话过程中最小化成悬浮框的实现(类似Android8.0画中画效果)
关于音视频通话过程中最小化成悬浮框这个功能的实现,网络上类似的文章很多,但是好像还没看到解释的较为清晰的,这里因为项目需要实现了这样的一个功能,今天我把它记录下来,一方面为了以后用到便于自己查阅,一方 ...
- Android 应用开机自启和无需权限开启悬浮框
开机自启主要自定义广播接收类,且需要在清单文件中注册,不要在代码中动态注册. <uses-permission android:name="android.permission.REC ...
- 026 Android 带不同类型条目的listview(纯文本类型的条目,图片+文字类型的条目)+读取内存空间、手机进程信息+常驻悬浮框
1.目标效果 带不同类型条目的listview(纯文本类型的条目,图片+文字类型的条目)+常驻悬浮框 2.页面布局文件 (1)activity_process_manager.xml <?xml ...
- android 界面悬浮框实现
// 定义浮动窗口布局 private View mFloatLayout; // 定义浮动窗口布局对象 private WindowManager.LayoutParams wmParams; // ...
随机推荐
- English class 82 The Importance of traveling
1,since I could basically walk : pretty much 2,Malaysian girl 3,profound love: deep very inportant 4 ...
- linux添加新硬盘
1.添加新磁盘 2.fdisk -l查看磁盘被识别的名称 3.如果输入fdisk -l命令没有找到新的磁盘,按下面步骤操作 1)进入到cd /sys/class/scsi_host/ 2)echo & ...
- page 页 分页 分段
小结: 1. 页:磁盘和内存间传输数据的最小单位: MySQL: What is a page? https://stackoverflow.com/questions/4401910/mysql-w ...
- 随着应用对事务完整性和并发性要求的不断提高,MySQL才开始开发基于事务的存储引擎
MYSQL 解锁与锁表 - 专注it - 博客园 https://www.cnblogs.com/wanghuaijun/p/5949934.html 2016-10-11 16:50 MYSQL 解 ...
- httpclient发送接受请求
需要注意三部分,request和参数的处理,响应数据.与请求相关的dll是System.Net. 核心代码: private string Post(string requestUrlString, ...
- MyEvent.SetEvent; // 同步信号置位
MyEvent.SetEvent; // 同步信号置位 TSimpleEvent.Create = TEvent.Create(nil, True, False, nil) ...
- DBGridEh表尾显示合计 .....
设置如下就可以了..... FooterRowCount : 1 SumList--------Active:=true 双击 DBGridEh 加入所需要的列....然后在 需要合计的..... ...
- 【PyQt5-Qt Designer】PyQt5+eric6 安装和配置
PyQt5+eric6 安装及配置 1.利用pip命令安装PyQt5 第一步:安装PyQt5 在cmd命令行中输入: pip install PyQt5 第二步:安装Qt的工具包 pip instal ...
- linux 查看磁盘读写:iostat
iostat命令用来查看磁盘IO的读写情况,用法如下: 安装iostat命令 [root@mysql ~]# yum install -y sysstat [root@mysql ~]# iostat ...
- Laravel上传产品图片Uploading img
这节我们讲Laravel产品图片上传,有很多方式可以实现,这里我们用intervention/image插件来进行.首先安装intervention/image插件,在命令行输入 composer r ...