HarmonyOS 应用开发《掌上英语》第22篇-卡片式UI设计从今日学习卡到单词翻转卡
2026/7/21 4:18:59 网站建设 项目流程

卡片式 UI 设计——从今日学习卡到单词翻转卡

一、引言

卡片式 UI 是移动应用中最主流的视觉设计模式,它将信息以独立卡片的形式组织,在有限的屏幕空间内清晰呈现多层次的内容。一个优秀的卡片设计需要在视觉层次、交互反馈和性能之间取得平衡。

本文以英语学习 App 中的三类典型卡片为例,系统讲解 HarmonyOS 中卡片式 UI 的实现思路:从简单的「今日学习卡」到数据驱动的「学习进度卡」,再到交互复杂的「单词翻转卡」,逐步深入卡片式设计的核心技巧。

二、基础卡片:今日学习卡

2.1 卡片布局分析

首页的「今日学习卡」是最简单的卡片形态——圆角矩形背景 + 内部文本 + 进度条。它使用@Builder构建,作为主页面的一个子模块:

// features/homePage/src/main/ets/pages/MainPage.ets@BuildertodayStudyBuilder(){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在主题切换时自动适配。

三、功能卡片组:ReusableFlowItem

3.1 统一卡片容器

在「练习模式」区域,四个功能卡片(单词记忆、听力训练、阅读训练、语法练习)使用统一的ReusableFlowItem组件。该组件通过stateStyles实现按压反馈:

@ComponentV2struct ReusableFlowItem{@Paramitem:PracticeView=newPracticeView($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容器叠加正反两个面。核心思路是通过rotateopacity的组合实现 3D 翻转动画:

// features/topicPage/src/main/ets/views/CourseHomePage.ets@Entry@ComponentV2exportstruct CourseHomePage{@LocalcurrentIndex:number=0;@LocalisFlipped:boolean=false;@LocalrotateY:number=0;@LocalfrontOpacity:number=1;@LocalbackOpacity:number=0;// ...其他状态...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.rotateY=0;// 回到正面this.frontOpacity=1;this.backOpacity=0;}else{this.rotateY=180;// 翻到反面this.frontOpacity=0;this.backOpacity=1;}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 的各个页面。通过borderRadiusshadowstateStyles等技术手段的组合使用,我们构建了视觉统一、交互反馈丰富的卡片体系。单词翻转卡更是实现了正反面独立布局 + 3D 翻转动画,在有限屏幕空间内展示了单词、音标、释义、例句、分类标签等多维信息,大幅提升了学习效率。

在卡片组件设计时,建议遵循"先统一后差异化"的原则,先用基础容器确定卡片模板,再针对不同业务场景定制内容和交互。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询