设计稿中的颜色在大屏上看着柔和换到强光环境或小字号时可能已经无法清楚阅读。实现重点落在颜色强度、预览焦点、深浅模式、对比结果和通过等级而不是继续增加装饰组件。让前景色、背景色、字号和对比结果共同驱动预览并给出明确等级。这次实现先收住三条主线解析颜色通道明确数据从哪里开始计算对比度让主要操作真正改变状态在组件中实时预览补齐设备形态或退出路径。颜色字符串先转成线性亮度先确定哪些值必须跨布局保留。答案是颜色强度、预览焦点、深浅模式、对比结果和通过等级否则就会出现只计算颜色亮度差而忽略相对亮度会得到错误的可访问性结论。exportinterfaceVisualState{intensity:numberfocusX:numberfocusY:numberactive:booleanmode:string}exportclassFeatureController{privatestate:VisualState{intensity:0.68,focusX:0.5,focusY:0.42,active:true,mode:颜色对比检查}moveFocus(x:number,y:number):VisualState{对比度来自两个相对亮度接入计算对比度以后所有入口都通过控制器推进当前阶段。this.state.focusXMath.max(0,Math.min(1,x))this.state.focusYMath.max(0,Math.min(1,y))returnthis.getState()}updateIntensity(value:number):number{constintensity:numberMath.max(0,Math.min(1,value))this.state.intensityintensityreturnintensity计算对比度完成后控制器把结果写回颜色强度、预览焦点、深浅模式、对比结果和通过等级视图只接收本次动作产生的新状态。字号与字重影响通过等级功能状态确定后再落视觉层顶部展示结果中央放真实组件预览侧边提供颜色和字号参数。import{FeatureController}from../features/FeatureControllerinterfaceMetricItem{label:string;value:string;trend:string}EntryComponentstruct Index{privatefeatureController:FeatureControllernewFeatureController()privatemetrics:MetricItem[][{label:当前结果,value:AAA,trend:12.4%},{label:核心指标,value:9.6 : 1,trend:稳定},{label:数据范围,value:通过,trend:已更新}]privatevalues:number[][32,44,38,58,51,73,68,86,79,94]build(){Column({space:18}){Row(){Column({space:3}){Text(ACCESSIBILITY LAB).fontSize(12).fontWeight(FontWeight.Bold).fontColor(#326BFF);Text(Contrast Lens).fontSize(28).fontWeight(FontWeight.Bold).fontColor(#20293A)}.alignItems(HorizontalAlign.Start);Blank();Text(最近 30 天).fontSize(13).fontColor(#647087).padding({left:13,right:13,top:8,bottom:8}).backgroundColor(#EEF1F6).borderRadius(16);Button(生成报告).backgroundColor(#326BFF).margin({left:10})}.width(100%)Row({space:14}){ForEach(this.metrics,(item:MetricItem,index:number){Column({space:6}){Row(){Text(item.label).fontSize(13).fontColor(index0?#E9EEFF:#7D8798);Blank();Text(item.trend).fontSize(12).fontColor(index0?#BDEEDD:#159873)}.width(100%);Text(item.value).fontSize(24).fontWeight(FontWeight.Bold).fontColor(index0?Color.White:#263044).width(100%)}.layoutWeight(1).padding(17).borderRadius(18).backgroundColor(index0?#326BFF:Color.White).border({width:index0?0:1,color:#E6E9EF})},(item:MetricItem)item.label)}.width(100%)Row({space:16}){Column({space:14}){Row(){Column({space:3}){Text(趋势概览).fontSize(18).fontWeight(FontWeight.Bold).fontColor(#273044);Text(让颜色选择直接对应可读性结果).fontSize(12).fontColor(#8A94A6)}.alignItems(HorizontalAlign.Start);Blank();Text(● 实时).fontSize(12).fontColor(#169B78)}.width(100%);Row({space:10}){ForEach(this.values,(value:number,index:number){Column({space:6}){Blank();Rect().width(24).height(value*1.8).radius(8).fill(index7?#326BFF:#D5DDE9);Text((index1).toString()).fontSize(11).fontColor(#8B95A6)}.height(190).layoutWeight(1)},(value:number,index:number)index.toString())}.layoutWeight(1).width(100%);Row(){Text(平均值 68.4).fontSize(12).fontColor(#7F899A);Blank();Text(峰值 9.6 : 1).fontSize(12).fontColor(#326BFF)}.width(100%)}.layoutWeight(1).height(100%).padding(20).backgroundColor(Color.White).borderRadius(22).border({width:1,color:#E7EAF0})Column({space:14}){Text(结果解读).fontSize(17).fontWeight(FontWeight.Bold).fontColor(#273044).width(100%);Stack(){Circle({width:180,height:180}).fill(#EDF1F7);Progress({value:78,total:100,type:ProgressType.Ring}).width(156).height(156).color(#326BFF).style({strokeWidth:12});Column({space:3}){Text(9.6 : 1).fontSize(25).fontWeight(FontWeight.Bold).fontColor(#263044);Text(AAA).fontSize(12).fontColor(#7F899B)}}.width(100%).height(190);Column({space:8}){Row(){Circle({width:8,height:8}).fill(#326BFF);Text(主要数据).fontSize(13).fontColor(#556176).margin({left:8});Blank();Text(68%).fontSize(13).fontColor(#556176)}.width(100%);Row(){Circle({width:8,height:8}).fill(#54C7EC);Text(辅助数据).fontSize(13).fontColor(#556176).margin({left:8});Blank();Text(22%).fontSize(13).fontColor(#556176)}.width(100%);Row(){Circle({width:8,height:8}).fill(#D9DFE8);Text(其他).fontSize(13).fontColor(#556176).margin({left:8});Blank();Text(10%).fontSize(13).fontColor(#556176)}.width(100%)}.width(100%).padding(14).backgroundColor(#F6F8FB).borderRadius(15)}.width(290).height(100%).padding(20).backgroundColor(Color.White).borderRadius(22).border({width:1,color:#E7EAF0})}.layoutWeight(1).width(100%)}.width(100%).height(100%).padding(24).backgroundColor(#F5F7FA)}}预览区直接呈现真实组件收尾路径与成功路径同样明确资源释放、版本失效和状态保留各自处理。}toggle():boolean{this.state.active!this.state.activereturnthis.state.active}getState():VisualState{return{intensity:this.state.intensity,focusX:this.state.focusX,focusY:this.state.focusY,active:this.state.active,mode:this.state.mode}}}离开ContrastLens页面时当前颜色强度、预览焦点、深浅模式、对比结果和通过等级按会话归属收尾再次进入后不会叠加旧任务。ContrastLens的计算与呈现下面是ContrastLens当前使用的目录。pages负责顶部展示结果中央放真实组件预览侧边提供颜色和字号参数features保存本文展示的业务链路。ContrastLens/ ├─ entry/src/main/ets/ │ ├─ pages/Index.ets # 首屏与响应式布局 │ ├─ features/FeatureController.ets # 模型、动作和边界 │ ├─ entryability/EntryAbility.ets # 页面入口与生命周期 │ └─ adapters/ # 真机能力或数据源接口 ├─ entry/src/main/resources/ # 颜色、文字和媒体资源 └─ build-profile.json5 # 工程构建配置Index.ets只组合界面FeatureController.ets处理颜色强度、预览焦点、深浅模式、对比结果和通过等级。如果后面接入真实设备或网络服务只需增加适配器并把结果转换成控制器认识的状态。ContrastLens最终把解析颜色通道、计算对比度和在组件中实时预览连在同一条状态路径中。