From 06bb7bcd1cc382e0b52fada1c5fc6676f75ff693 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=91=E5=8D=9A=E6=96=87?= <1323515022@qq.com> Date: Mon, 2 Nov 2026 16:53:27 +0800 Subject: [PATCH] =?UTF-8?q?feat(android):=20=E6=8E=A7=E4=BB=B6=E6=B5=AE?= =?UTF-8?q?=E5=B1=82=E5=8C=96=E2=80=94=E2=80=94statusView/sensBar/controlB?= =?UTF-8?q?ar=20=E7=A7=BB=E5=85=A5=20stage=20=E5=BA=95=E9=83=A8=E5=8F=A0?= =?UTF-8?q?=E5=8A=A0=E5=B1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 三个控件原是 stage 的垂直兄弟节点,显示即抢高度,于是 surfaceView 的 letterbox 几何跟着变:横屏实测控件可见时画面 1216x684、隐藏时 1920x1080, 即用户感知的「一按按钮画面就被挤小」。 改为 stage 内的 chromeOverlay(LinearLayout,Gravity.BOTTOM, WRAP_CONTENT,底色 0x99000000 半透明):画面尺寸现在与控件显隐无关。 setControlsVisible 仍统一 GONE 三个子视图,容器随之塌成 0 高,隐藏态与 改动前逐字节等价,4a 的黑边唤出逻辑一行未动。 不碰解码、触摸映射、协议与 CursorOverlayView。竖屏实测 stage 高 2069 (等于内容区高度)、画面恒定 1080x607,连续 4 次采样无差异;横屏可见态与 隐藏态画面均为 1920x1080;R7 绝对映射三点误差 1px/0px/1px;JVM 60 例全绿。 --- .../kotlin/com/verify/remote/MainActivity.kt | 45 ++++++++++++++++--- 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/apps/android-viewer/app/src/main/kotlin/com/verify/remote/MainActivity.kt b/apps/android-viewer/app/src/main/kotlin/com/verify/remote/MainActivity.kt index f318f85..0c267bc 100644 --- a/apps/android-viewer/app/src/main/kotlin/com/verify/remote/MainActivity.kt +++ b/apps/android-viewer/app/src/main/kotlin/com/verify/remote/MainActivity.kt @@ -56,6 +56,12 @@ class MainActivity : Activity(), RemoteSurfaceView.Listener { /** 4a:横屏自动隐藏的两个控制条(Q3=A)+ 状态行 */ private lateinit var controlBar: LinearLayout private lateinit var sensBar: LinearLayout + /** + * 循环 5:三个控件的**浮层容器**,是 [stage] 的底部叠加子视图——不再是画面 + * 的垂直兄弟。`setControlsVisible` 把三个视图一起 GONE,容器 WRAP_CONTENT + * 随之塌成 0 高,于是 stage / 画面的 letterbox 几何与控件显隐**无关**。 + */ + private lateinit var chromeOverlay: LinearLayout @Volatile private var handle = 0L @@ -301,7 +307,9 @@ class MainActivity : Activity(), RemoteSurfaceView.Listener { statusView = TextView(this).apply { textSize = 12f setPadding(dp(12), dp(6), dp(12), dp(6)) - setBackgroundColor(0xCC000000.toInt()) + // 循环 5:底色统一移到浮层容器(chromeOverlay)上,这里保持透明—— + // 两层半透明黑叠加会让浮层比设计值明显更黑。 + setBackgroundColor(android.graphics.Color.TRANSPARENT) setTextColor(0xFFFFFFFF.toInt()) maxLines = 3 } @@ -423,16 +431,34 @@ class MainActivity : Activity(), RemoteSurfaceView.Listener { addView(sensLabel, LayoutParams(0, LayoutParams.WRAP_CONTENT, 1f)) addView(sensUpButton, LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)) } - return LinearLayout(this).apply { + // 循环 5/Q2=A:三个控件收进浮层容器,作为 stage 的**底部叠加层**。 + // 为什么必须这样:它们是 stage 的垂直兄弟时,显示即抢高度 → surfaceView + // 的 letterbox 几何跟着变(横屏实测可见态画面 1216x684、隐藏态 1920x1080, + // 即"一按按钮画面就被挤小")。改成 stage 的子视图后,画面尺寸与控件显隐无关。 + // + // 半透明底放在**容器**上而不是各条上:一次绘制、一层叠色,且 GONE 时整层 + // 一起消失(三个子视图仍由 setControlsVisible 统一 GONE,容器纵向塌成 0)。 + chromeOverlay = LinearLayout(this).apply { orientation = LinearLayout.VERTICAL - visibility = View.GONE - addView(stage, LayoutParams(LayoutParams.MATCH_PARENT, 0, 1f)) - // 固定高度而非 WRAP_CONTENT:与 weight=1 的兄弟共存时, - // WRAP_CONTENT 可能被压成 0(实测 bounds=[0,0][0,0],状态栏不可见) + setBackgroundColor(CHROME_OVERLAY_BG) addView(statusView, LayoutParams(LayoutParams.MATCH_PARENT, dp(64))) addView(sensBar, LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)) addView(controlBar, LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)) } + stage.addView( + chromeOverlay, + FrameLayout.LayoutParams( + FrameLayout.LayoutParams.MATCH_PARENT, + FrameLayout.LayoutParams.WRAP_CONTENT, + Gravity.BOTTOM, + ), + ) + return LinearLayout(this).apply { + orientation = LinearLayout.VERTICAL + visibility = View.GONE + // 画面撑满整个远控面板:控件的显隐不再参与垂直分配。 + addView(stage, LayoutParams(LayoutParams.MATCH_PARENT, 0, 1f)) + } } private fun prefs() = getSharedPreferences(PREFS, Context.MODE_PRIVATE) @@ -1015,6 +1041,13 @@ class MainActivity : Activity(), RemoteSurfaceView.Listener { /** 4a/Q7=A:横屏无操作隐藏控制条的延时 */ private const val CONTROLS_HIDE_MS = 3000L + /** + * 循环 5/Q2=A:控件浮层底色——60% 黑。半透明是为了让被覆盖的画面仍然可辨 + * (横屏画面占满 stage 高度,浮层必然盖住底部;透明度是可读性与不遮挡的折中)。 + * 只用在这一处(容器上),各控件自身保持默认/透明底。 + */ + private const val CHROME_OVERLAY_BG = 0x99000000.toInt() + /** * 与协议版本保持一致:远控画面状态栏显示当前握手版本(方案 R5 要求)。 * 值随 `common::PROTO_VERSION` 人工同步——Android 侧不做线格式解析,