96SEO 2026-08-05 23:21 7
AI 助手回复“打车”意图时会下发一张“确认行程”卡片:
关键视觉特征只有一个——左右两个真挖出去的半圆缺口。按理说,
最直觉的做法是把撕线那一行做成 Stack中间放虚线。左右各放一个填外层底色的 Circle形成视觉上的“缺口”。
Stack {
// 中间水平虚线
Line
.height
.startPoint
.endPoint
.stroke
.strokeWidth
.strokeDashArray
.width
.margin
// 左右两个跟底色一致的“假缺口”
Row {
Circle
.fill
.offset
Blank
Circle
.fill
.offset
}
.width
}
.width
.height
痛点 #1:颜色不匹配导致假缺口露出浅灰色块。怎么说呢,
卡片被塞进 AI 聊天气泡里气泡背景是浅蓝渐变。与 #F5F6FA 不一致,缺口处直接露出浅灰色块,看起来像是“贴上去的”。
痛点 #2:阴影仍然是矩形轮廓,没有沿缺口走。
外层 .shadow 加在最外面的 Column 上。阴影边界仍是矩形圆角,缺口边缘没有阴影包络,视觉上没有凹感。
根本原因:这两个 Circle 并没有真的把形状挖掉,只是用同块盖住而已。一旦底色变化、父容器出现渐变或需要截图分享时就会立刻穿帮。
既然要“真挖洞”。自然想到使用 SVG 方法描述一个带缺口的形状,接下来把卡片裁剪成该形状。
方法示例:
M …H ,A …V ,A …A ,V …A ,H …A ,V …A ,A …V ,A …Z
尝试直接把 Path.clipShape),IDE 报错——clipShape) 不接受绘制组件 Path)。
痛点 #3:API 用错导致编译错误。
于是采用“双层 Stack”:底层 Path 加阴影,上层 Column 用相同形状裁剪内容。至于代码结构如下,
结果:
) 在新版本 ArkUI 已不推荐。用 PathShape) 替代。其实,* 痛点 #4:双层结构易失效且维护成本高 *
| 类名 | Description | L用途 |
|---|---|---|
P |
ath
html
Project Name : MyApplication Component Name : ConfirmTripCardComp Description : The goal is to implement a ticket style card that contains a gradient blue header。dashed line separator in middle and two semi-circular notches on both sides of
This documentation explains how you would approach building this component and what you have tried in order to create an actual
┌──────────────────────────────────────────┐ │ 确认行程 │ │ ─── │ │ │ │ ⊙ 香港中国公司协会 立即出发 │ │ ⋮ 全程 公里 分钟 │ │ ⊙ 香港国际机场 预计 : 到达 │ └──┘ ← 撕线 + 两侧凹槽 │ │ │ │ ┌────────────────────────────────┐ │ │ │ │ │ │ └────────────────────────────────┘ │ │ 预估 ~ 人民币起 │ │ 已选中 种车型: │ │ │ │ ┌────── 确认用车 ──────┐ │ └──────────────────────────────────────────┘
⚠️ 使用者痛点 #0: 若任何视觉细节错位。都可能导致使用者误以为功能异常,从而影响使用体验。所有实现必须保证 **像素级对齐** 与 **自适应布局**。
⚡ 痛点 #1 – 背景颜色不匹配导致假孔显露灰色块 当卡片嵌入 AI 聊天气泡时其背景为浅蓝渐变;若使用固定颜色 ) 的 Circle 来遮挡。则会出现明显颜色不一致的灰块,看起来像是「贴上去」的假孔。
Stack {
// 中间水平虚线
Line
.height
.startPoint
.endPoint
.stroke
.strokeWidth
.strokeDashArray
.width
.margin
// 左右两个与背景同色的 “假孔”
Row {
Circle
.fill // <-- 固定颜色 → 与父容器不匹配
.offset
Blank
Circle
.fill
.offset
}.width
}.width.height
⚡ 痛点 #2 – 阴影仍保持矩形轮廓 将 `.shadow` 加在最外层 `Column` 上后投射出的阴影始终是矩形/圆角矩形。而不是沿着凹槽轮廓展开,从而失去 “凹陷感”。此时原因在于 **Circle 并未真的把区域挖掉**。它们只是用同块覆盖而已,一旦背景或父容器改变,就会立刻穿帮。
⚡ 痛点 #3 – API 使用错误导致编译报错 直接将 ``Path`组件当作 `.clipShape` 参数会报错,因为 `clipShape` 接受的是 **Shape 对象** 而非视图节点 `Path`。此错误常见于文档分散且命名相近的情况下。按理说,
Path → 绘制组件。仅用于渲染 SVG 方法;加入视图树后不会参与几何裁剪计算。PathShape → Shape 对象。用作 clipShape / mask 等属性的入参,可参与几何运算。<\/ul>M x y // 起点 H w-r // 顶部直线至右侧圆角前 A r r 0 0 1 w r // 顶部右圆角 V ny-nr // 垂直至左侧凹槽上缘 A nr nr 0 0 1 w ny+nr // 凹槽右侧弧线 V h-r // 垂直至右下圆角前 A r r 0 0 1 w-r h // 底部右圆角 H r // 底部直线至左下圆角前 A r r 0 0 1 r h // 底部左圆角 V ny+nr // 垂直回到左侧凹槽下缘 A nr nr 0 0 1 r ny-nr // 凹槽左侧弧线 Z // 闭合方法 <\/codeline>
⚡ 痛点 #4 – 双层 Stack 难以同步宽高 & 阴影位置 即便使用双层结构。也会遇到以下问题:
new Path 已被废弃,需要改用 new PathShape;若强行使用仍可运行,但底层 Path 的投射阴影只能覆盖矩形外缘,不会贴合凹槽。Stack 必须保持完全相同尺寸,否则两层错位导致视觉漂移。<\/ol>
| 类名 | 作用 | 使用场景 |
|---|---|---|
Path<\/ code> | 绘制组件。仅用于渲染 SVG 方法<\/ td> | 放置于视图树内部绘制各种形状<\/ td> |
PathShape<\/ code> | 几何 Shape 对象,可作为 clip/mask 参数<\/ td> | 需要进行几何裁剪或遮罩时使用<\/ td> |
import { PathShape } from '@kit.ArkUI';Column /* 内容 */ /*①先裁剪 */ .clipShape })) /*②再加投射 */ .shadow({ radius :12。color:'#33000000',offsetX :0,offsetY :4,});其实,<\/codeline>
⚡ 痛点 #6 – 错误地认为 Clip 会把 Shadow 一并裁掉。需要“双层结构”,说起来,这种思维源自 Web/RN/SwiftUI 的经验。但在 ArkUI 中恰恰相反——Shadow 是在合成阶段根据最终几何轮廓生成 Outer Shadow,所以只需单层就可以 “沿凹陷外发光”。其实,
.shadow 调用。否则 Shadow 将基于未裁剪前的矩形轮廓计算。<\/ul>
onAreaChange 回调返回宽高单位为 vp。说起来,<\/ul>
Path commands 字符串里的数值单位为 px。<\/ul>
所有进入方法计算的数据都必须经过 vp2px 转换。说到例如,
const cornerPx = vp2px; // 圆角16vp → px const notchPx = vp2px;// 缺口9vp → px \/\/ …,后续所有 path 参数均使用上述 px 值 \<\/codeline>
Row .width .height // 零体积节点 .border({ width这方面。{ top :1 },// top dashed line 为唯一可见部分 color这方面,'#33000000',style:borderStyle.Dashed,});\<\/codeline>
至于解决办法,在首帧检测到宽高 <=0 时返回一个超大矩形,以等价“不裁剪”。
if{ return 'M0 L2000 L2000 L0 Z';} \<\/codeline>
至于防御策略。若检测到无法容纳完整凹槽,则退化为普通无孔圓角矩形。
const minNy = cornerPx + notchPx;const maxNy = h - cornerPx - notchPx;if{ return this.getPlainRectPath;} // 无孔版本 let ny = this.notchY;说起来,if ny = minNy;if ny = maxNy;\<\/codeline>
做法是在抬头区域一样监听 onAreaChange 获取实际高度。将其转化为 px 并作为 notchY 输入给方法生成函数,实现 “贴着抬头底边走”。
@Local headerHeightVp:number=40;话说回来,// vp 单位。高度随内容变化自动更新 @Local notchYPx:number=vp2px;TicketHeader /*…*/ //.onAreaChange 捕获实际高度并同步字段 .onAreaChange=>{ this.headerHeightVp=Number;this.notchYPx=vp2px);}),\<\/codeline>
import { PathShape } from '@kit.ArkUI';@ComponentV2 export struct ConfirmTripCardComp { @Param @Require card : TripCard;@Local cardWidthPx:number=0;话说回来,// 实际 px 宽度。由 onAreaChange 更新 @Local cardHeightPx:number=0;// 实际 px 高度,由 onAreaChange 更新 @Local notchYPx:number=80;// 缺口中心 y,单位 px;默认值占位 @Local headerHeightVp:number=40;// 抬头实际高度,随文字动态变化 private readonly cornerRadiusVp:number=16;不过,private readonly notchRadiusVp:number=9;} \<\/codeline>
getCardPath:string{ const w=this.cardWidthPx;const h=this.cardHeightPx;if{return 'M0 L20000 L20000 L0 Z';} // 首帧兜底 const r=vp2px;// 圆角 px const nr=vp2px;// 缺孔半径 px // 防止高度不足无法容纳完整凹槽 const minNy=r+nr;其实,const maxNy=h-r-nr;if{ // 返回普通四周带圆角的矩形 path return `M ${r} H ${w-r} A ${r} ${r} ${w} ${r} V ${h-r} A ${r} ${r} ${w-r} ${h} H ${r} A ${r} ${r} ${r} ${h-r} V ${r} Z`;} // 钳制 notch Y 在合法区间内 let ny=this.notchYPx;ifny=minNy,怎么说呢,ifny=maxNy;// 完整带两侧内凹半圆穴道的 path 字符串 return `M ${r}`+ // 起始左上弧入口 ` H ${w-r}`+ // 顶部直线至右上弧前 ` A ${r} ${r} ${} ${} `+ // 顶部右圆弧 ` V ${}`+ // 向下至右穴入口 ` A ${nr} ${nr} ${} ${} `+ // Right 内凹半円 ` V ${}`+ // 向下至右下圓弧開始 ` A ${r} ${r} ${} ${} `+ // Right bottom 圆弧 ` H ${r}`+ ` A ${r} ${r} ${} ${} `+ ` V ${}`+ ` A ${nr} ${nr} ${} ${} ` ` V ${}` ` A ${r} ${r} ${} ${} Z`;} \<\/codeline>
build{ Stack{ Column{ /* ★ 抬头区 ★ */ this.TicketHeader;/* ★ 撕線 ★ — 零體積節點 */ Row .width .height .border({ width这方面。{top :1},color:'#33000000',style:borderStyle.Dashed,});/* ★ 主体白區 ★ — 地圖/價格/按鈕 */ Column{ /* 此處省略具體子組件 */ } } /* ---- 主要三步 ---- */ //.① 裁切實際幾何輪廓 .clipShape})) //.② 緊接著添加陰影 → 自動沿剖面外發光 .shadow({ radius :12。color :'#33000000',offsetX :0,offsetY :4,}) //.③ 捕獲實際渲染尺寸,以觸發路徑重算 .onAreaChange=>{ this.cardWidthPx = vp2px);this.cardHeightPx = vp2px);}) //.④ 背景顏色與圓角設定 .backgroundColor }.width;} \<\/codeline>
@Builder TicketHeader{ Stack{ /* 背景層:藍底漸變 */ Column .width .height .linearGradient({ angle :90。colors:,] });/* 内容層:標題 + 三行資訊 */ Column /* 標題示例 */ Text.fontSize.fontWeight.fontColor.marginTop;/* 更多信息,…省略 */ //.--- 動態測量抬頭實際高度 ---// ).onAreaChange=>{ this.headerHeightVp = Number;this.notchYPx = vp2px);//<‑‑ 缺孔對齊抬頭底邊 }); }.width; } \<\/codeline>
ClipShape 用 PathShape ;话说回来,Shadow 同層跟 Clip走;Path 参数需 vp→PX ;首幀太矮要兜底,撕線零體積+dashed border;欠孔貼著抬頭底邊走.
Sorry!The message is incomplete because it exceeds maximum allowed length.
作为专业的SEO优化服务提供商,我们致力于通过科学、系统的搜索引擎优化策略,帮助企业在百度、Google等搜索引擎中获得更高的排名和流量。我们的服务涵盖网站结构优化、内容优化、技术SEO和链接建设等多个维度。
| 服务项目 | 基础套餐 | 标准套餐 | 高级定制 |
|---|---|---|---|
| 关键词优化数量 | 10-20个核心词 | 30-50个核心词+长尾词 | 80-150个全方位覆盖 |
| 内容优化 | 基础页面优化 | 全站内容优化+每月5篇原创 | 个性化内容策略+每月15篇原创 |
| 技术SEO | 基本技术检查 | 全面技术优化+移动适配 | 深度技术重构+性能优化 |
| 外链建设 | 每月5-10条 | 每月20-30条高质量外链 | 每月50+条多渠道外链 |
| 数据报告 | 月度基础报告 | 双周详细报告+分析 | 每周深度报告+策略调整 |
| 效果保障 | 3-6个月见效 | 2-4个月见效 | 1-3个月快速见效 |
我们的SEO优化服务遵循科学严谨的流程,确保每一步都基于数据分析和行业最佳实践:
全面检测网站技术问题、内容质量、竞争对手情况,制定个性化优化方案。
基于用户搜索意图和商业目标,制定全面的关键词矩阵和布局策略。
解决网站技术问题,优化网站结构,提升页面速度和移动端体验。
创作高质量原创内容,优化现有页面,建立内容更新机制。
获取高质量外部链接,建立品牌在线影响力,提升网站权威度。
持续监控排名、流量和转化数据,根据效果调整优化策略。
基于我们服务的客户数据统计,平均优化效果如下:
我们坚信,真正的SEO优化不仅仅是追求排名,而是通过提供优质内容、优化用户体验、建立网站权威,最终实现可持续的业务增长。我们的目标是与客户建立长期合作关系,共同成长。
Demand feedback