前文概要
连续四篇介绍了车载设置,主要都是和源码相关,还未看过的,可以参考借鉴学习一下源码知识。车载设置–按键提示音
本文开始进入下一个篇章,主要是和 camera 相关,例如倒车,TV ,360 全景等,其主要实现原理是基于 WindowManager 来显示全屏窗口,在窗口中加载 camera 传递的数据。基于此,有必要先介绍一下 WindowManager 和 camera 相关的知识点,本文先从 WindowManager 开始。
WindowManager 类结构
public interface WindowManager implements ViewManager
WindowManager 是窗口管理器,所有显示窗口都可以通过它来控制。通常我们调用的是 WindowManager 继承自基类的 addView 方法和 removeView 方法来显示和隐藏窗口:
- addView(View view, ViewGroup.LayoutParams params)
Assign the passed LayoutParams to the passed View and add the view to the window. 用于添加一个窗口 - removeView(View view) 移除一个窗口
- updateViewLayout(View view, ViewGroup.LayoutParams params) 更新窗口的参数
WindowManager 主要是通过 Context.getSystemService(Context.WINDOW_SERVICE) 来获取。
WindowManager.LayoutParams 参数介绍
WindowManager.LayoutParams 这个类用于提供悬浮窗所需的参数,其中有几个经常会用到的变量:
- x 值用于确定悬浮窗的位置,如果要横向移动悬浮窗,就需要改变这个值。
- y 值用于确定悬浮窗的位置,如果要纵向移动悬浮窗,就需要改变这个值。
- gravity 值用于确定悬浮窗的对齐方式及设置 x 和 y 值的参考系。
- format 值用于确定窗口背景遮罩位图格式,默认为黑色,一般设置为半透明 (PixelFormat.TRANSLUCENT)
- alpha 值用于确定这个窗口的透明值,1.0表示不透明,0.0表示全透明
- width 值用于指定悬浮窗的宽度。
- height 值用于指定悬浮窗的高度。
- type 值用于确定窗口在屏幕上的显示层次,值越高,显示层次越高。一般设为 TYPE_PHONE,表示在所有应用程序之上,但在状态栏之下。
- flags 值用于确定悬浮窗的行为,比如说不可聚焦,非模态对话框等等。
permission denied 解决办法
1.创建悬浮窗这种窗体需要向用户申请权限才可以的,因此还需要在 AndroidManifest.xml中加入 。
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
2.手机端设置允许调试应用在其他应用显示悬浮窗。例如有以下提示:
android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRootImpl$W@e604098 -- permission denied for window type 2038
at android.view.ViewRootImpl.setView(ViewRootImpl.java:806)
at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:373)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:114)
那么 将 type 改为TYPE_PHONE ,并且在手机端打开 权限管理–>悬浮窗管理–>调试应用勾选。
这样调试应用就能显示在其他应用之上。
悬浮窗示例
1. 对 WindowManager.LayoutParams 参数进行设置:
mWindo wManager = (WindowManager) getApplication().getSystemService(Context.WINDOW_SERVICE);
mLayoutParams = new WindowManager.LayoutParams();
// 设置悬浮窗显示层次,在应用层之上,状态栏之下
mLayoutParams.type = WindowManager.LayoutParams.TYPE_PHONE;
//悬浮窗遮罩背景 半透明
mLayoutParams.format = PixelFormat.TRANSLUCENT;
// 悬浮窗曲奇方式,以屏幕左上角对齐
mLayoutParams.gravity = Gravity.LEFT | Gravity.TOP;
mLayoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
mLayoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
//FLAG_NOT_TOUCH_MODAL不阻塞事件传递到后面的窗口
mLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
- 对小球增加拖动事件,主要是在 onTouch 方法中根据手指移动距离更新 WindowManager.LayoutParams 参数:
mLlRoot.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
mStartX = (int) event.getRawX();
mStartY = (int) event.getRawY();
break;
case MotionEvent.ACTION_MOVE:
mEndX = (int) event.getRawX();
mEndY = (int) event.getRawY();
//getRawX是触摸位置相对于屏幕的坐标,getX是相对于按钮的坐标
mLayoutParams.x = (int) event.getRawX() - mLlRoot.getMeasuredWidth() / 2;
mLayoutParams.y = (int) event.getRawY() - mLlRoot.getMeasuredHeight() / 2;
mWindowManager.updateViewLayout(mWindowView, mLayoutParams);
return true;
}
return false;
}
});
3.通过定时任务去获取 CPU 温度并显示出来:
private String getCputemp(){
String path = "/sys/class/thermal/thermal_zone0/temp";
StringBuffer sb = new StringBuffer();
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader(path));
String readline = "";
while ((readline = br.readLine()) != null) {
System.out.println("readline:" + readline);
sb.append(readline);
}
br.close();
Log.d("Bradley", "onCreate: "+sb.toString());
} catch (Exception e) {
e.printStackTrace();
}
return sb.toString();
}
总结
通过本文大致了解悬浮效果背后是通过 WindowManager 来添加 view 实现的,同时对 WindowManager.LayoutParams 参数有个大致了解,后续还会继续讲解 WindowManager 相关的文章,敬请期待!
happy a nice day!