From 0c9d4049b39c68f0d436efa51a35661c06e33abc Mon Sep 17 00:00:00 2001 From: AskaEth Date: Mon, 2 Nov 2026 06:55:31 +0800 Subject: [PATCH] =?UTF-8?q?fix(selection):=20Checkbox=20/=20Radio=20?= =?UTF-8?q?=E5=91=BD=E4=B8=AD=E5=8C=BA=E6=81=92=2048=C3=9748=EF=BC=88?= =?UTF-8?q?=E5=A4=8D=E5=AE=A1=20P2-2=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 无标签时行宽只有状态层的 40dp(A1 的 minimumInteractiveComponentSize 是 48) - ControlGeometry::hit_padding() = (48−40)/2 = 4,view 侧左右各留这段透明内边距 - 单测钉住 40 + 2×4 == 48(checkbox 与 radio 各一遍) --- .../app-iced/src/components/selection/checkbox.rs | 13 ++++++++++--- .../app-iced/src/components/selection/geometry.rs | 9 +++++++++ crates/app-iced/src/components/selection/radio.rs | 11 +++++++++-- 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/crates/app-iced/src/components/selection/checkbox.rs b/crates/app-iced/src/components/selection/checkbox.rs index b20c20c..41a7d69 100644 --- a/crates/app-iced/src/components/selection/checkbox.rs +++ b/crates/app-iced/src/components/selection/checkbox.rs @@ -11,7 +11,7 @@ //! 里面套一个 40 的圆容器,再套 20 的方框(见 `shell` 的模块文档)。 use iced::widget::{container, row, text}; -use iced::{Alignment, Element, Length}; +use iced::{Alignment, Element, Length, Padding}; use unlucky_design::typography::TypeRole; @@ -164,10 +164,17 @@ pub fn checkbox<'a, M: Clone + 'a>(ui: &'a Ui, spec: Checkbox<'a, M>) -> Element ); } - // 命中区 48:方框 20 + 状态层 40 都在里面垂直居中 + // 命中区 48:方框 20 + 状态层 40 都在里面垂直居中; + // 左右各留 `hit_padding` 透明内边距,无标签时命中区也是 48×48(复审 P2-2) + let pad = geometry.hit_padding(); let body = container(content) .height(Length::Fill) - .align_y(Alignment::Center); + .align_y(Alignment::Center) + .padding(Padding { + left: pad, + right: pad, + ..Padding::default() + }); shell::shell( &source, diff --git a/crates/app-iced/src/components/selection/geometry.rs b/crates/app-iced/src/components/selection/geometry.rs index 4914a0d..d0a081b 100644 --- a/crates/app-iced/src/components/selection/geometry.rs +++ b/crates/app-iced/src/components/selection/geometry.rs @@ -96,6 +96,15 @@ impl ControlGeometry { } } + /// 命中区比可见状态层宽出来的部分(左右**各一份**):`(48 − 40) / 2 = 4`。 + /// + /// 无标签时行宽只有状态层的 40dp,命中区就少 8dp;A1 的 + /// `minimumInteractiveComponentSize` 是 **48**,所以 view 侧左右各留这段透明内边距 + /// (复审 P2-2)。有标签时行宽本来 ≥48,这段内边距不改变结论,只是保持两处口径一致。 + pub fn hit_padding(&self) -> f32 { + (self.hit - self.state_layer) / 2.0 + } + /// 勾形横向端点跨度(20 画布内 0.2→0.8):`[源]` `Checkbox.kt:496-514` 的路径比例。 /// /// 这是 research/15 §25 明确允许的「组件级常量」(路径比例 0.2/0.4/0.5/0.7/0.8 不进令牌层)。 diff --git a/crates/app-iced/src/components/selection/radio.rs b/crates/app-iced/src/components/selection/radio.rs index f0fb6e0..64680cd 100644 --- a/crates/app-iced/src/components/selection/radio.rs +++ b/crates/app-iced/src/components/selection/radio.rs @@ -15,7 +15,7 @@ //! 内点:独立 10×10 圆容器居中在环里(绘制半径 12/2 − 2/2 = 5,即**直径 10**,§19.2)。 use iced::widget::{container, row, text}; -use iced::{Alignment, Element, Length}; +use iced::{Alignment, Element, Length, Padding}; use unlucky_design::typography::TypeRole; @@ -134,9 +134,16 @@ pub fn radio<'a, M: Clone + 'a>(ui: &'a Ui, spec: Radio<'a, M>) -> Element<'a, M ); } + // 命中区 48×48:左右各留 `hit_padding` 透明内边距(无标签时行宽才不是 40;复审 P2-2) + let pad = geometry.hit_padding(); let body = container(content) .height(Length::Fill) - .align_y(Alignment::Center); + .align_y(Alignment::Center) + .padding(Padding { + left: pad, + right: pad, + ..Padding::default() + }); shell::shell( &source,