在AndroidManifest.xml中加入
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
创建悬浮窗布局文件
floatwindow_layout.xml
<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/small_window_layout"
android:layout_width="60dip"
android:layout_height="25dip"
android:background="@drawable/floatwindow"
>
<TextView
android:id="@+id/percent"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center"
android:textColor="#ffffff"
/>
</LinearLayout>
通过bindService启动服务
Intent intent = new Intent(this, FloatWindowService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
创建FloatWindowService.java 类
public class FloatWindowService extends Service {
private final String TAG = "FloatWindowService";
private WindowManager.LayoutParams wmParams;
private WindowManager mWindowManager;
private FloatWindowView mFloatView;
private MainActivity mainActivity;
@Override
public void onCreate() {
super.onCreate();
Log.i(TAG, "onCreate");
//
initWindowParams();
initView();
mWindowManager.addView(mFloatView, wmParams);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.i(TAG, "onBind");
return new ShowHomePageBinder();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
if (mFloatView != null) {
//移除悬浮窗口
Log.i(TAG, "removeView");
mWindowManager.removeView(mFloatView);
}
Log.i(TAG, "onDestroy");
}
private void initView() {
// mFloatView = LayoutInflater.from(getApplication()).inflate(R.layout.floatwindow_layout, null);
mFloatView = new FloatWindowView(getApplicationContext());
mFloatView.setParams(wmParams);
mFloatView.setMoveThreshold(5);
mFloatView.setClickable(true);
mFloatView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d(TAG, "click float window....");
if (mainActivity == null) {
Log.d(TAG, "main activity is null");
return;
}
Log.d(TAG, "tabhost setCurrentTab to home page");
mainActivity.onKeyDown(MainActivity.KEYCODE_F0, new KeyEvent(KeyEvent.ACTION_DOWN, MainActivity.KEYCODE_F0));
}
});
}
/**
* 初始化 LayoutParams
*/
private void initWindowParams() {
mWindowManager = (WindowManager) getApplication().getSystemService(getApplication().WINDOW_SERVICE);
wmParams = new WindowManager.LayoutParams();
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;
}
public void setMainActivity(MainActivity activity) {
mainActivity = activity;
}
public class ShowHomePageBinder extends Binder
{
public FloatWindowService getFloatWindowService()
{
return FloatWindowService.this;
}
}
}
自定义FloatWindowView
public class FloatWindowView extends LinearLayout {
/**
* 记录悬浮窗的宽度
*/
public static int viewWidth;
/**
* 记录悬浮窗的高度
*/
public static int viewHeight;
/**
* 用于更新悬浮窗的位置
*/
private WindowManager windowManager;
/**
* 悬浮窗的参数
*/
private WindowManager.LayoutParams mParams;
/**
* 记录当前手指位置在屏幕上的横坐标值
*/
private float xInScreen;
/**
* 记录当前手指位置在屏幕上的纵坐标值
*/
private float yInScreen;
/**
* 记录手指按下时在屏幕上的横坐标的值
*/
private float xDownInScreen;
/**
* 记录手指按下时在屏幕上的纵坐标的值
*/
private float yDownInScreen;
/**
* 记录手指按下时在悬浮窗的View上的横坐标的值
*/
private float xInView;
/**
* 记录手指按下时在悬浮窗的View上的纵坐标的值
*/
private float yInView;
/**
* 点击监听器
*/
private OnClickListener mClickLinstener;
/**
* 设置点击响应灵敏度
*/
private int threshold = 30;
public FloatWindowView(Context context) {
super(context);
windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
LayoutInflater.from(context).inflate(R.layout.floatwindow_layout, this);
View view = findViewById(R.id.float_window_layout);
// TextView goHomeView = (TextView)findViewById(R.id.gohome);
viewWidth = view.getLayoutParams().width;
viewHeight = view.getLayoutParams().height;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// 手指按下时记录必要数据,纵坐标的值都需要减去状态栏高度
xInView = event.getX();
yInView = event.getY();
xDownInScreen = event.getRawX();
yDownInScreen = event.getRawY();
xInScreen = event.getRawX();
yInScreen = event.getRawY();
break;
case MotionEvent.ACTION_MOVE:
xInScreen = event.getRawX();
yInScreen = event.getRawY();
// 手指移动的时候更新小悬浮窗的位置
updateViewPosition();
break;
case MotionEvent.ACTION_UP:
// // 如果手指离开屏幕时,xDownInScreen和xInScreen相等,且yDownInScreen和yInScreen相等,则视为触发了单击事件。
if (needIntercept()) {
return true;
} else {
mClickLinstener.onClick(this);
}
break;
default:
break;
}
return true;
}
/**
* 将悬浮窗的参数传入,用于更新悬浮窗的位置。
*
* @param params
* 悬浮窗的参数
*/
public void setParams(WindowManager.LayoutParams params) {
mParams = params;
}
/**
* 更新悬浮窗在屏幕中的位置。
*/
private void updateViewPosition() {
mParams.x = (int) (xInScreen - xInView);
mParams.y = (int) (yInScreen - yInView);
windowManager.updateViewLayout(this, mParams);
}
/**
* 是否拦截
* @return true:拦截;false:不拦截.
*/
private boolean needIntercept() {
if (Math.abs(xDownInScreen - xInScreen) > threshold || Math.abs(yDownInScreen - yInScreen) > threshold) {
return true;
}
return false;
}
public void setMoveThreshold(int threshold) {
this.threshold = threshold;
}
@Override
public void setOnClickListener(OnClickListener l) {
mClickLinstener = l;
}
}
在主类中定义成员变量并将MainActivity的引用传给FloatWindowService
private FloatWindowService mFloatWindowService = null;
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
Log.d(TAG, "onServiceDisconnected");
mFloatWindowService = null;
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.d(TAG, "onServiceConnected...");
mFloatWindowService = ((FloatWindowService.ShowHomePageBinder)service).getFloatWindowService();
if (mFloatWindowService != null) {
mFloatWindowService.setMainActivity(MainActivity.this);
}
}
};
参考博客
* Android桌面悬浮窗效果实现,仿360手机卫士悬浮窗效果*
Android 使用WindowManager实现悬浮窗及源码解析
service回调activity
service获取activity引用