fix(design,app-iced): 图标尺寸与禁用 α 收敛到官方字节码,两族拆开(M86)
图标:IconSize::Button 16→18(AAR ButtonDefaults.<clinit> 的 bipush 18);新增 IconSize::SwitchThumb=16(SwitchTokens.Selected/UnselectedIconSize)承接开关滑块,按钮与 滑块不再借同一档;IconSize::Nav 的值不动但文档订正(无消费,官方导航/列表图标是 24)。 ButtonSmallTokens.IconSize=20 在整包 AAR 里零消费(javap 搜 getIconSize 无外部调用), 是死令牌,不再作为取值依据。 禁用 α:官方本来就分两族——按钮容器 0.10(*ButtonTokens.DisabledContainerOpacity)与 面状控件 0.12(chip 描边 / slider 轨道 / switch 轨道)。原来的缺陷是一个全局 12% 同时 服务两族(按钮那半边一直错、另半边一直对),现拆成 disabled_button_colors/…_content 与 disabled_colors/disabled_content_over_role 两个入口;interaction 首次超 400 行, 禁用口径与测试搬到 interaction/disabled.rs。 标题栏 caption 三键:官方 SmallIconButtonTokens.IconSize=24,按用户点名缩到 20 (容器 46×48 不动),登记为项目偏离;icons.rs 加按令牌取尺寸的入口 view_at,按 (种类,尺寸) 分别烘焙 SVG,20px 的 stroke 取 1.8 保视觉线宽 1.5px。
This commit is contained in:
1 parent
c825e1aa3d
commit
b566097107
16 files changed
+664
-175
No files matched your search
@@ -38,14 +38,37 @@ impl StateLayer {
|
||||
}
|
||||
}
|
||||
|
||||
/// 禁用态的透明度(M3):容器 12%、内容 38%。
|
||||
/// 禁用态的透明度(M3):**按钮家族**容器 10%、内容 38%。
|
||||
///
|
||||
/// 别用「灰化」近似——深色模式下灰化会降低对比度,alpha 叠加两种模式都成立。
|
||||
pub const DISABLED_CONTAINER_ALPHA: f32 = 0.12;
|
||||
///
|
||||
/// ⚠️ 官方禁用 α 分**两类**,这个常量只属于第一类:
|
||||
/// - **按钮容器 10%**:`BaselineButtonTokens` / `FilledButtonTokens` / `OutlinedButtonTokens` /
|
||||
/// `TextButtonTokens` / `ElevatedButtonTokens` / `TonalButtonTokens` 的 `DisabledContainerOpacity`
|
||||
/// = `0.1f`(AAR 字节码);
|
||||
/// - **面状控件(chip 容器/描边、slider 轨道、switch 轨道)12%**:那是另一类令牌
|
||||
/// (`AssistChipTokens.FlatDisabledOutlineOpacity` / `SliderTokens.DisabledInactiveTrackOpacity` /
|
||||
/// `SwitchTokens.DisabledTrackOpacity` = `0.12f`),口径在
|
||||
/// `unlucky_app_iced::components::interaction::disabled_colors`。
|
||||
///
|
||||
/// 曾经的缺陷不是「12 是错的」,而是**同一个常量同时服务这两类**:按钮那半边一直错、另半边一直对。
|
||||
pub const DISABLED_CONTAINER_ALPHA: f32 = 0.10;
|
||||
/// 禁用态内容(文字/图标)透明度。
|
||||
pub const DISABLED_CONTENT_ALPHA: f32 = 0.38;
|
||||
|
||||
/// 禁用态容器色:`on_surface` 12% 叠在 `surface` 上。
|
||||
/// 禁用态的透明度(M3):**面状控件族**容器与描边 12%。
|
||||
///
|
||||
/// 这一族是「一整面涂上去的容器或用它画出来的描边/轨道」,官方 token 各写一份但值统一是 `0.12f`:
|
||||
/// `AssistChipTokens.FlatDisabledOutlineOpacity`、`FilterChipTokens.FlatDisabledSelectedContainerOpacity`
|
||||
/// / `FlatDisabledUnselectedOutlineOpacity`、`SliderTokens.DisabledInactiveTrackOpacity`、
|
||||
/// `SwitchTokens.DisabledTrackOpacity`(AAR 字节码 `<clinit>`)。
|
||||
///
|
||||
/// **不适用于按钮容器**:按钮是 [`DISABLED_CONTAINER_ALPHA`](10%,`*ButtonTokens.DisabledContainerOpacity`)。
|
||||
/// 更不适用于 TextField 的 Filled 容器——那是 `FilledTextFieldTokens.FieldDisabledContainerOpacity = 0.04f`,
|
||||
/// 我们仍在用 12%(既有 D10 偏离,未在本轮收口)。
|
||||
pub const DISABLED_SURFACE_ALPHA: f32 = 0.12;
|
||||
|
||||
/// 禁用态容器色:`on_surface` 10%(按钮家族的 `DisabledContainerOpacity`)叠在 `surface` 上。
|
||||
pub fn disabled_container(scheme: &super::Scheme) -> Color {
|
||||
scheme
|
||||
.get(super::Role::OnSurface)
|
||||
|
||||
@@ -27,8 +27,8 @@
|
||||
//! `render_px / VIEWBOX` 缩放。同样的 `1.5` 在 20px 渲染下只有 1.25px 视觉宽度。
|
||||
//!
|
||||
//! 因此 iced 侧必须**按 SVG 语义重算**:要保持 1.5px 视觉线宽,viewBox 里的 stroke-width 得取
|
||||
//! `1.5 × 24 / render_px`(20px → 1.8、16px → 2.25、24px → 1.5)。[`Icon::stroke_width`] 就是这个
|
||||
//! 换算的纯函数——**不要在适配层手抄 1.5 这个数**,那是 Slint 口径。
|
||||
//! `1.5 × 24 / render_px`(24px → 1.5、20px → 1.8、18px → 2.0、16px → 2.25)。[`Icon::stroke_width`]
|
||||
//! 就是这个换算的纯函数——**不要在适配层手抄 1.5 这个数**,那是 Slint 口径。
|
||||
|
||||
mod glyphs;
|
||||
mod kinds;
|
||||
@@ -66,15 +66,38 @@ pub enum IconPaint {
|
||||
}
|
||||
|
||||
/// 图标的标准渲染尺寸(页面只从这几档里取,不许自定义零散值)。
|
||||
///
|
||||
/// ## 每一档服务于哪个规格(出处全部是 A 级:`material3-android-1.4.0.aar` 的字节码)
|
||||
///
|
||||
/// 判据顺序固定为:**先看官方组件实际消费哪个值,再看 token 类里写了什么**。两者冲突时以
|
||||
/// 「有消费者的那个」为准——1.4.0 里 `ButtonSmallTokens.IconSize = 20` 就是**零消费者**的死令牌
|
||||
/// (`javap` 全 AAR 搜 `getIconSize` 调用,没有任何类读它;`ButtonDefaults` 只借了同一
|
||||
/// token 类的 `IconLabelSpace` / `ContainerHeight` / `ContainerShapeRound`)。
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum IconSize {
|
||||
/// 12px:行内小图标(徽标内)。
|
||||
Inline,
|
||||
/// 16px:按钮/标题栏按钮。
|
||||
/// 16px:**控件内微字形**——Switch 滑块内的勾/图标。
|
||||
///
|
||||
/// A 级:`SwitchTokens.SelectedIconSize = 16.0d` / `UnselectedIconSize = 16.0d`。
|
||||
/// 别拿它当按钮图标用:按钮是 18(见 [`IconSize::Button`]),两者在官方是两个 token。
|
||||
SwitchThumb,
|
||||
/// 18px:**按钮内前置/后置图标**,也用于 Chip 图标。
|
||||
///
|
||||
/// A 级:`ButtonDefaults.<clinit>` 里 `bipush 18` → `IconSize = 18.dp`(12b 1.6 引的
|
||||
/// `ButtonDefaults.IconSize=18` 就是这一行);`AssistChipTokens.IconSize = 18.0d`(12b 13.4)。
|
||||
/// 死令牌说明:`BaselineButtonTokens.IconSize` / `ButtonSmallTokens.IconSize` 都写 20,
|
||||
/// 但 AAR 里没有任何类调用它们的 `getIconSize`(`FilledTonalButtonTokens` 反而是 18)。
|
||||
Button,
|
||||
/// 20px:导航项、列表行。
|
||||
/// 20px:**目录档,当前无消费**。
|
||||
///
|
||||
/// ⚠️ 别按名字拿它当导航/列表图标:官方导航轨与列表行的图标是 **24**
|
||||
/// (`AppBarTokens.IconSize = 24.0d`、12b 5.5 / 4.4),实现侧也一直是 24([`IconSize::Toolbar`])。
|
||||
/// 标题栏 caption 按钮的 20 不是这一档,见 [`TITLEBAR_CAPTION_ICON_PX`](那是项目偏离)。
|
||||
Nav,
|
||||
/// 24px:卡片头、工具栏。
|
||||
/// 24px:卡片头、工具栏、IconButton、标题栏 caption(官方口径)。
|
||||
///
|
||||
/// A 级:`SmallIconButtonTokens.IconSize = 24.0d`(12b 2.2 / 16.5)、`AppBarTokens.IconSize = 24.0d`。
|
||||
Toolbar,
|
||||
/// 32px:空态图标块。
|
||||
Empty,
|
||||
@@ -85,7 +108,8 @@ impl IconSize {
|
||||
pub const fn px(self) -> f32 {
|
||||
match self {
|
||||
IconSize::Inline => 12.0,
|
||||
IconSize::Button => 16.0,
|
||||
IconSize::SwitchThumb => 16.0,
|
||||
IconSize::Button => 18.0,
|
||||
IconSize::Nav => 20.0,
|
||||
IconSize::Toolbar => 24.0,
|
||||
IconSize::Empty => 32.0,
|
||||
@@ -93,8 +117,9 @@ impl IconSize {
|
||||
}
|
||||
|
||||
/// 全部档位,由小到大。
|
||||
pub const ALL: [IconSize; 5] = [
|
||||
pub const ALL: [IconSize; 6] = [
|
||||
IconSize::Inline,
|
||||
IconSize::SwitchThumb,
|
||||
IconSize::Button,
|
||||
IconSize::Nav,
|
||||
IconSize::Toolbar,
|
||||
@@ -102,6 +127,17 @@ impl IconSize {
|
||||
];
|
||||
}
|
||||
|
||||
/// 标题栏 caption 按钮(最小化 / 最大化 / 关闭)的图标边长——**用户点名的项目偏离**。
|
||||
///
|
||||
/// 官方 `SmallIconButtonTokens.IconSize = 24.0d`(AAR 字节码,12b 16.5 同值),我们的 24
|
||||
/// **本来就是对的**,所以这条不是「对齐规范」,是业主主观调整:用户原话「右上角三个金刚键的
|
||||
/// 图标显示稍大了些,能不能在**保持其容器尺寸不变**的前提下把图标改小些」。
|
||||
///
|
||||
/// 约束:**容器不动**(46×48 仍来自 `LayoutMetrics::titlebar_button_width` /
|
||||
/// `titlebar_height`),只缩图标;且这条**只适用于 caption 三键**,不许扩散到导航/卡片/表单的
|
||||
/// 24px 图标(那些是 12b 2.2 / 4.4 / 5.5 / 9.6 / 16.5 的判据)。
|
||||
pub const TITLEBAR_CAPTION_ICON_PX: f32 = 20.0;
|
||||
|
||||
/// 一个图标的几何数据。
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct Icon {
|
||||
@@ -248,4 +284,59 @@ mod tests {
|
||||
assert!(!IconKind::Plus.icon().has_curves());
|
||||
assert!(!IconKind::ChevronDown.icon().has_curves());
|
||||
}
|
||||
|
||||
/// 每一档的像素值都被**钉在官方出处**上:改值必须同时改这条测试,改的人会看到出处。
|
||||
///
|
||||
/// 这不是「断言一个常量等于它自己」——它断言的是「我们读到的官方值」,
|
||||
/// 所以下一个人按 `research/12b` 或按某个 token 类把 18 改回 16/20 时,这条会红并打印出处。
|
||||
#[test]
|
||||
fn icon_sizes_are_pinned_to_their_official_sources() {
|
||||
// A 级:ButtonDefaults.<clinit> 的 `bipush 18` → IconSize = 18.dp
|
||||
// (`AssistChipTokens.IconSize = 18.0d` 同值)。
|
||||
assert_eq!(
|
||||
IconSize::Button.px(),
|
||||
18.0,
|
||||
"按钮/Chip 图标 18:AAR ButtonDefaults.IconSize(12b 1.6 同值)。\
|
||||
ButtonSmallTokens.IconSize=20 是零消费者的死令牌,不要按它改回去"
|
||||
);
|
||||
// A 级:SwitchTokens.SelectedIconSize / UnselectedIconSize = 16.0d
|
||||
assert_eq!(
|
||||
IconSize::SwitchThumb.px(),
|
||||
16.0,
|
||||
"Switch 滑块图标 16:AAR SwitchTokens.Selected/UnselectedIconSize"
|
||||
);
|
||||
// A 级:SmallIconButtonTokens.IconSize / AppBarTokens.IconSize = 24.0d
|
||||
assert_eq!(
|
||||
IconSize::Toolbar.px(),
|
||||
24.0,
|
||||
"IconButton/标题栏/卡片头 24:AAR SmallIconButtonTokens / AppBarTokens"
|
||||
);
|
||||
// 目录档(当前无消费):不许被当成 nav 图标用(nav 是 24)。
|
||||
assert_eq!(IconSize::Nav.px(), 20.0, "目录档 20(无消费)");
|
||||
assert_eq!(IconSize::Inline.px(), 12.0);
|
||||
assert_eq!(IconSize::Empty.px(), 32.0);
|
||||
}
|
||||
|
||||
/// 标题栏 caption 的 20 是**项目偏离**,不是规范值;这条把「偏离的是哪两个数」钉住。
|
||||
#[test]
|
||||
fn titlebar_caption_icon_is_a_registered_deviation() {
|
||||
assert_eq!(
|
||||
TITLEBAR_CAPTION_ICON_PX, 20.0,
|
||||
"用户点名的偏离:官方 SmallIconButtonTokens.IconSize = 24,caption 三键缩到 20"
|
||||
);
|
||||
// 绑定成局部变量再过断言:直接比两个常量会被 clippy 判成「常量断言」(assertions_on_constants)。
|
||||
let caption = TITLEBAR_CAPTION_ICON_PX;
|
||||
let official = IconSize::Toolbar.px();
|
||||
assert!(
|
||||
caption < official,
|
||||
"偏离方向是「更小」:{caption} 应 < 官方 {official};若哪天反了,那就不是用户要的那件事了"
|
||||
);
|
||||
// 20px 渲染时视觉线宽仍是 1.5(SVG 语义),这条防「缩图标顺手把线宽也带细」。
|
||||
let stroke = stroke_width_for(caption, VISUAL_STROKE_PX);
|
||||
assert!(
|
||||
(stroke - 1.8).abs() < 1.0e-6,
|
||||
"20px 渲染应取 1.8 个 viewBox 单位"
|
||||
);
|
||||
assert!((visual_stroke_px(caption, stroke) - VISUAL_STROKE_PX).abs() < 1.0e-6);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user