Android 悬浮窗实现
2016-08-10 20:31
288 查看
在工作中遇到开发悬浮窗的需求,在此整理一下,记录心得O(∩_∩)O哈哈~
大概的思路如下:
我们将悬浮窗绑定在一个service中,某个activity界面上的开关来控制悬浮窗的显示/隐藏/移除
这里 我们简化步骤 仅用activity来控制悬浮窗
1.首先是悬浮窗的布局(这里我们做一个时钟的悬浮窗)
floating_window.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="150dp" android:layout_height="150dp" android:background="@android:color/holo_purple" android:orientation="vertical" > <DigitalClock android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:textSize="12sp" android:background="@android:color/background_light" android:alpha="0.8"/> <AnalogClock android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@android:color/holo_blue_light" /> </LinearLayout>
2.然后是activity的布局
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="com.example.demo_xuanfuchuang.MainActivity" > <!-- <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/hello_world" /> --> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" android:gravity="center" > <!--这里我们使用两个button来控制悬浮窗显示/隐藏--> <Button android:id="@+id/start" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="20dp" android:background="@android:color/holo_blue_light" android:text="@string/action_start" /> <Button android:id="@+id/end" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="20dp" android:background="@android:color/holo_red_light" android:text="@string/action_end" /> </LinearLayout> </LinearLayout>
3.(干货在此)重点在这里
3.1 悬浮窗初始化
WindowManager wm = (WindowManager)getSystemService(Context.WINDOW_SERVICE);//获取 View view = LayoutInflater.from(this).inflate(R.layout.floating_window,null); LayoutParams lp = new WindowManager.LayoutParams(); ...... wm.addView(view,lp);
关于WindowManager,详细解释的链接
http://gundumw100.iteye.com/blog/830235
关于WindowManager.LayoutParams,详细解释的链接
http://blog.sina.com.cn/s/blog_4b3c1f950100qd9s.html
在实际操作中,仅仅这样虽然添加上了悬浮窗,但是悬浮窗有可能将整个桌面覆盖,这里就需要我们用到合理的WindowManager.LayoutParams属性
lp.type = WindowManager.LayoutParams.TYPE_TOAST;
首先是type属性,一般来说悬浮窗可以使用TYPE_SYSTEM_ALERT,但是该属性需要在AndroidManifest.xml中声明权限 如果我们在手机的权限管理中关闭该应用的悬浮窗权限,那么在不加处理的情况下,会报错,即使我们事先考虑过该问题,关闭权限时也会无法显示悬浮窗.
因此我们可以考虑使用WindowManager.LayoutParams.TYPE_TOAST,不需要申请权限就可以直接显示
float mHorizontalMargin = 0f; float mVerticalMargin =0.3f; lp.gravity = Gravity.LEFT|Gravity.TOP; lp.horizontalMargin = mHorizontalMargin; lp.verticalMargin = mVerticalMargin;
这里的代码来定位初始位置,首先是lp.gravity定位初始位置,这里是定位在左上角,而lp.horizontalMargin和lp.verticalMargin分别是相对于初始位置的偏移位置, 三者一起,就定位了一个精确的初始位置
lp.height = WindowManager.LayoutParams.WRAP_CONTENT; lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
这里必须要配置这两个属性,否则的话,就会全屏覆盖 - -! 你懂的
lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|......;
这里的属性可以自行百度
3.2悬浮窗的自由移动
view.setOnTouchListener(…)方法实现
private int X = 0, Y = 0; private boolean mMoved=false; @Override public boolean onTouch(View view, MotionEvent event) { // TODO Auto-generated method stub final int x = (int) event.getRawX(); final int y = (int) event.getRawY(); float dx, dy; boolean ret=false; switch(event.getAction()){ case MotionEvent.ACTION_DOWN: X = x; Y = y; mMoved = false; break; case MotionEvent.ACTION_MOVE: if(mMoved || Math.abs(x-X) > 10 || Math.abs(y-Y) > 10){ dx = (x-X)*1.0f/wm.getDefaultDisplay().getWidth(); dy = (y-Y)*1.0f/wm.getDefaultDisplay().getHeight(); X = x; Y = y; lp.horizontalMargin = lp.horizontalMargin + dx; lp.verticalMargin = lp.verticalMargin + dy; wm.updateViewLayout(view, lp); mMoved = true; } break; case MotionEvent.ACTION_UP: if(mMoved){ dx = (x-X)*1.0f/wm.getDefaultDisplay().getWidth(); dy = (y-Y)*1.0f/wm.getDefaultDisplay().getHeight(); X = x; Y = y; lp.horizontalMargin = lp.horizontalMargin + dx; lp.verticalMargin = lp.verticalMargin + dy; if(lp.horizontalMargin < 0f) lp.horizontalMargin = 0f; else if(lp.horizontalMargin > 1.0f) lp.horizontalMargin = 1.0f; if(lp.verticalMargin < 0f) lp.verticalMargin = 0f; else if(lp.verticalMargin > 1.0f) lp.verticalMargin = 1.0f; wm.updateViewLayout(view, lp); ret = true; } break; } return ret; }
此处代码就是简单的移动位置的计算,不做解释了,另外
WindowManager.LayoutParams.horizontalMargin和
WindowManager.LayoutParams.verticalMargin属性取值
0.0f到1.0f代表整个屏幕长宽
下面完整Activity代码
package com.example.demo_xuanfuchuang; import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.view.Gravity; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; import android.view.View.OnClickListener; import android.view.WindowManager; import android.view.WindowManager.LayoutParams; import android.view.animation.LayoutAnimationController; import android.widget.Button; public class MainActivity extends Activity implements View.OnClickListener, View.OnTouchListener{ private View view; private WindowManager wm; private LayoutParams lp; private float mHorizontalMargin = 0f; private float mVerticalMargin =0.3f; private Button bt_start; private Button bt_end; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); bt_start = (Button)findViewById(R.id.start); bt_end = (Button)findViewById(R.id.end); bt_start.setOnClickListener(this); bt_end.setOnClickListener(this); wm = (WindowManager)getSystemService(Context.WINDOW_SERVICE); view = LayoutInflater.from(this).inflate(R.layout.floating_window,null); lp = new WindowManager.LayoutParams(); lp.type = WindowManager.LayoutParams.TYPE_TOAST; lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; lp.gravity = Gravity.LEFT|Gravity.TOP; lp.height = WindowManager.LayoutParams.WRAP_CONTENT; lp.width = WindowManager.LayoutParams.WRAP_CONTENT; lp.horizontalMargin = mHorizontalMargin; lp.verticalMargin = mVerticalMargin; wm.addView(view,lp); view.setVisibility(View.GONE); view.setOnTouchListener(this); } @Override public void onClick(View v) { // TODO Auto-generated method stub if(bt_start.equals(v)){ view.setVisibility(View.VISIBLE); }else if(bt_end.equals(v)){ view.setVisibility(View.GONE); } } private int X = 0, Y = 0; private boolean mMoved=false; @Override public boolean onTouch(View view, MotionEvent event) { // TODO Auto-generated method stub final int x = (int) event.getRawX(); final int y = (int) event.getRawY(); float dx, dy; boolean ret=false; switch(event.getAction()){ case MotionEvent.ACTION_DOWN: X = x; Y = y; mMoved = false; break; case MotionEvent.ACTION_MOVE: if(mMoved || Math.abs(x-X) > 10 || Math.abs(y-Y) > 10){ dx = (x-X)*1.0f/wm.getDefaultDisplay().getWidth(); dy = (y-Y)*1.0f/wm.getDefaultDisplay().getHeight(); X = x; Y = y; lp.horizontalMargin = lp.horizontalMargin + dx; lp.verticalMargin = lp.verticalMargin + dy; android.util.Log.i("ztest","lp.horizontalMargin = " + lp.horizontalMargin + "; lp.verticalMargin = " + lp.verticalMargin); wm.updateViewLayout(view, lp); mMoved = true; } break; case MotionEvent.ACTION_UP: if(mMoved){ dx = (x-X)*1.0f/wm.getDefaultDisplay().getWidth(); dy = (y-Y)*1.0f/wm.getDefaultDisplay().getHeight(); X = x; Y = y; lp.horizontalMargin = lp.horizontalMargin + dx; lp.verticalMargin = lp.verticalMargin + dy; if(lp.horizontalMargin < 0f) lp.horizontalMargin = 0f; else if(lp.horizontalMargin > 1.0f) lp.horizontalMargin = 1.0f; if(lp.verticalMargin < 0f) lp.verticalMargin = 0f; else if(lp.verticalMargin > 1.0f) lp.verticalMargin = 1.0f; wm.updateViewLayout(view, lp); ret = true; } break; } return ret; } }
到这里,一个简单的悬浮窗Demo就实现了,具体效果在我的小米手机上如下:
相关文章推荐
- Android桌面悬浮窗效果实现,仿360手机卫士悬浮窗效果
- Android桌面悬浮窗效果实现,仿360手机卫士悬浮窗效果
- Android桌面悬浮窗进阶,QQ手机管家小火箭效果实现
- [android ui]Android桌面悬浮窗效果实现,仿360手机卫士悬浮窗效果
- Android桌面悬浮窗效果实现,仿360手机卫士悬浮窗效果
- android 应用 悬浮窗实现思路
- Android桌面悬浮窗进阶,QQ手机管家小火箭效果实现
- Android实现类似360,QQ管家那样的悬浮窗
- Android桌面悬浮窗效果实现,仿360手机卫士悬浮窗效果
- Android桌面悬浮窗进阶,QQ手机管家小火箭效果实现
- Android桌面悬浮窗效果实现,仿360手机卫士悬浮窗效果
- Android桌面悬浮窗效果实现,仿360手机卫士悬浮窗效果
- Android桌面悬浮窗效果实现,仿360手机卫士悬浮窗效果
- Android桌面悬浮窗效果实现,仿360手机卫士悬浮窗效果
- Android桌面悬浮窗效果实现,仿360手机卫士悬浮窗效果
- Android桌面悬浮窗效果实现,仿360手机卫士悬浮窗效果
- Android桌面悬浮窗效果实现,仿360手机卫士悬浮窗效果(待阅)
- Android桌面悬浮窗效果实现
- Android桌面悬浮窗进阶,QQ手机管家小火箭效果实现
- Android桌面悬浮窗效果实现,仿360手机卫士悬浮窗效果