跨端: 按压反馈内联进基础玻璃卡 —— 18 个站点从 1 个变全部(基础组件自带动画)
用户问过两次:
·「各个组件带响应点击、滑动的动画了吗」
·「基础组件包含动画」
之前按压反馈是**单独一个 modifier**,要靠调用点自己叠:
CompositeModifier.of([GlassCardModifier.of(x), PressFeedbackModifier.of()])
实测全仓 18 个玻璃卡站点里**只有 1 个**记得叠。
★ 这不是"写的人不小心"—— **两个东西要一起用时,就该是一个东西**。
把按压并进基础卡之后,18 个站点**自动全都有**按压反馈,
且**不需要在每个调用点改一个字**。这才是"基础组件包含动画"的形状。
实现:
· `GlassCardModifier` 加 `pressable`(**默认 true**),在自己的
`applyNormalAttribute` 末尾内联调用反馈 —— 不走 CompositeModifier,
那是给"调用点自己有好几个 modifier 要叠"用的,这里是基础组件内部要知道的事。
· `PressFeedbackModifier.attach(instance, color?)` 抽成静态方法,
两边共用同一段 `onTouch` 逻辑(`instance` 本来就是 `CommonAttribute`,
类型一致,不需要包一层)。
· 顺带把原先唯一"叠对了"的那处(`MainPage` 会话组头卡)简化掉 ——
它现在是全场唯一的例外写法,反而容易让人以为"要叠才生效"。
★ 为什么默认 **true** 而不是"想按才开":WebUI 那一侧是**全局**的 ——
`index.css:1169` 对 `button, a, input, textarea, select, [role='button']`
统一给了 `transition`。"可点就有点击反馈"在两端都该是默认。
静态信息卡可以传 false —— 但不会有人漏,因为不可点的卡本来就没有按压语义,
而**漏掉真正可点的卡**才是原来那个问题(18 分之 17 漏)。
设备验证(模拟器):在组头卡上长按,hilog 抓到
PressFB: touch type=0 ← Down
PressFB: touch type=1 ← Up
成对到达。验证用的临时 hilog 已撤(不是留在代码里)。
★ 记一个**没验成**的取证方法,免得下次再花时间:
想靠"按住时截图看底色变了"来取证,试了三轮都不行 ——
`snapshot_display` 的往返延迟(~250ms + 传输)比一次按压的窗口长,
抓到的永远是松开后的画面。**延时不敏感的取证是 hilog**:
回调有没有触发是个**事件事实**,不需要抢时间窗。
This commit is contained in:
@ -332,11 +332,33 @@ export struct GlassCard {
|
||||
export class GlassCardModifier implements AttributeModifier<CommonAttribute> {
|
||||
/** 壁纸是否开启。关着时不铺材质(退回实体系统色,与原来观感一致)。 */
|
||||
private active: boolean = false;
|
||||
/**
|
||||
* 是否**同时**带按压反馈(默认带)。
|
||||
*
|
||||
* ★★ 2026-09-20 加(用户问过两次:「各个组件带响应点击、滑动的动画了吗」
|
||||
* 「基础组件包含动画」)。
|
||||
*
|
||||
* 之前按压反馈是**单独一个 modifier**,要靠调用点自己写
|
||||
* `CompositeModifier.of([GlassCardModifier.of(x), PressFeedbackModifier.of()])`
|
||||
* —— 实测全仓 18 个玻璃卡站点里**只有 1 个**记得加。
|
||||
* 这不是"写的人不小心":**两个东西要一起用时,就该是一个东西**。
|
||||
* 把按压并进基础卡之后,18 个站点**自动全都有**按压反馈,
|
||||
* 且不需要在每个调用点改一个字(这正是"基础组件包含动画"的意思)。
|
||||
*
|
||||
* ★ 为什么默认 **true**(而不是"想按才开"):
|
||||
* WebUI 那一侧是**全局**的 —— `index.css:1169`
|
||||
* button, a, input, textarea, select, [role='button'] { transition: … }
|
||||
* "可点就有点击反馈"在两端都该是默认,而不是逐处声明。
|
||||
* 静态信息卡(不可点的)自己传 false —— 但那**不会**有声音,
|
||||
* 因为不可点本来就不该有按压感;这里只是别给它挂无用的 `onTouch`。
|
||||
*/
|
||||
private pressable: boolean = true;
|
||||
|
||||
/** 工厂:`GlassCardModifier.of(this.bgActive)` */
|
||||
static of(active: boolean): GlassCardModifier {
|
||||
/** 工厂:`GlassCardModifier.of(this.bgActive)`;静态卡传 `false` */
|
||||
static of(active: boolean, pressable: boolean = true): GlassCardModifier {
|
||||
const m = new GlassCardModifier();
|
||||
m.active = active;
|
||||
m.pressable = pressable;
|
||||
return m;
|
||||
}
|
||||
|
||||
@ -387,6 +409,17 @@ export class GlassCardModifier implements AttributeModifier<CommonAttribute> {
|
||||
/* 壁纸关着时不铺任何材质(退了才不浪费一次模糊) */
|
||||
instance.backgroundBlurStyle(BlurStyle.NONE);
|
||||
}
|
||||
/*
|
||||
* 按压反馈直接内联在这里(而不是让调用点再挂一个 modifier)——
|
||||
* 理由见 `pressable` 字段的注释:两个东西要一起用时,就该是一个东西。
|
||||
*
|
||||
* ★ 内联而不是 `CompositeModifier.of([this, PressFeedbackModifier.of()])`:
|
||||
* `CompositeModifier` 是给"调用点自己有好几个 modifier 要叠"用的;
|
||||
* 而这里是**基础组件内部要知道的事**,转一层反而多一个间接。
|
||||
*/
|
||||
if (this.pressable) {
|
||||
PressFeedbackModifier.attach(instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -615,11 +648,26 @@ export class PressFeedbackModifier implements AttributeModifier<CommonAttribute>
|
||||
* ★ `Cancel` 必须一起处理:手势被父容器(列表滚动)抢走时不会来 `Up`,
|
||||
* 只处理 `Up` 会让元素**永远停在按下的样子**。
|
||||
*/
|
||||
PressFeedbackModifier.attach(instance, this.color);
|
||||
}
|
||||
|
||||
/**
|
||||
* 把按压反馈挂到任意组件的**普通态**属性上(可复用)。
|
||||
*
|
||||
* ★ 抽成静态方法是为了让 `GlassCardModifier` 能在**自己的**
|
||||
* `applyNormalAttribute` 里内联调用它 —— `AttributeModifier` 的
|
||||
* `instance` 参数本来就是 `CommonAttribute`,两边类型一致,不需要包一层。
|
||||
*
|
||||
* @param instance 目标组件的属性集合
|
||||
* @param color 按压时叠上去的色(默认系统点击效果色)
|
||||
*/
|
||||
static attach(instance: CommonAttribute, color?: ResourceColor): void {
|
||||
const pressColor: ResourceColor = color !== undefined ? color : $r('sys.color.ohos_id_color_click_effect');
|
||||
instance.onTouch((e: TouchEvent) => {
|
||||
const down: boolean = e.type === TouchType.Down;
|
||||
const cancel: boolean = e.type === TouchType.Cancel;
|
||||
/* 用 `BLANK` 常量而不是 `Color.Transparent` 字面量:避免"透明色"被误当成"没设" */
|
||||
const c: ResourceColor = down ? this.color : Color.Transparent;
|
||||
const c: ResourceColor = down ? pressColor : Color.Transparent;
|
||||
instance.backgroundColor(c);
|
||||
});
|
||||
}
|
||||
|
||||
@ -755,16 +755,14 @@ struct InboxTab {
|
||||
.padding({ left: 10, right: 12 })
|
||||
.alignItems(VerticalAlign.Center)
|
||||
/*
|
||||
* ★★ 两个属性集要**合成一个**再挂(实测撞出来的)。
|
||||
*
|
||||
* `.attributeModifier()` 一个组件只能挂一个,链两个是后者覆盖前者 ——
|
||||
* 第一版就是链了两句,结果玻璃与按压反馈只生效一个,而编译器不报错。
|
||||
* WebUI 那边是 CSS 类名天然叠加;ArkUI 是单一插槽,叠加要显式做。
|
||||
* ★★ 2026-09-20 简:这里原来写的是
|
||||
* CompositeModifier.of([GlassCardModifier.of(...), PressFeedbackModifier.of()])
|
||||
* —— 那是"两个 modifier 要叠"的通用解法,当时**只有这一处**记得叠。
|
||||
* 现在按压反馈已经**内联进基础卡**(见 `GlassCardModifier.pressable`),
|
||||
* 单独再挂一遍会挂两个 `onTouch`(第二个覆盖第一个,行为上等价但白挂)。
|
||||
* 这一处是全仓唯一"以前就叠对了"的,现在反而成了唯一的例外写法。
|
||||
*/
|
||||
.attributeModifier(CompositeModifier.of([
|
||||
GlassCardModifier.of(this.bgActive),
|
||||
PressFeedbackModifier.of()
|
||||
]))
|
||||
.attributeModifier(GlassCardModifier.of(this.bgActive))
|
||||
.borderRadius(Theme.radiusCard)
|
||||
.border({ width: 1, color: Theme.border })
|
||||
.clip(true)
|
||||
|
||||
Reference in New Issue
Block a user