编辑海报时临时把折叠屏展开画布面积变大了但刚才选中的元素、缩放比例和撤销记录不能跟着消失。折叠屏展开后不该丢掉编辑进度海报画布如何保持连续需要的不只是首屏效果还要补上画布元素、选中标识、坐标变换和撤销快照。把画布状态从具体页面布局中抽离让折叠态、展开态和宽屏态读取同一份编辑数据。这次按【确定画布坐标系 → 建立元素模型 → 实现选中与移动 → 加入缩放和撤销 → 最后处理形态切换】逐层推进先让关键动作跑通再安排折叠态保留画布与主操作展开后增加图层栏和属性面板。展开屏幕前先固定画布坐标窗口尺寸变化时重新创建页面导致选中元素回到第一项甚至把编辑历史清空。因此先把画布元素、选中标识、坐标变换和撤销快照写成独立模型页面只订阅结果。exportinterfaceCanvasPoint{x:numbery:number}exportinterfaceCanvasElement{id:stringname:stringx:numbery:numberscale:numberopacity:numberselected:boolean}interfaceCanvasSnapshot{elements:CanvasElement[]selectedId:string}exportclassFeatureController{privateelements:CanvasElement[][{id:hero,name:折叠海报画布主视觉,x:120,y:88,scale:1,opacity:1,selected:true},{id:copy,name:标题文本,x:156,y:246,scale:1,opacity:1,selected:false},{id:light,name:氛围光层,x:410,y:120,scale:1.2,opacity:0.42,selected:false}]privatehistory:CanvasSnapshot[][]privateselectedId:stringhero这些字段不引用具体组件折叠屏和平板只需选择自己的呈现方式。一次拖动怎样进入撤销栈实现选中与移动从一个明确命令开始。命令带上目标和输入控制器完成判断后再提交修改。组件把意图交给控制器真正的数据修改只发生在这里。getElements():CanvasElement[]{returnthis.elements}select(id:string):boolean{constexists:booleanthis.elements.some((item:CanvasElement)item.idid)if(!exists){returnfalse}this.selectedIdidthis.elementsthis.elements.map((item:CanvasElement)({id:item.id,name:item.name,x:item.x,y:item.y,scale:item.scale,opacity:item.opacity,selected:item.idid}asCanvasElement))returntrue}moveSelected(point:CanvasPoint):boolean{constindex:numberthis.elements.findIndex((item:CanvasElement)item.idthis.selectedId)if(index0||point.x0||point.y0){returnfalse}this.pushSnapshot()constcurrent:CanvasElementthis.elements[index]this.elements[index]{id:current.id,name:current.name,x:point.x,y:point.y,scale:current.scale,opacity:current.opacity,selected:current.selected}returntrue}updateScale(delta:number):number{constindex:numberthis.elements.findIndex((item:CanvasElement)item.idthis.selectedId)if(index0){这样处理后窗口尺寸变化时重新创建页面导致选中元素回到第一项甚至把编辑历史清空会在写入前被截住。折叠与展开不是两份页面折叠态保留画布与主操作展开后增加图层栏和属性面板。这套排列首先服务折叠屏和平板的观看距离与操作范围。首屏把实现选中与移动对应的结果放在视觉中心次要参数退到边缘区域。import{FeatureController}from../features/FeatureControllerinterfaceFeatureItem{id:numbertitle:stringdetail:string}EntryComponentstruct Index{privatefeatureController:FeatureControllernewFeatureController()StateselectedId:number1Statemessage:string展开屏幕后继续编辑同一个元素Statewide:booleanfalseStatezoomPercent:number92StateshowGrid:booleantrueStateundoCount:number0privateitems:FeatureItem[][{id:1,title:主标题,detail:可交互能力 1},{id:2,title:渐变背景,detail:可交互能力 2},{id:3,title:行动按钮,detail:可交互能力 3}]privateselected():FeatureItem{returnthis.items.find((item:FeatureItem)item.idthis.selectedId)??this.items[0]}privateselectLayer(id:number):void{this.selectedIdidthis.message正在编辑${this.selected().title}}privatechangeZoom(delta:number):void{this.zoomPercentMath.max(60,Math.min(130,this.zoomPercentdelta))this.undoCountthis.message缩放${this.zoomPercent}% · 可撤销${this.undoCount}步}privateundo():void{if(this.undoCount0){this.message没有可撤销操作;return}this.undoCount--this.zoomPercentMath.max(60,this.zoomPercent-4)this.message已撤销剩余${this.undoCount}步}build(){Row({space:14}){Column({space:12}){Text(__TITLE__).fontSize(27).fontWeight(FontWeight.Bold).fontColor(Color.White)Text(this.message).fontSize(12).fontColor(#E7E9FF)List({space:8}){ForEach(this.items,(item:FeatureItem){ListItem(){Row({space:9}){Circle({width:9,height:9}).fill(this.selectedIditem.id?#FFFFFF:#80FFFFFF);Text(item.title).fontSize(15).fontColor(Color.White).layoutWeight(1)}.padding(12).borderRadius(13).backgroundColor(this.selectedIditem.id?#36FFFFFF:#18FFFFFF).onClick(()this.selectLayer(item.id))}},(item:FeatureItem)item.id.toString())}.layoutWeight(1)Row({space:8}){Button(撤销).onClick(()this.undo());Button(this.showGrid?关闭网格:显示网格).onClick((){this.showGrid!this.showGrid})}}.width(this.wide?31%:38%).height(100%).padding(18).borderRadius(24).backgroundColor(__ACCENT__)Column({space:14}){Row(){Text(画布).fontSize(18).fontWeight(FontWeight.Bold);Blank();Text(${this.zoomPercent}%).fontColor(__ACCENT__)}.width(100%)Stack(){Rect().width(${this.zoomPercent}%).height(${Math.min(82,this.zoomPercent*0.65)}%).radius(24).fill(#EEF0F8)Column({space:10}){Text(this.selected().title).fontSize(27).fontWeight(FontWeight.Bold).fontColor(__ACCENT__);Text(选中元素保持稳定窗口变化后继续编辑).fontSize(12).fontColor(#667085)}.padding(24)}.layoutWeight(1).width(100%).backgroundColor(this.showGrid?#F7F8FC:Color.White).borderRadius(24)Row({space:10}){Button(缩小).onClick(()this.changeZoom(-4));Button(放大).backgroundColor(__ACCENT__).onClick(()this.changeZoom(4))}}.layoutWeight(1).height(100%).padding(18).borderRadius(24).backgroundColor(Color.White)}.width(100%).height(100%).padding(18).backgroundColor(#F2F4F8).onAreaChange((oldArea:Area,newArea:Area){this.wideNumber(newArea.width)760})Index.ets在这里读取控制器结果并组织折叠态保留画布与主操作展开后增加图层栏和属性面板。计算仍留在功能层因此更换设备形态只需调整区域组合。旋转之后找回正在编辑的元素加入缩放和撤销结束后仍可能收到旧事件下面的代码先判断阶段再决定保留或回退。return1}this.pushSnapshot()constcurrent:CanvasElementthis.elements[index]constnext:numberMath.max(0.4,Math.min(2.4,current.scaledelta))this.elements[index]{id:current.id,name:current.name,x:current.x,y:current.y,scale:next,opacity:current.opacity,selected:current.selected}returnnext}undo():boolean{constsnapshot:CanvasSnapshot|undefinedthis.history.pop()if(!snapshot){returnfalse}this.selectedIdsnapshot.selectedIdthis.elementssnapshot.elements.map((item:CanvasElement)({id:item.id,name:item.name,x:item.x,y:item.y,scale:item.scale,opacity:item.opacity,selected:item.selected}asCanvasElement))returntrue}privatepushSnapshot():void{this.history.push({selectedId:this.selectedId,elements:this.elements.map((item:CanvasElement)({id:item.id,name:item.name,x:item.x,y:item.y,scale:item.scale,opacity:item.opacity,selected:item.selected}asCanvasElement))})if(this.history.length30){this.history.shift()}}}失败结果保留最近一次有效状态并给最后处理形态切换留下重新进入的入口。FoldCanvas的文件落点下面是FoldCanvas当前使用的目录。pages负责折叠态保留画布与主操作展开后增加图层栏和属性面板features保存本文展示的业务链路。FoldCanvas/ ├─ 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处理画布元素、选中标识、坐标变换和撤销快照。如果后面接入真实设备或网络服务只需增加适配器并把结果转换成控制器认识的状态。到这里确定画布坐标系与最后处理形态切换已经接到同一份状态上界面变化不会切断编辑过程。
企业数字化 ERP 产品动态
相关推荐
Claude Code 50+ 命令实战:用 TaoToken 统一 Key 打通 CLI 斜杠指令与快捷键 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 22:00:23
华为OD机试真题 新系统 2026-09-13 JavaGoC【受限序列重排】 目录
题目
思路
Code
题目
题目内容:
给定一个包含 n 个整数的数组 nums 和一个整数 k,需要将 nums 中的所有元素重新排列,生成一个新的序列。
数组下标从 0 开始,新序列中下标为 k-1 的元素和下标为 k 的元素不能相同。
请统计满足条件的不同排列数量,相同的数组… · 2026/9/27 22:00:23
风洞湍流速度场的粗糙度分析与能量耗散建模——基于PIV实验数据的湍流标度律研究 一、问题背景
湍流是自然界和工程应用中最普遍的流体流动形态之一。从航空航天中的飞行器绕流、能源动力中的燃气轮机燃烧,到汽车高速行驶的气动阻力、高层建筑的风致振动,无不涉及湍流问题。湍流的核心特征之一是能量级串(energy cascade&am… · 2026/9/27 22:33:34
500美元租个AI程序员?Devin 20亿美元背后的真相与谎言:用TaoToken统一Key实测AI工具链 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 22:33:34
OpenCode 完全使用指南:开源 AI 编程助手入门到精通(TaoToken 配置篇) /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 22:33:34
凌晨四点,我的 Claude Trace 日志泄露了用户手机号:一次 GDPR 合规排查与配置加固实录 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 22:33:34
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现 简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01
汕头网站建设制作厂家避坑指南:5大注意事项救急 汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习 简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现 简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01
汕头网站建设制作厂家避坑指南:5大注意事项救急 汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习 简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01