卡片式 UI 设计——从今日学习卡到单词翻转卡一、引言卡片式 UI 是移动应用中最主流的视觉设计模式它将信息以独立卡片的形式组织在有限的屏幕空间内清晰呈现多层次的内容。一个优秀的卡片设计需要在视觉层次、交互反馈和性能之间取得平衡。本文以英语学习 App 中的三类典型卡片为例系统讲解 HarmonyOS 中卡片式 UI 的实现思路从简单的「今日学习卡」到数据驱动的「学习进度卡」再到交互复杂的「单词翻转卡」逐步深入卡片式设计的核心技巧。二、基础卡片今日学习卡2.1 卡片布局分析首页的「今日学习卡」是最简单的卡片形态——圆角矩形背景 内部文本 进度条。它使用Builder构建作为主页面的一个子模块// features/homePage/src/main/ets/pages/MainPage.etsBuildertodayStudyBuilder(){Column(){// 标题行今日学习 坚持 7 天Row(){Text(今日学习).fontSize(16).fontWeight(FontWeight.Medium);Text(坚持 7 天).fontSize(12).fontColor($r(sys.color.font_secondary)).layoutWeight(1).textAlign(TextAlign.End);}.width(100%).margin({bottom:8});// 数据行已学 15 词 / 目标 30 词 50%Row(){Text(已学 15 词 / 目标 30 词).fontSize(13).fontColor($r(sys.color.font_secondary)).layoutWeight(1);Text(50%).fontSize(20).fontWeight(FontWeight.Bold).fontColor($r(sys.color.comp_background_emphasize));}.width(100%).margin({bottom:8});// 线性进度条Progress({value:15,total:30,type:ProgressType.Linear}).color($r(sys.color.comp_background_emphasize)).height(8).width(100%);}.padding(16).borderRadius(16).backgroundColor($r(sys.color.background_primary));}2.2 卡片设计要点核心样式参数参数值视觉效果borderRadius(16)16vp 圆角柔和边缘增加亲和力padding(16)16vp 内边距内容和边界留白backgroundColor(primary)白色背景与浅灰底色区隔视觉层次构建卡片的标题行使用layoutWeight(1)textAlign(TextAlign.End)让 “坚持 7 天” 右对齐形成主标题 副标签的视觉结构。进度数据通过字号13 和 20和颜色次要色和强调色区分主次引导用户视线聚焦在 50% 的完成率上。进度条组件使用ProgressType.Linear配合8vp高度形成清晰可见的进度指示其颜色comp_background_emphasize在主题切换时自动适配。三、功能卡片组ReusableFlowItem3.1 统一卡片容器在「练习模式」区域四个功能卡片单词记忆、听力训练、阅读训练、语法练习使用统一的ReusableFlowItem组件。该组件通过stateStyles实现按压反馈ComponentV2struct ReusableFlowItem{Paramitem:PracticeViewnewPracticeView($r(app.media.ic_home),顺序练习,1、3256);build(){Row(){Column(){Text(this.item.name).textOverflow({overflow:TextOverflow.Ellipsis}).maxLines(1).fontWeight(FontWeight.Bold).fontSize($r(sys.float.Body_S)).fontColor($r(sys.color.font_primary));Text(this.item.describe).textOverflow({overflow:TextOverflow.Ellipsis}).maxLines(1).fontSize($r(sys.float.Caption_M)).fontColor($r(sys.color.font_secondary)).margin({top:$r(app.float.vp_2)});}.justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Start).layoutWeight(1);Image(this.item.imageUri).interpolation(ImageInterpolation.High).objectFit(ImageFit.Fill).width(40).height(40).clip(true).margin({left:$r(app.float.vp_4),right:$r(app.float.vp_4)});}.stateStyles({pressed:{.scale({x:0.97,y:0.97})}}).backgroundColor($r(sys.color.background_secondary)).justifyContent(FlexAlign.SpaceBetween).height(100).width(100%).padding({left:$r(app.float.vp_12),right:$r(app.float.vp_16)}).borderRadius($r(app.float.vp_12));}}3.2 按压反馈实现stateStyles是 ArkTS 中处理交互状态的最佳方式。当用户按下卡片时组件以动画方式缩放到 0.97 倍.stateStyles({pressed:{.scale({x:0.97,y:0.97})}})这种微缩放效果模拟了真实世界中按下物体的反应提升了交互的真实感。实现时需要注意缩放值不宜过小0.95~0.98 是合适的范围过小会显得突兀避免在缩放组件中包含复杂布局嵌套结构可能在动画时产生锯齿与点击事件配合stateStyles只管理视觉反馈业务逻辑仍需写在onClick中四、高级卡片3D 翻转单词卡4.1 正反面结构设计单词翻转卡是项目中交互最复杂的卡片使用Stack容器叠加正反两个面。核心思路是通过rotate和opacity的组合实现 3D 翻转动画// features/topicPage/src/main/ets/views/CourseHomePage.etsEntryComponentV2exportstruct CourseHomePage{LocalcurrentIndex:number0;LocalisFlipped:booleanfalse;LocalrotateY:number0;LocalfrontOpacity:number1;LocalbackOpacity:number0;// ...其他状态...build(){// ...Stack(){// 正面单词展示Column(){Row(){Text(this.currentWord().partOfSpeech).fontSize(12).fontColor(#165DFF).backgroundColor(#EAF2FF).padding({left:10,right:10,top:4,bottom:4}).borderRadius(12);Blank();Text(this.isFavorite?★:☆).fontSize(24).fontColor(#FFB020).onClick((){this.isFavorite!this.isFavorite;});}.width(100%).padding({left:18,right:18,top:14});Column(){Text(this.currentWord().word).fontSize(34).fontWeight(FontWeight.Bold).fontColor(#165DFF).margin({bottom:8});Row({space:8}){Text(this.currentWord().phonetic).fontSize(15).fontColor($r(sys.color.font_secondary));Text(▶).fontSize(12).fontColor(#FFFFFF).width(26).height(26).textAlign(TextAlign.Center).borderRadius(13).backgroundColor(#165DFF);}.alignItems(VerticalAlign.Center).margin({bottom:16});Text(this.currentWord().translation).fontSize(20).fontWeight(FontWeight.Medium).fontColor($r(sys.color.font_primary)).textAlign(TextAlign.Center).margin({bottom:14});Text(this.currentWord().example).fontSize(14).fontColor($r(sys.color.font_secondary)).textAlign(TextAlign.Center).maxLines(2).padding({left:18,right:18});}.layoutWeight(1).justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center).width(100%);Text(点击卡片查看释义).fontSize(11).fontColor($r(sys.color.font_tertiary)).margin({bottom:12});}.width(100%).height(280).backgroundColor($r(sys.color.background_primary)).borderRadius(20).shadow(ShadowStyle.OUTER_DEFAULT_MD)// 3D 投影效果.rotate({x:0,y:this.rotateY,z:0,centerX:50%,centerY:50%,perspective:1200}).opacity(this.frontOpacity).onClick(()this.flipCard());// 反面详细释义Column(){Text(详细释义).fontSize(13).fontColor($r(sys.color.font_secondary)).margin({bottom:8});Text(this.currentWord().translation).fontSize(22).fontWeight(FontWeight.Bold).fontColor(#165DFF).textAlign(TextAlign.Center).margin({bottom:14});Text(this.currentWord().example).fontSize(14).fontColor($r(sys.color.font_primary)).padding({left:20,right:20}).textAlign(TextAlign.Center).maxLines(2).margin({bottom:8});Text(this.currentWord().exampleTranslation).fontSize(13).fontColor($r(sys.color.font_secondary)).padding({left:20,right:20}).textAlign(TextAlign.Center).maxLines(2).margin({bottom:14});Row({space:6}){Text(this.getCategoryLabel()).fontSize(10).fontColor(#165DFF).backgroundColor(#EAF2FF).padding({left:8,right:8,top:3,bottom:3}).borderRadius(8);ForEach(this.currentWord().tags,(tag:string){Text(tag).fontSize(10).fontColor(#165DFF).backgroundColor(#EAF2FF).padding({left:8,right:8,top:3,bottom:3}).borderRadius(8);},(tag:string)tag);}.justifyContent(FlexAlign.Center).margin({bottom:10});Text(点击返回正面).fontSize(11).fontColor($r(sys.color.font_tertiary));}.width(100%).height(280).justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center).backgroundColor(#F8FAFC)// 浅灰背景区分正反面.borderRadius(20).shadow(ShadowStyle.OUTER_DEFAULT_MD).rotate({x:0,y:this.rotateY-180,z:0,centerX:50%,centerY:50%,perspective:1200}).opacity(this.backOpacity).onClick(()this.flipCard());}.width(90%).height(280);}}4.2 翻转动画实现翻转动画通过animateTo驱动在 400ms 内完成 Y 轴旋转 180 度privateflipCard():void{animateTo({duration:400,curve:Curve.EaseInOut},(){if(this.isFlipped){this.rotateY0;// 回到正面this.frontOpacity1;this.backOpacity0;}else{this.rotateY180;// 翻到反面this.frontOpacity0;this.backOpacity1;}this.isFlipped!this.isFlipped;});}关键动画参数参数值说明duration400ms翻转时长适中节奏curveCurve.EaseInOut缓入缓出模拟真实惯性rotate.y0 → 180Y 轴旋转角度perspective1200透视距离值越小 3D 效果越强正反面同步技巧反面卡片的rotate比正面多 180 度this.rotateY - 180确保卡片翻转过程中始终保持某一面正对用户的视觉效果。透明度frontOpacity/backOpacity配合旋转角度在翻转过程中平滑过渡避免背面透过正面显示。4.3 卡片颜色与布局差异正反面的视觉差异通过颜色和布局来体现维度正面反面背景色background_primary白色#F8FAFC浅灰主色调单词 34px Bold#165DFF释义 22px Bold#165DFF内容重点词性徽章、发音按钮、收藏例句翻译、分类标签底部提示“点击卡片查看释义”“点击返回正面”这种对比明确了正面浏览单词 — 反面查看详解的功能划分用户一目了然。五、卡片设计的通用原则5.1 视觉规范原则实现方式圆角统一所有卡片使用 16~20vp borderRadius阴影层次ShadowStyle.OUTER_DEFAULT_MD提供 3D 层次感留白充足卡片内统一 16vp padding颜色系统背景色使用sys.color变量自动适配主题5.2 交互反馈// 三种反馈示例.stateStyles({pressed:{.scale({x:0.97,y:0.97})}})// 1. 按压缩放.onClick(()this.flipCard())// 2. 点击切换.gesture(SwipeGesture().onAction(...))// 3. 手势滑动六、总结从简单的今日学习卡到复杂的 3D 翻转单词卡卡片式 UI 设计贯穿了英语学习 App 的各个页面。通过borderRadius、shadow、stateStyles等技术手段的组合使用我们构建了视觉统一、交互反馈丰富的卡片体系。单词翻转卡更是实现了正反面独立布局 3D 翻转动画在有限屏幕空间内展示了单词、音标、释义、例句、分类标签等多维信息大幅提升了学习效率。在卡片组件设计时建议遵循先统一后差异化的原则先用基础容器确定卡片模板再针对不同业务场景定制内容和交互。
HarmonyOS 应用开发《掌上英语》第22篇-卡片式UI设计从今日学习卡到单词翻转卡
卡片式 UI 设计——从今日学习卡到单词翻转卡一、引言卡片式 UI 是移动应用中最主流的视觉设计模式它将信息以独立卡片的形式组织在有限的屏幕空间内清晰呈现多层次的内容。一个优秀的卡片设计需要在视觉层次、交互反馈和性能之间取得平衡。本文以英语学习 App 中的三类典型卡片为例系统讲解 HarmonyOS 中卡片式 UI 的实现思路从简单的「今日学习卡」到数据驱动的「学习进度卡」再到交互复杂的「单词翻转卡」逐步深入卡片式设计的核心技巧。二、基础卡片今日学习卡2.1 卡片布局分析首页的「今日学习卡」是最简单的卡片形态——圆角矩形背景 内部文本 进度条。它使用Builder构建作为主页面的一个子模块// features/homePage/src/main/ets/pages/MainPage.etsBuildertodayStudyBuilder(){Column(){// 标题行今日学习 坚持 7 天Row(){Text(今日学习).fontSize(16).fontWeight(FontWeight.Medium);Text(坚持 7 天).fontSize(12).fontColor($r(sys.color.font_secondary)).layoutWeight(1).textAlign(TextAlign.End);}.width(100%).margin({bottom:8});// 数据行已学 15 词 / 目标 30 词 50%Row(){Text(已学 15 词 / 目标 30 词).fontSize(13).fontColor($r(sys.color.font_secondary)).layoutWeight(1);Text(50%).fontSize(20).fontWeight(FontWeight.Bold).fontColor($r(sys.color.comp_background_emphasize));}.width(100%).margin({bottom:8});// 线性进度条Progress({value:15,total:30,type:ProgressType.Linear}).color($r(sys.color.comp_background_emphasize)).height(8).width(100%);}.padding(16).borderRadius(16).backgroundColor($r(sys.color.background_primary));}2.2 卡片设计要点核心样式参数参数值视觉效果borderRadius(16)16vp 圆角柔和边缘增加亲和力padding(16)16vp 内边距内容和边界留白backgroundColor(primary)白色背景与浅灰底色区隔视觉层次构建卡片的标题行使用layoutWeight(1)textAlign(TextAlign.End)让 “坚持 7 天” 右对齐形成主标题 副标签的视觉结构。进度数据通过字号13 和 20和颜色次要色和强调色区分主次引导用户视线聚焦在 50% 的完成率上。进度条组件使用ProgressType.Linear配合8vp高度形成清晰可见的进度指示其颜色comp_background_emphasize在主题切换时自动适配。三、功能卡片组ReusableFlowItem3.1 统一卡片容器在「练习模式」区域四个功能卡片单词记忆、听力训练、阅读训练、语法练习使用统一的ReusableFlowItem组件。该组件通过stateStyles实现按压反馈ComponentV2struct ReusableFlowItem{Paramitem:PracticeViewnewPracticeView($r(app.media.ic_home),顺序练习,1、3256);build(){Row(){Column(){Text(this.item.name).textOverflow({overflow:TextOverflow.Ellipsis}).maxLines(1).fontWeight(FontWeight.Bold).fontSize($r(sys.float.Body_S)).fontColor($r(sys.color.font_primary));Text(this.item.describe).textOverflow({overflow:TextOverflow.Ellipsis}).maxLines(1).fontSize($r(sys.float.Caption_M)).fontColor($r(sys.color.font_secondary)).margin({top:$r(app.float.vp_2)});}.justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Start).layoutWeight(1);Image(this.item.imageUri).interpolation(ImageInterpolation.High).objectFit(ImageFit.Fill).width(40).height(40).clip(true).margin({left:$r(app.float.vp_4),right:$r(app.float.vp_4)});}.stateStyles({pressed:{.scale({x:0.97,y:0.97})}}).backgroundColor($r(sys.color.background_secondary)).justifyContent(FlexAlign.SpaceBetween).height(100).width(100%).padding({left:$r(app.float.vp_12),right:$r(app.float.vp_16)}).borderRadius($r(app.float.vp_12));}}3.2 按压反馈实现stateStyles是 ArkTS 中处理交互状态的最佳方式。当用户按下卡片时组件以动画方式缩放到 0.97 倍.stateStyles({pressed:{.scale({x:0.97,y:0.97})}})这种微缩放效果模拟了真实世界中按下物体的反应提升了交互的真实感。实现时需要注意缩放值不宜过小0.95~0.98 是合适的范围过小会显得突兀避免在缩放组件中包含复杂布局嵌套结构可能在动画时产生锯齿与点击事件配合stateStyles只管理视觉反馈业务逻辑仍需写在onClick中四、高级卡片3D 翻转单词卡4.1 正反面结构设计单词翻转卡是项目中交互最复杂的卡片使用Stack容器叠加正反两个面。核心思路是通过rotate和opacity的组合实现 3D 翻转动画// features/topicPage/src/main/ets/views/CourseHomePage.etsEntryComponentV2exportstruct CourseHomePage{LocalcurrentIndex:number0;LocalisFlipped:booleanfalse;LocalrotateY:number0;LocalfrontOpacity:number1;LocalbackOpacity:number0;// ...其他状态...build(){// ...Stack(){// 正面单词展示Column(){Row(){Text(this.currentWord().partOfSpeech).fontSize(12).fontColor(#165DFF).backgroundColor(#EAF2FF).padding({left:10,right:10,top:4,bottom:4}).borderRadius(12);Blank();Text(this.isFavorite?★:☆).fontSize(24).fontColor(#FFB020).onClick((){this.isFavorite!this.isFavorite;});}.width(100%).padding({left:18,right:18,top:14});Column(){Text(this.currentWord().word).fontSize(34).fontWeight(FontWeight.Bold).fontColor(#165DFF).margin({bottom:8});Row({space:8}){Text(this.currentWord().phonetic).fontSize(15).fontColor($r(sys.color.font_secondary));Text(▶).fontSize(12).fontColor(#FFFFFF).width(26).height(26).textAlign(TextAlign.Center).borderRadius(13).backgroundColor(#165DFF);}.alignItems(VerticalAlign.Center).margin({bottom:16});Text(this.currentWord().translation).fontSize(20).fontWeight(FontWeight.Medium).fontColor($r(sys.color.font_primary)).textAlign(TextAlign.Center).margin({bottom:14});Text(this.currentWord().example).fontSize(14).fontColor($r(sys.color.font_secondary)).textAlign(TextAlign.Center).maxLines(2).padding({left:18,right:18});}.layoutWeight(1).justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center).width(100%);Text(点击卡片查看释义).fontSize(11).fontColor($r(sys.color.font_tertiary)).margin({bottom:12});}.width(100%).height(280).backgroundColor($r(sys.color.background_primary)).borderRadius(20).shadow(ShadowStyle.OUTER_DEFAULT_MD)// 3D 投影效果.rotate({x:0,y:this.rotateY,z:0,centerX:50%,centerY:50%,perspective:1200}).opacity(this.frontOpacity).onClick(()this.flipCard());// 反面详细释义Column(){Text(详细释义).fontSize(13).fontColor($r(sys.color.font_secondary)).margin({bottom:8});Text(this.currentWord().translation).fontSize(22).fontWeight(FontWeight.Bold).fontColor(#165DFF).textAlign(TextAlign.Center).margin({bottom:14});Text(this.currentWord().example).fontSize(14).fontColor($r(sys.color.font_primary)).padding({left:20,right:20}).textAlign(TextAlign.Center).maxLines(2).margin({bottom:8});Text(this.currentWord().exampleTranslation).fontSize(13).fontColor($r(sys.color.font_secondary)).padding({left:20,right:20}).textAlign(TextAlign.Center).maxLines(2).margin({bottom:14});Row({space:6}){Text(this.getCategoryLabel()).fontSize(10).fontColor(#165DFF).backgroundColor(#EAF2FF).padding({left:8,right:8,top:3,bottom:3}).borderRadius(8);ForEach(this.currentWord().tags,(tag:string){Text(tag).fontSize(10).fontColor(#165DFF).backgroundColor(#EAF2FF).padding({left:8,right:8,top:3,bottom:3}).borderRadius(8);},(tag:string)tag);}.justifyContent(FlexAlign.Center).margin({bottom:10});Text(点击返回正面).fontSize(11).fontColor($r(sys.color.font_tertiary));}.width(100%).height(280).justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center).backgroundColor(#F8FAFC)// 浅灰背景区分正反面.borderRadius(20).shadow(ShadowStyle.OUTER_DEFAULT_MD).rotate({x:0,y:this.rotateY-180,z:0,centerX:50%,centerY:50%,perspective:1200}).opacity(this.backOpacity).onClick(()this.flipCard());}.width(90%).height(280);}}4.2 翻转动画实现翻转动画通过animateTo驱动在 400ms 内完成 Y 轴旋转 180 度privateflipCard():void{animateTo({duration:400,curve:Curve.EaseInOut},(){if(this.isFlipped){this.rotateY0;// 回到正面this.frontOpacity1;this.backOpacity0;}else{this.rotateY180;// 翻到反面this.frontOpacity0;this.backOpacity1;}this.isFlipped!this.isFlipped;});}关键动画参数参数值说明duration400ms翻转时长适中节奏curveCurve.EaseInOut缓入缓出模拟真实惯性rotate.y0 → 180Y 轴旋转角度perspective1200透视距离值越小 3D 效果越强正反面同步技巧反面卡片的rotate比正面多 180 度this.rotateY - 180确保卡片翻转过程中始终保持某一面正对用户的视觉效果。透明度frontOpacity/backOpacity配合旋转角度在翻转过程中平滑过渡避免背面透过正面显示。4.3 卡片颜色与布局差异正反面的视觉差异通过颜色和布局来体现维度正面反面背景色background_primary白色#F8FAFC浅灰主色调单词 34px Bold#165DFF释义 22px Bold#165DFF内容重点词性徽章、发音按钮、收藏例句翻译、分类标签底部提示“点击卡片查看释义”“点击返回正面”这种对比明确了正面浏览单词 — 反面查看详解的功能划分用户一目了然。五、卡片设计的通用原则5.1 视觉规范原则实现方式圆角统一所有卡片使用 16~20vp borderRadius阴影层次ShadowStyle.OUTER_DEFAULT_MD提供 3D 层次感留白充足卡片内统一 16vp padding颜色系统背景色使用sys.color变量自动适配主题5.2 交互反馈// 三种反馈示例.stateStyles({pressed:{.scale({x:0.97,y:0.97})}})// 1. 按压缩放.onClick(()this.flipCard())// 2. 点击切换.gesture(SwipeGesture().onAction(...))// 3. 手势滑动六、总结从简单的今日学习卡到复杂的 3D 翻转单词卡卡片式 UI 设计贯穿了英语学习 App 的各个页面。通过borderRadius、shadow、stateStyles等技术手段的组合使用我们构建了视觉统一、交互反馈丰富的卡片体系。单词翻转卡更是实现了正反面独立布局 3D 翻转动画在有限屏幕空间内展示了单词、音标、释义、例句、分类标签等多维信息大幅提升了学习效率。在卡片组件设计时建议遵循先统一后差异化的原则先用基础容器确定卡片模板再针对不同业务场景定制内容和交互。