Android 可移动悬浮窗口 WindowManager

一、有图有真相

二、如何创建悬浮窗口

比较简单,,主要是使用WindowManager API,以下是使用方法

@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout. activity_main);// 获取ServiceWindowManager mWindowManager = (WindowManager) getSystemService("window" );ImageView imageView = new ImageView(this);imageView.setImageResource(R.drawable. ic_launcher);// 设置窗口类型,一共有三种Application windows, Sub-windows, System windows// API中以TYPE_开头的常量有23个mWindowParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT ;// 设置期望的bitmap格式mWindowParams.format = PixelFormat.RGBA_8888;// 以下属性在Layout Params中常见重力、坐标,宽高mWindowParams.gravity = Gravity.LEFT | Gravity. TOP;mWindowParams.x = 100;mWindowParams.y = 100;mWindowParams .width = WindowManager.LayoutParams. WRAP_CONTENT;mWindowParams .height = WindowManager.LayoutParams. WRAP_CONTENT;// 添加指定视图mWindowManager.addView(imageView, mWindowParams);}

需要添加权限

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

如果没有以上权限,会出现如下异常:

java.lang.RuntimeException: Unable to start activity ComponentInfo{loveworld.floatview/loveworld.floatview.MainActivity}: android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRoot$W@40513b60 — permission denied for this window typeat android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1768)at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1784)at android.app.ActivityThread.access$1500(ActivityThread.java:123)at android.app.ActivityThread$H.handleMessage(ActivityThread.java:939)at android.os.Handler.dispatchMessage(Handler.java:99)at android.os.Looper.loop(Looper.java:130)at android.app.ActivityThread.main(ActivityThread.java:3835)at java.lang.reflect.Method.invokeNative(Native Method)at java.lang.reflect.Method.invoke(Method.java:507)at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:847)at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:605)at dalvik.system.NativeStart.main(Native Method)Caused by: android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRoot$W@40513b60 — permission denied for this window typeat android.view.ViewRoot.setView(ViewRoot.java:552)at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:177)at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:91)at android.view.Window$LocalWindowManager.addView(Window.java:465)at loveworld.floatview.MainActivity.onCreate(MainActivity.java:55)at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1722)… 11 more

三、如何使悬浮窗口可移动

窗口随手指移动需要获取先获取手指的点击事件,而点击事件通常都是通过覆写视图的onTouchEvent获得,当前例子也看不到悬浮窗口仅能看到其中包含的图片,所以选择在ImageView获取并处理触摸事件,获取手指轨迹X,Y坐标,更新窗口位置达到随手指移动效果。

首先自定义ImageView

public class MoveImageView extends ImageView {public MoveImageView(Context context) {super(context);}public MoveImageView(Context context, AttributeSet attrs) {super(context, attrs);}public MoveImageView(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);}}覆写onTouchEvent方法,用于监听图片视图的触摸事件@Overridepublic boolean onTouchEvent(MotionEvent event) {int titleHeight = 0;if (mListener != null) {titleHeight = mListener.getTitleHeight();}// 当前值以屏幕左上角为原点mRawX = event.getRawX();mRawY = event.getRawY() – titleHeight;final int action = event.getAction();switch (action) {case MotionEvent.ACTION_DOWN:// 以当前父视图左上角为原点mStartX = event.getX();mStartY = event.getY();break;case MotionEvent.ACTION_MOVE:updateWindowPosition();break;case MotionEvent.ACTION_UP:updateWindowPosition();break;}// 消耗触摸事件return true;}最后通过更新窗口X,Y轴参数达到移动效果/** * 更新窗口参数,控制浮动窗口移动 */private void updateWindowPosition() {if (mListener != null) {// 更新坐标LayoutParams layoutParams = mListener.getLayoutParams();layoutParams.x = (int)(mRawX – mStartX);layoutParams.y = (int)(mRawY – mStartY);// 使参数生效mWindowManager.updateViewLayout(this, layoutParams);}} 其中当前自定义视图要用到两个变量,只有在Activity中可以获取到,这就涉及到如何在自定义视图中获取到这两个变量。 可以把变量保存到Application中,也可以使用单例对象在Activity中初始化并赋值在自定义视图中获取,当前是使用接口回调方法,在Activity中实现接口通过这种方法使自定义视图获取变量,感觉这种方式比较好,不用考虑把变量放到Application涉及到的生命周期释放等问题,也不用考虑单例促使对象的生命周期一样很长。我不但的回首,伫足,然后时光扔下我轰轰烈烈的向前奔去。

Android 可移动悬浮窗口 WindowManager

相关文章:

你感兴趣的文章:

标签云: