HarmonyOS7 多媒体能力怎么放进一个页面:MediaPanelSwitcher 组合式案例解析
文章目录
- 前言
- 这个案例适合学什么
- 完整代码
- 先看页面骨架:一个状态切三块内容
- 切换头部为什么用 `ForEach`
- `Web` 面板讲的是“控制感”
- `Canvas` 面板讲的是“自定义表达”
- `Image` 面板讲的是“资源展示效率”
- 这三个组件到底怎么选
- 真实业务里怎么改造成可用页面
- 这类组合页容易踩的坑
- 写在最后
前言
单独学Web、Canvas、Image都不难,真正到了业务里,麻烦的是它们往往不会单独出现。一个内容页可能上半部分是图片画廊,中间是一块自绘数据区,底部还嵌着网页内容。这个时候,问题就不再是“某个组件怎么用”,而是“多个能力怎么在一个页面里组织得清楚”。
这一页案例很适合讲这个问题。它不是某个单组件教程,而是一个典型的组合式页面骨架:用一个切换面板,把三类媒体能力收在同一个交互入口里。
这个案例适合学什么
它最有价值的地方,不是具体内容有多复杂,而是把三个能力放在了同一个页面语境里:
Web适合展示外部内容和页面控制Canvas适合自绘可视化和动态图形Image适合展示视觉资源和图库内容
你看完这页,至少能建立一个判断框架:同一个需求里,不同媒体能力应该怎么分工。
完整代码
import{DEMO_BG_COLOR,DEMO_CARD_COLOR,DEMO_THEME_COLOR,DEMO_SUBTEXT_COLOR}from'./types'@Entry@Componentstruct MediaPanelSwitcher{@StateisShow:boolean=true@StateactivePanel:number=0privatesettings:RenderingContextSettings=newRenderingContextSettings(true)privatecontext:CanvasRenderingContext2D=newCanvasRenderingContext2D(this.settings)build(){Column(){if(this.isShow){Scroll(){Column({space:16}){Text('Web + Canvas + Image 综合').fontSize(16).fontColor(DEMO_THEME_COLOR).fontWeight(FontWeight.Bold)Column(){Row({space:0}){ForEach(['Web 组件','Canvas 绘图','Image 图片'],(label:string,idx:number)=>{Text(label).fontSize(13).fontColor(idx===this.activePanel?'#FFFFFF':'#666666').padding({left:16,right:16,top:8,bottom:8}).backgroundColor(idx===this.activePanel?DEMO_THEME_COLOR:'#E8E8E8').borderRadius(6).margin({right:8}).onClick(()=>{this.activePanel=idx})})}.width('100%')}.backgroundColor(DEMO_CARD_COLOR).padding(12).borderRadius(12)if(this.activePanel===0){Column(){Column(){Text('Web View 占位').fontSize(14).fontColor('#FFFFFF')}.width('100%').height(180).backgroundColor('#333333').borderRadius(10).justifyContent(FlexAlign.Center)Row({space:6}){ForEach(['后退','前进','刷新','首页'],(label:string)=>{Text(label).fontSize(11).fontColor(DEMO_THEME_COLOR).backgroundColor('#E8F4FD').borderRadius(4).padding({left:8,right:8,top:4,bottom:4})})}.width('100%').justifyContent(FlexAlign.SpaceEvenly).margin({top:8})}.backgroundColor(DEMO_CARD_COLOR).padding(12).borderRadius(12)}elseif(this.activePanel===1){Column(){Column(){Canvas(this.context).onReady(()=>{this.context.fillStyle='#4D96FF'this.context.fillRect(10,10,360,50)this.context.fillStyle='#6BCB77'this.context.fillRect(10,70,360,50)this.context.fillStyle='#FFA500'this.context.fillRect(10,130,360,50)}).width('100%').height(180).backgroundColor('#FAFAFA').borderRadius(8)}}.backgroundColor(DEMO_CARD_COLOR).padding(12).borderRadius(12)}else{Column(){Row({space:6}){Column(){Text('1').fontSize(14).fontColor('#FFF')}.layoutWeight(1).height(120).backgroundColor('#4D96FF').borderRadius(8).justifyContent(FlexAlign.Center)Column(){Text('2').fontSize(14).fontColor('#FFF')}.layoutWeight(1).height(120).backgroundColor('#FFA500').borderRadius(8).justifyContent(FlexAlign.Center)Column(){Text('3').fontSize(14).fontColor('#FFF')}.layoutWeight(1).height(120).backgroundColor('#6BCB77').borderRadius(8).justifyContent(FlexAlign.Center)}.width('100%')}.backgroundColor(DEMO_CARD_COLOR).padding(12).borderRadius(12)}Column({space:6}){Text('三大组件功能对比').fontSize(14).fontColor(DEMO_THEME_COLOR).fontWeight(FontWeight.Bold)Text('Web: 加载网页 / JS交互 / 前进后退 / Cookie').fontSize(12).fontColor('#333333')Text('Canvas: 绘制图形 / 渐变 / 动画 / 图表').fontSize(12).fontColor('#333333')Text('Image: 显示图片 / 裁剪 / 滤镜 / 填充').fontSize(12).fontColor('#333333')Text('共同场景: 混合布局 / 数据可视化 / 富媒体').fontSize(11).fontColor(DEMO_SUBTEXT_COLOR).margin({top:2})}.width('100%').backgroundColor('#E8F4FD').padding(14).borderRadius(12)}.width('100%')}}Text('MediaPanelSwitcher - Web、Canvas、Image 整合页').fontSize(12).fontColor(DEMO_SUBTEXT_COLOR).margin({top:12})}.width('100%').height('100%').backgroundColor(DEMO_BG_COLOR).padding(16)}}先看页面骨架:一个状态切三块内容
这个页面最核心的状态其实只有一个:
@StateactivePanel:number=0它决定当前显示哪块媒体面板。这个思路非常适合做轻量切换页,因为你不用真的跳路由,也不用在页面间来回进出,所有能力都被折叠在一个统一容器里。
切换头部为什么用ForEach
顶部按钮区用了这一段:
ForEach(['Web 组件','Canvas 绘图','Image 图片'],(label:string,idx:number)=>{Text(label).fontColor(idx===this.activePanel?'#FFFFFF':'#666666').backgroundColor(idx===this.activePanel?DEMO_THEME_COLOR:'#E8E8E8').onClick(()=>{this.activePanel=idx})})这段代码的价值,不只是少写几个按钮,而是把“选项配置”和“当前态样式”绑在了一起。这样后面如果你要扩成 4 个、5 个面板,也不需要重构页面结构。
说白了,这是一种很典型的低成本选项卡写法。
Web面板讲的是“控制感”
案例里的Web区没有放真实网页,而是用了一个占位块加控制按钮:
ForEach(['后退','前进','刷新','首页'],(label:string)=>{Text(label)})这其实是在强调Web组件和其他媒体组件最大的不同点之一:它除了展示内容,还天然带导航和页面控制属性。
所以如果你要做帮助中心、嵌入活动页、混合式内容详情,Web更适合承载“可浏览、可跳转、可回退”的内容区域。
Canvas面板讲的是“自定义表达”
中间面板用了三块矩形做占位绘制:
Canvas(this.context).onReady(()=>{this.context.fillRect(10,10,360,50)this.context.fillRect(10,70,360,50)this.context.fillRect(10,130,360,50)})这一块虽然简单,但意思很明确:Canvas的优势在于你不受预设组件限制,可以自己画图形、图表、动画甚至小游戏元素。
所以它最适合承载的是“系统没有现成组件,但你又想完全自己控制”的可视区。
Image面板讲的是“资源展示效率”
第三块内容用三个等宽色块模拟图片卡片:
Row({space:6}){Column(){Text('1')}.layoutWeight(1)Column(){Text('2')}.layoutWeight(1)Column(){Text('3')}.layoutWeight(1)}这里的重点是layoutWeight(1)。它让三张图天然等比分布,很适合做图库、对比展示、商品缩略图和相册入口。
相比Canvas和Web,Image更偏内容呈现本身,而不是行为容器或自绘能力。
这三个组件到底怎么选
案例最后那块功能对比区,方向是对的。你可以把它进一步归纳成一个更实用的判断法。
- 需要嵌网页、承载 H5 内容、做混合页:优先
Web - 需要完全自定义图形表现:优先
Canvas - 需要稳定展示视觉资源:优先
Image
很多页面不是三选一,而是三者组合。关键不是“哪个更强”,而是谁负责什么。
真实业务里怎么改造成可用页面
这个骨架稍微改一下,就能变成一个富媒体演示中心。
比如:
- 第一块接真实
WebController,做帮助文档浏览页 - 第二块换成设备状态图、订单图表或进度面板
- 第三块接真实图片资源,做轮播入口或图库预览
一旦内容真实起来,这个页面就会从演示页变成一个多能力切换工作台。
这类组合页容易踩的坑
第一个坑,是把所有能力都堆在同一屏里,不做切换和分层,最后页面极其乱。
第二个坑,是只关注组件能不能放进去,不考虑每类内容的交互节奏。Web、Canvas、Image的操作方式其实完全不同。
第三个坑,是三块内容高度和样式完全脱节,导致页面像三个临时拼接的模块。
写在最后
这个案例最值得学的,不是某个组件 API,而是“组合能力”的思维。单个组件学会了只是起点,真正能落到业务里的是你怎么让它们在同一个页面里各司其职。
把这层理解建立起来,后面你看富媒体页面,就不会只盯着某一个组件了。