android 悬浮窗教程
悬浮窗教程,很简单。知识点不多,写下来 总结一下。
权限
首先 是在AndroidManiFest.xml 定义权限
如果 Android版本大于6.0 ,还需要引导用户 同意这个权限才行。并不是 你定义了就会给你的。
//判断是否 有悬浮窗的权限 if (!Settings.canDrawOverlays(getApplicationContext())) { Intent alertOver = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())); //这个页面不会返回值 所以用这个 startActivity(alertOver); }
创建悬浮窗
下面这段代码 ,你可以直接复制到你的项目里面 运行。记得要申请权限!!!!
@SuppressLint("ClickableViewAccessibility") void initShow() { //获取服务 WindowManager windowManager = (WindowManager) getSystemService(WINDOW_SERVICE); // 设定参数 WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(); //Android 8 对悬浮窗 进行了 改变 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; } else { layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE; } //设置位图格式 默认是不透明的 layoutParams.format = PixelFormat.TRANSPARENT; //设置宽 高 可以是MATCH_PARENT ,WRAP_CONTENT ,或者 确切的数值 layoutParams.width =300; layoutParams.height = 300; //设置悬浮窗 位置,这个受layoutParams.gravity 影响,它提供了从给定边缘的偏移量。 // 也就是说 这个悬浮窗的实际x,y位置。是这里x,y 加上偏移量后的。 layoutParams.x = 300; layoutParams.y = 300; //View以外的区域可以响应点击和触摸事件 layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; //容器与小部件之间的水平边距,作为容器宽度的百分比。 // 通俗的讲 ,就是悬浮窗会在 x,y位置的那个方向,影响 layoutParams.x ,layoutParams.y的偏移量 //这个默认是AXIS_X_SHIFT NO_GRAVITY //将悬浮窗原点坐标系与屏幕重合 就是 把悬浮窗变成和普通view一样 都是以左上角为原点 //这个很重要 layoutParams.gravity = Gravity.LEFT | Gravity.TOP; //创建view 就是悬浮窗里面的内容 TextView textView = new android.support.v7.widget.AppCompatTextView(getApplicationContext()){ @Override public boolean performClick() { return super.performClick(); } }; textView.setText("我是悬浮窗"); //给view添加触摸事件,来使用悬浮窗可以移动 textView.setOnTouchListener(new View.OnTouchListener() { //这个用于保存 当手指按下时候,离悬浮窗左上角的 x,y距离,这里设定初始值 是悬浮窗宽高的一半 float inX =layoutParams.width>>1, inY = layoutParams.height>>1; @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: //得到 点击位置 在悬浮窗中的位置 inX = event.getX(); inY = event.getY(); break; case MotionEvent.ACTION_MOVE: //得到当前滑动位置,在整个屏幕上面的坐标 float nowX = event.getRawX(); float nowY = event.getRawY(); Zprint.log(this.getClass()," inX inY",inX,inY,nowX,nowY); //屏幕X坐标 减去 点击时候 在悬浮窗中的位置 X 距离 layoutParams.x= (int) (nowX-inX); //屏幕高度坐标 要注意 状态栏高度 layoutParams.y = (int) (nowY-statusHeight-inY); //更新悬浮窗 位置 windowManager.updateViewLayout(textView, layoutParams); break; } return false; } }); //这下面代码只是说明 在悬浮窗里面的view 与在activity里面的view ,没有任何不同 textView.setOnClickListener(v -> textView.setText("点击了")); textView.setBackgroundColor(getColor(android.R.color.darker_gray)); //添加view windowManager.addView(textView, layoutParams); }
首先,是获得windowManager,设置activity的宽高 也是通过这个类来实现的。获取这个实例的方式是通过getSystemService(WINDOW_SERVICE)。在activity中的 也可以通过getWindowManager()来获取。
接着,就new 一个WindowManager.LayoutParams 布局参数。这个主要设置 悬浮窗的大小,类型(注意Android8),位置,位图之类的。上面 解释很清楚。如果不懂的 评论。
其次,就可以创建一个View 填充悬浮窗的内容。这个View既可以动态生成,也可以用xml写好,再用 LayoutInflater 实例出来。这个View和在activity中的view 并没有什么区别!!!
最后 调用添加view就可以了。
更新悬浮窗位置
使用windowManager.updateViewLayout(View, ViewGroup.LayoutParams);来更新悬浮窗的位置。我们可以给悬浮窗里面的view 添加触摸事件 ,来获取触摸位置,更新悬浮窗,我上面那段触摸事件 可以实现当你按住悬浮窗任意一个位置时候,拖动悬浮窗,离开悬浮窗时候,手指最后离开悬浮窗中的位置是和一开始按住悬浮窗中的位置 是一样的。
要注意 状态栏高度,ViewGroup.LayoutParams的x,y坐标是以状态栏和屏幕左边的交点为原点的。而getRaxY() 得到的是距离屏幕左上角的x,y坐标。
获取状态栏高度:
public int getStatusBarHeight() { //局部变量 声明后,要赋值,不像成员变量会有默认值 int result = 0; int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android"); if (resourceId > 0) { result = getResources().getDimensionPixelSize(resourceId); } return result; }
更新悬浮窗内容
更新悬浮窗内容,就和在activity中更新view一样。找到view的实例进行更新view即可。记住要在主线程中
附 得到Android主线程
//handler 持有主线程的looper private Handler mainHandler = new Handler(getMainLooper(), new Handler.Callback() { @Override public boolean handleMessage(Message msg) { //这里接收处理mainHandler 发送来的message //在这里写实际在主线程中运行的代码 return false; } }); //在你要更新view的地方,或者需要主线程操作的地方 发送message mainHandler.sendMessage(Message);
如果 你感觉上面代码 还是繁琐,也可以调用handler的post(Runnable)方法
mainHandler.post(Runnable r)
更多相关文章
- ubuntu环境下我的第一个android apk (2014.12.12更新)
- 自己祝贺一下访问量突破10000,发几个android的资料介绍(持续更新)
- 自己祝贺一下访问量突破10000,发几个android的资料介绍(持续更新)
- 如何申请 android google map API key
- Android移动view动画问题
- android异步更新UI
- 更新Anadroid SDK Tooks之后,Eclipse提示No update were found
- Android(安卓)更改 Toast 的默认位置及自定义Toast
- 更新Anadroid SDK Tooks之后,Eclipse提示No update were found