获取刘海屏安全区域
// 获取刘海屏安全区域(Android P+)
private fun getDisplayCutoutInsets(): Rect {
val insets = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
window.decorView.rootWindowInsets?.displayCutout?.safeInsets
} else {
null
}
return insets ?: Rect(0, 0, 0, 0)
}
// 获取状态栏高度
private fun getStatusBarHeight(): Int {
var result = 0
val resourceId = resources.getIdentifier("status_bar_height", "dimen", "android")
if (resourceId > 0) {
result = resources.getDimensionPixelSize(resourceId)
}
return result
}
OpenClaw 适配刘海屏的解决方案
调整触摸区域
public class NotchAwareClawView extends View {
private OpenClaw openClaw;
private int notchHeight;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 初始化OpenClaw
openClaw = new OpenClaw(this);
// 获取刘海高度
notchHeight = getStatusBarHeight();
// 设置触摸监听
openClaw.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
// 调整触摸事件的Y坐标,避开刘海区域
MotionEvent adjustedEvent = MotionEvent.obtain(event);
float rawY = event.getRawY();
if (rawY < notchHeight) {
// 将刘海区域的触摸映射到有效区域
adjustedEvent.setLocation(event.getX(), notchHeight);
}
return openClaw.onTouch(v, adjustedEvent);
}
});
}
}
使用WindowInsetsListener(推荐)
// Android 11+ 使用WindowInsets API
ViewCompat.setOnApplyWindowInsetsListener(window.decorView) { view, windowInsets ->
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
val insets = windowInsets.getInsets(WindowInsets.Type.systemBars() or WindowInsets.Type.displayCutout())
// 设置OpenClaw的有效区域
val clawView = findViewById<View>(R.id.claw_view)
clawView.setPadding(
clawView.paddingLeft + insets.left,
clawView.paddingTop + insets.top,
clawView.paddingRight + insets.right,
clawView.paddingBottom + insets.bottom
)
// 设置OpenClaw的触摸边界
openClaw.setTouchableArea(
insets.left.toFloat(),
insets.top.toFloat(),
(screenWidth - insets.right).toFloat(),
(screenHeight - insets.bottom).toFloat()
);
}
windowInsets
}
配置OpenClaw的手势识别区域
public class NotchAdaptedClaw extends OpenClaw {
private Rect safeArea;
public NotchAdaptedClaw(Context context) {
super(context);
calculateSafeArea();
}
private void calculateSafeArea() {
// 计算安全区域(避开刘海)
DisplayMetrics metrics = getResources().getDisplayMetrics();
int statusBarHeight = getStatusBarHeight();
int navBarHeight = getNavigationBarHeight();
safeArea = new Rect(
0,
statusBarHeight,
metrics.widthPixels,
metrics.heightPixels - navBarHeight
);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
// 过滤掉刘海区域的触摸事件
if (event.getY() < safeArea.top) {
return false; // 忽略刘海区域的触摸
}
return super.onTouchEvent(event);
}
@Override
public boolean isPointInTouchableArea(float x, float y) {
// 重写触摸区域判断
return safeArea.contains((int) x, (int) y);
}
}
刘海屏全屏适配
// Activity中启用全屏并处理刘海
private void setupFullScreenWithNotch() {
// 启用全屏
window.decorView.systemUiVisibility = (
View.SYSTEM_UI_FLAG_FULLSCREEN |
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
)
// 允许内容延伸到刘海区域(Android P+)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
val layoutParams = window.attributes
layoutParams.layoutInDisplayCutoutMode =
WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
window.attributes = layoutParams
}
// 为OpenClaw设置边距
val clawLayout = findViewById<FrameLayout>(R.id.claw_layout)
clawLayout.setOnApplyWindowInsetsListener { view, insets ->
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
val cutout = insets.displayCutout
if (cutout != null) {
val safeInsets = cutout.safeInsets
// 调整OpenClaw的布局边距
view.setPadding(
safeInsets.left,
safeInsets.top,
safeInsets.right,
safeInsets.bottom
)
// 更新OpenClaw的触摸边界
openClaw.updateTouchBoundary(
safeInsets.left,
safeInsets.top,
view.width - safeInsets.right,
view.height - safeInsets.bottom
)
}
}
insets
}
}
厂商特定适配
// 检查是否为特定厂商的刘海屏
public static boolean isNotchDevice(Context context) {
// 小米
if (Build.MANUFACTURER.equalsIgnoreCase("Xiaomi")) {
return Settings.Global.getInt(context.getContentResolver(),
"force_black", 0) == 1;
}
// 华为
if (Build.MANUFACTURER.equalsIgnoreCase("HUAWEI")) {
try {
ClassLoader cl = context.getClassLoader();
Class HwNotchSizeUtil = cl.loadClass("com.huawei.android.util.HwNotchSizeUtil");
Method get = HwNotchSizeUtil.getMethod("hasNotchInScreen");
return (boolean) get.invoke(HwNotchSizeUtil);
} catch (Exception e) {
return false;
}
}
// OPPO
if (Build.MANUFACTURER.equalsIgnoreCase("OPPO")) {
return context.getPackageManager().hasSystemFeature("com.oppo.feature.screen.heteromorphism");
}
// VIVO
if (Build.MANUFACTURER.equalsIgnoreCase("VIVO")) {
try {
ClassLoader cl = context.getClassLoader();
Class ftFeature = cl.loadClass("android.util.FtFeature");
Method get = ftFeature.getMethod("isFeatureSupport", int.class);
return (boolean) get.invoke(ftFeature, 0x00000020);
} catch (Exception e) {
return false;
}
}
return false;
}
配置建议
- 测试不同设备:在不同厂商的刘海屏设备上测试
- 动态适配:使用WindowInsets API进行动态适配
- 向后兼容:为Android P以下版本提供fallback方案
- 手势边界:确保手势识别区域避开刘海区域
- 用户体验:考虑刘海对多指操作的影响,适当调整手势灵敏度
这些方法可以确保OpenClaw在各种刘海屏设备上都能正常工作,提供良好的用户体验。

版权声明:除非特别标注,否则均为本站原创文章,转载时请以链接形式注明文章出处。