Android实现系统级悬浮按钮
本文实例为大家分享了android系统级悬浮按钮的具体代码,供大家参考,具体内容如下
具体的需求
1、就是做一个系统级的悬浮按钮,就像iphone 桌面的那个悬浮按钮效果一样,能随意拖动,并且手一放开,悬浮按钮就自动靠边。
2、可以点击并且可以随意拖动。
3、悬浮按钮自动靠边的时候,或者移动到边上的时候,自动隐藏半边。
4、横竖屏切换都兼容
1、就在windowmanager 里面添加view,这个view通过自定义控件来实现。
2、在ontouch里的motionevent.action_move事件里头,通过控制悬浮按钮的具体坐标来实现随意移动。
3、在ontouch里的motionevent.action_up事件里头,来控制悬浮按钮自动靠边,并且自动隐藏半边,不过在这里ontouch和onclick这两个事件是一起触发的,不过这也有解决办法,你可以在手放开的瞬间,通过移动的距离,来决定是否触发点击事件,,如果返回false,就会触发点击事件,如果返回true就会触发点击事件
4、通过自定义控件onlayout方法,来捕获横竖屏切换事件,
5、还有一个靠哪边停靠的问题,通过坐标来判读更靠近哪一边。就靠哪边停靠。
![以中间这个中心点为准,以更短的x轴画一个正方形]
下面是具体实现代码:
import android.content.context; import android.graphics.canvas; import android.graphics.point; import android.graphics.rect; import android.util.attributeset; import android.view.motionevent; import android.view.view; import android.view.windowmanager; import android.widget.imageview; import com.iapppay.openid.channel.loginresultcallback; import com.iapppay.openid.channel.openidapplication; import com.iapppay.openid.channel.util.displayutil; import com.iapppay.openid.channel.util.logutil; import com.iapppay.openid.channel.util.res; /** * created by huangtiebing 2017/2/14. */ public class dragfloatactionbutton extends imageview implements view.ontouchlistener, view.onclicklistener { public static string tag = "dragfloatactionbutton"; private context context; float lastx, lasty; float originx, originy; int screenwidth; int screenheight; private int originwidth; private windowmanager windowmanager; // // 此windowmanagerparams变量为获取的全局变量,用以保存悬浮窗口的属性 private windowmanager.layoutparams windowmanagerparams; private loginresultcallback resultcallback; //悬浮按钮点击回调 public dragfloatactionbutton(context context, boolean isforcelogin, loginresultcallback resultcallback) { this(context, null); openidapplication.getinstance().setforcelogin(isforcelogin); this.resultcallback = resultcallback; } public dragfloatactionbutton(context context, attributeset attrs) { this(context, attrs, 0); } public dragfloatactionbutton(context context, attributeset attrs, int defstyleattr) { super(context, attrs, defstyleattr); this.context = context; point screensize = displayutil.getscreensize(context); screenwidth = screensize.x; screenheight = screensize.y; setimageresource(res.drawable(context, "ipay_float_btn_bg")); setontouchlistener(this); setonclicklistener(this); windowmanager = (windowmanager) getcontext().getapplicationcontext().getsystemservice(context.window_service); } public int getoriginwidth() { return originwidth; } public void setoriginwidth(int originwidth) { this.originwidth = originwidth; } @override public boolean ontouch(view v, motionevent event) { windowmanagerparams = (windowmanager.layoutparams) this.getlayoutparams(); //获取到状态栏的高度 rect frame = new rect(); getwindowvisibledisplayframe(frame); int ea = event.getaction(); switch (ea) { case motionevent.action_down: lastx = event.getrawx();// 获取触摸事件触摸位置的原始x坐标 lasty = event.getrawy(); originx = lastx; originy = lasty; break; case motionevent.action_move: float dx = event.getrawx() - lastx; float dy = event.getrawy() - lasty; windowmanagerparams.x += dx; windowmanagerparams.y += dy; logutil.d(tag, "移动距离:dx=" + dx + ",dy=" + dy); showallbtn(); lastx = (int) event.getrawx(); lasty = (int) event.getrawy(); break; case motionevent.action_up: float lastmovedx = math.abs(event.getrawx() - originx); float lastmovedy = math.abs(event.getrawy() - originy); logutil.d(tag, "松开时,移动距离:lastmovedx=" + lastmovedx + ", lastmovedy=" + lastmovedy); if (lastmovedx < 10 && lastmovedy < 10) { //移动距离太小,视为点击, return false; } else { updateviewlayout(event); isfirstclick = true; return true; } } return false; } /** * 显示整个图标 */ public void showallbtn() { windowmanagerparams.width = originwidth; windowmanagerparams.height = originwidth; setimageresource(res.drawable(context, "ipay_float_btn_bg")); windowmanager.updateviewlayout(this, windowmanagerparams); // 刷新显示 } /** * 悬浮按钮显示在左边 */ private void showinleft() { windowmanagerparams.x = 0; windowmanagerparams.width = originwidth / 2; windowmanagerparams.height = originwidth; setimageresource(res.drawable(context, "ipay_float_btn_left_hidden")); windowmanager.updateviewlayout(this, windowmanagerparams); // 刷新显示 } /** * 悬浮按钮显示在右边 */ private void showinright() { windowmanagerparams.width = originwidth / 2; windowmanagerparams.height = originwidth; windowmanagerparams.x = screenwidth - windowmanagerparams.width; setimageresource(res.drawable(context, "ipay_float_btn_right_hidden")); windowmanager.updateviewlayout(this, windowmanagerparams); // 刷新显示 } /** * 悬浮按钮显示在上面 */ private void showintop() { windowmanagerparams.y = 0; windowmanagerparams.width = originwidth; windowmanagerparams.height = originwidth / 2; setimageresource(res.drawable(context, "ipay_float_btn_top_hidden")); windowmanager.updateviewlayout(this, windowmanagerparams); // 刷新显示 } /** * 悬浮按钮显示在下面 */ private void showinbottom() { windowmanagerparams.width = originwidth; windowmanagerparams.height = originwidth / 2; windowmanagerparams.y = screenheight - windowmanagerparams.width; setimageresource(res.drawable(context, "ipay_float_btn_bottom_hidden")); windowmanager.updateviewlayout(this, windowmanagerparams); // 刷新显示 } /** * 更新悬浮图标 * * @param event 手动移动事件 */ public void updateviewlayout(motionevent event) { point center = new point(screenwidth / 2, screenheight / 2); //屏幕中心点 float xoffset, yoffset;//以屏幕中心点为原点,x轴和y轴上的偏移量 if (event != null) {//手动移动的 xoffset = event.getrawx() - center.x; yoffset = event.getrawy() - center.y; } else {//自动隐藏 xoffset = lastx - center.x; yoffset = lasty - center.y; } if (math.abs(xoffset) >= math.abs(yoffset)) {//向左或向右缩进隐藏 if (xoffset <= 0) { //向左缩进 showinleft(); } else { showinright(); } } else {//向上或向下缩进隐藏 if (yoffset <= 0) {//向上缩进 showintop(); } else { showinbottom(); } } } @override protected void onmeasure(int widthmeasurespec, int heightmeasurespec) { super.onmeasure(widthmeasurespec, heightmeasurespec); } @override protected void onlayout(boolean changed, int left, int top, int right, int bottom) { super.onlayout(changed, left, top, right, bottom); point screensize = displayutil.getscreensize(context); if (screenwidth != screensize.x) {//屏幕旋转切换 screenwidth = screensize.x; screenheight = screensize.y; lasty = windowmanagerparams.x; lastx = windowmanagerparams.y; windowmanagerparams.x = (int) lastx; windowmanagerparams.y = (int) lasty; updateviewlayout(null); } } private boolean isfirstclick = true; @override protected void ondraw(canvas canvas) { super.ondraw(canvas); } @override public void onclick(view v) { logutil.d(tag, "执行点击事件"); if (!isfirstclick) { openidapplication.getinstance().floatbtnclick(context, openidapplication.getinstance().isforcelogin(), resultcallback); } else {//半隐藏状态,点击显示全部 isfirstclick = false; showallbtn(); } } }
调用实现代码,这里注意有个问题,弹出系统级的悬浮窗,需要配置权限:
并且android 6.0以上的手机,还要弹出对话框问用户是否运行,如果这个用户拒绝了,就不能弹出系统级的悬浮窗了,还有个别手机厂商修改了android源码,还需要进系统设置里去允许这个应用弹出悬浮窗。这样的话就体验感非常不好,不过这里有个小技巧,按下面方式设置为toast类型就完全解决,既不用配置权限,也不弹出窗来向用户获取权限,完全解决问题。
windowmanager.layoutparams windowmanagerparams = new windowmanager.layoutparams(windowmanager.layoutparams.type_toast, windowmanager.layoutparams.flag_not_touch_modal | windowmanager.layoutparams.flag_not_focusable, pixelformat.translucent);
具体实现代码如下:
dragfloatactionbutton floatbtn = new dragfloatactionbutton(context, isforcelogin, mresultcallback); windowmanager windowmanager = (windowmanager) context.getsystemservice(context.window_service); // 设置layoutparams(全局变量)相关参数 windowmanager.layoutparams windowmanagerparams = new windowmanager.layoutparams(windowmanager.layoutparams.type_toast, windowmanager.layoutparams.flag_not_touch_modal | windowmanager.layoutparams.flag_not_focusable, pixelformat.translucent); /** * 注意,flag的值可以为: * 下面的flags属性的效果形同“锁定”。 * 悬浮窗不可触摸,不接受任何事件,同时不影响后面的事件响应。 * layoutparams.flag_not_touch_modal 不影响后面的事件 * layoutparams.flag_not_focusable 不可聚焦 * layoutparams.flag_not_touchable 不可触摸 */ // 调整悬浮窗口至左上角,便于调整坐标 windowmanagerparams.gravity = gravity.left | gravity.top; // 以屏幕左上角为原点,设置x、y初始值 windowmanagerparams.x = 0; windowmanagerparams.y = 0; // 设置悬浮窗口长宽数据 floatbtn.measure(0, 0); floatbtn.setoriginwidth(floatbtn.getmeasuredwidth() - 50); windowmanagerparams.width = floatbtn.getoriginwidth(); windowmanagerparams.height = windowmanagerparams.width; // 显示myfloatview图像 windowmanager.addview(floatbtn, windowmanagerparams);
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。