尧图精选

《HarmonyOS 7 精准碰一碰跨设备协作开发实战》02:触点坐标怎么变成应用里的精准落点【鸿蒙心迹】

🕒 发布时间:2026/9/27 3:50:08 📁 来源:尧图网络
上一篇我们解决了能传这一篇要解决传哪。同样一张图片碰左边进素材库碰中间进画布碰右边进属性区——坐标到底是怎么变成业务落点的先讲个我调试时遇到的事。我把CrossDrop工作台分成了三个区域左边素材库中间编辑画布右边属性面板。代码写好以后拿手机一碰——嘿不管碰哪图片全进了素材库。我当时就懵了。系统明明给了触点坐标为什么区域判断全错后来打日志才发现系统给的坐标是屏幕坐标我拿它直接和组件坐标比差了整整一个标题栏的高度。就这一个坑调了一下午。一、先搞清楚四种坐标根本不是一回事我们日常说坐标好像就是一个(x,y)。但在窗口系统里至少有四种坐标每两种之间都差着偏移量第一种——屏幕坐标。整个显示器左上角是(0,0)你碰屏幕哪一点系统返回的就是这个坐标。这个坐标是全局的不管你开了几个窗口它都是相对于整个屏幕算的。第二种——窗口坐标。相对于当前窗口的左上角。窗口标题栏、边框这些算进去没有不同系统不一样。窗口在屏幕上移了这个坐标会不会变不会它是窗口内部的。第三种——页面坐标。相对于应用内容区域。状态栏、标题栏、导航栏这些都不算从真正的内容区域开始算。第四种——组件局部坐标。相对于某个具体组件的左上角。素材库有自己的坐标画布有自己的坐标。你看从屏幕上哪一点到哪个组件的哪一块中间要换算四层。少算任何一层结果都是错的。二、一步一步拆触点坐标怎么变成业务落点我们拿一个具体例子走一遍。假设用户碰屏幕位置是(x300, y200)。第一步屏幕坐标 → 窗口坐标先知道这个触点落在哪个窗口里。系统会告诉你这个点属于CrossDrop主窗口。窗口在屏幕上的位置是(offsetX100, offsetY50)。那窗口内部坐标就是窗口内x 300 - 100 200窗口内y 200 - 50 150这一步你得问窗口要它的位置。窗口移了位置变了换算公式就要跟着变。第二步窗口坐标 → 页面坐标窗口里不是全是内容。上面有标题栏左边有侧边栏。标题栏高度是40px。那内容区域的起点就是y40。页面坐标页面x 200假设左边没有边距页面y 150 - 40 110这一步最容易漏。我第一次调的时候就忘了减标题栏高度结果所有区域判断都往下偏了一截。第三步页面坐标 → 组件区域判断现在知道了内容区域里的位置接下来判断落在哪个业务区域。CrossDrop工作台布局大概是这样左边素材库x从0到250中间画布x从250到750右边属性区x从750到1000页面x200小于250那就是落在素材库区域。碰中间画布位置x大概是500落在250~750之间那就是插入画布。碰右边属性区x大概是800大于750那就是进入待处理资源区。这段代码解决什么问题坐标转换工具。文件coordinate/CoordinateConverter.ets用途系统坐标转应用业务坐标接入位置触点事件回调后classCoordinateConverter{// 窗口在屏幕上的偏移privatewindowOffsetX:number0;privatewindowOffsetY:number0;// 标题栏高度privatetitleBarHeight:number40;// 更新窗口位置updateWindowPosition(offsetX:number,offsetY:number){this.windowOffsetXoffsetX;this.windowOffsetYoffsetY;}// 屏幕坐标 → 页面内容坐标toContentCoordinate(screenX:number,screenY:number):{x:number;y:number}{return{x:screenX-this.windowOffsetX,y:screenY-this.windowOffsetY-this.titleBarHeight};}}第四步组件区域匹配光知道坐标落在哪个大块还不够还要知道具体是哪个组件。这时候有两种做法做法一自己算边界。每个区域记录自己的位置和尺寸判断坐标在不在这个矩形里。做法二用系统的HitTest。让ArkUI自己做命中测试直接返回落在哪个组件上。自己算的好处是可控坏处是布局变了边界也要跟着改。HitTest的好处是自动跟随布局坏处是有时候你想要的业务区域和组件边界不完全一致。这段代码解决什么问题区域匹配判断。文件router/RegionMatcher.ets用途根据坐标判断业务落点接入位置坐标转换完成后interfaceRegion{id:string;name:string;x:number;y:number;width:number;height:number;handler:string;}classRegionMatcher{privateregions:Region[][];addRegion(region:Region){this.regions.push(region);}match(x:number,y:number):Region|null{for(letregionofthis.regions){if(xregion.xxregion.xregion.widthyregion.yyregion.yregion.height){returnregion;}}returnnull;}}// 使用constmatchernewRegionMatcher();matcher.addRegion({id:material,name:素材库,x:0,y:0,width:250,height:800,handler:add_material});matcher.addRegion({id:canvas,name:编辑画布,x:250,y:0,width:500,height:800,handler:insert_canvas});matcher.addRegion({id:property,name:属性区,x:750,y:0,width:250,height:800,handler:add_pending});三、坐标这块最容易踩的坑坐标转换看起来简单实际全是细节。我踩过的坑列一下第一个坑状态栏高度没算。系统返回的坐标到底算不算状态栏不同设备不一样。手机和PC不一样横屏和竖屏也不一样。这个要实测别想当然。第二个坑窗口标题栏偏移。PC上窗口有标题栏你是从窗口边框开始算还是从客户区开始算这个差几个像素判断就错了。第三个坑缩放比例。有些设备有屏幕缩放比如125%缩放。你拿到的坐标是物理像素还是逻辑像素这个一定要搞清楚。第四个坑窗口移动了。用户把窗口从左边拖到右边你还在用旧的窗口偏移量算结果全错。所以窗口位置变化的时候要监听并更新。第五个坑横竖屏切换。手机竖屏和横屏窗口尺寸完全变了。区域边界也要跟着重算。第六个坑自由窗口尺寸变了。PC上用户可以拖窗口边缘调整大小窗口尺寸变了你的区域边界也要重新布局。第二篇总结坐标转换这件事核心不是写几行换算代码而是搞清楚四种坐标之间的层级关系屏幕坐标 → 窗口坐标 → 页面坐标 → 组件局部坐标。每一层都有自己的偏移量少算一层结果就错。工程上最容易翻车的不是算法是细节状态栏高度、标题栏偏移、缩放比例、窗口移动、横竖屏切换——这些环境变量任何一个变了你的坐标换算就要跟着变。下一篇我们把难度再往上提一级PC上同时开了三个窗口用户碰屏幕的时候怎么知道他碰的是哪个窗口
上一篇/下一篇内容由系统自动关联 返回资讯列表 →