一套代码适配四种屏幕——StyleConfiguration 键盘多设备适配方案
文章目录问题在哪StyleConfiguration 的设计思路KeyStyle 接口定义StyleConfiguration.getInputStyle 完整逻辑资源文件命名规范组件如何使用 StyleConfiguration屏幕旋转适配完整流程这种设计模式的通用价值踩坑记录写在最后搞输入法开发最头疼的事情之一就是屏幕适配手机竖屏、手机横屏、平板竖屏、平板横屏键盘的尺寸、按键大小、字体都不一样。KikaInputMethod 里的StyleConfiguration用了一套挺优雅的方案值得借鉴。问题在哪不同设备键盘的差异点场景特点挑战手机竖屏键盘宽高度有限按键小字体要适配手机横屏键盘更宽高度更有限按键要更扁平板竖屏分辨率高空间充足按键可以更大平板横屏宽度极大按键宽度要重新分配RK 开发板分辨率特殊720×1280完全独立的样式集如果每个场景都用 if-else 直接写死数值代码会变成噩梦。StyleConfiguration 的设计思路核心思路把样式选择和样式使用分离。KeyStyle 接口定义所有设备共享同一套接口只是资源值不同exportinterfaceKeyStyle{deviceType?:string;// 按键尺寸 basicButtonWidth:Resource;// 普通字母键宽度basicButtonHeight:Resource;// 按键高度switchButtonWidth:Resource;// 切换键数字/符号宽度returnButtonWidthType1:Resource;// Enter 键宽度类型1returnButtonWidthType2:Resource;// Enter 键宽度类型2spaceButtonWidth1:Resource;// 空格键宽度1spaceButtonWidth2:Resource;// 空格键宽度2// 图标尺寸 featurePicSize:Resource;// 功能图标大小returnPicSize:Resource;// 回车图标大小editPicSize:Resource;// 编辑图标大小editImageSize:Resource;// 编辑图片大小// 间距 paddingTop:Resource;// 键盘顶部内边距paddingLeftRight:Resource;// 左右内边距// 下拉菜单 downMenuHeight:Resource;downMenuPicWidth:Resource;downMenuPicHeight:Resource;downMenuWidth:Resource;subMenuWidth:Resource;// 字体 litterNumberFontSize:Resource;// 小号数字字体en_fontSize:Resource;// 英文字体大小symbol_fontSize:Resource;// 符号字体大小switchNumberFontSize:Resource;// 切换按钮字体// 其他 keyboardHeight:Resource;// 键盘总高度editCircleSize:Resource;// 编辑圆圈大小editSmallCircle:Resource;editSmallCircleMargin:Resource;editButtonSize:Resource;editFontSize:Resource;editDriverLeft:Resource;}StyleConfiguration.getInputStyle 完整逻辑import{deviceInfo}fromkit.BasicServicesKit;exportclassStyleConfiguration{// 组件初始化时调用从 AppStorage 读取已计算好的样式// 如果 AppStorage 里还没有第一次就重新计算staticgetSavedInputStyle():KeyStyle{letstyleAppStorage.getKeyStyle(inputStyle);if(style){returnstyle;}// AppStorage 里没有用默认值计算letisLandscapeAppStorage.getboolean(isLandscape)??false;letisRkDeviceAppStorage.getboolean(isRkDevice)??false;returnStyleConfiguration.getInputStyle(isLandscape,isRkDevice,deviceInfo.deviceType);}// 根据设备信息选择对应样式集staticgetInputStyle(isLandscape:boolean,isRkDevice:boolean,deviceType:string):KeyStyle{// 优先级1RK 开发板独立适配if(isRkDevice){return{basicButtonWidth:$r(app.float.rk_basic_button_width),basicButtonHeight:$r(app.float.rk_basic_button_height),en_fontSize:$r(app.float.rk_en_fontSize),// ... 其他 rk_* 资源};}// 优先级2平板设备if(deviceTypetablet){if(isLandscape){return{deviceType:tablet_landSpace,basicButtonWidth:$r(app.float.landSpace_basic_button_width),basicButtonHeight:$r(app.float.landSpace_basic_button_height),en_fontSize:$r(app.float.landSpace_en_fontSize),symbol_fontSize:$r(app.float.landSpace_symbol_fontSize),// ... 其他 landSpace_* 资源};}else{return{deviceType:tablet_portrait,basicButtonWidth:$r(app.float.portrait_basic_button_width),basicButtonHeight:$r(app.float.portrait_basic_button_height),en_fontSize:$r(app.float.portrait_en_fontSize),// ... 其他 portrait_* 资源};}}// 优先级3手机if(!isLandscape){// 手机竖屏return{basicButtonWidth:$r(app.float.s_basic_button_width),basicButtonHeight:$r(app.float.s_basic_button_height),en_fontSize:$r(app.float.en_fontSize),keyboardHeight:$r(app.float.keyboard_height),// ... 其他 s_* 资源};}else{// 手机横屏return{basicButtonWidth:$r(app.float.h_basic_button_width),basicButtonHeight:$r(app.float.h_basic_button_height),en_fontSize:$r(app.float.en_fontSize),// ... 其他 h_* 资源};}}}资源文件命名规范每种设备的样式值存在resources/base/element/float.json里用前缀区分rk_* → RK 开发板 s_* → 手机small/standard竖屏 h_* → 手机横屏horizontal landSpace_* → 平板横屏 portrait_* → 平板竖屏比如按键高度{float:[{name:s_basic_button_height,value:40.0},{name:h_basic_button_height,value:32.0},{name:portrait_basic_button_height,value:48.0},{name:landSpace_basic_button_height,value:36.0},{name:rk_basic_button_height,value:36.0}]}组件如何使用 StyleConfiguration所有键盘组件通过StorageLink响应式读取样式// SpaceItem.etsComponentexportstruct SpaceItem{StorageLink(inputStyle)inputStyle:KeyStyleStyleConfiguration.getSavedInputStyle();build(){Stack(){Text(space).fontSize(this.inputStyle.symbol_fontSize)// 根据设备自动适配字体}.width(this.spaceWith).height(100%).onClick((){InputHandler.getInstance().insertText( );})}}// KeyItem.etsComponentexportstruct KeyItem{StorageLink(inputStyle)inputStyle:KeyStyleStyleConfiguration.getSavedInputStyle();build(){Stack(){Text(this.keyValue).fontSize(this.inputStyle.en_fontSize)// 字体自适应}.width(this.inputStyle.basicButtonWidth)// 按键宽度自适应.height(this.inputStyle.basicButtonHeight)// 按键高度自适应}}当屏幕旋转时KeyboardController.resizePanel()重新计算inputStyle并更新 AppStorage所有组件自动重新渲染。屏幕旋转适配完整流程startuml title 屏幕旋转适配流程 :用户旋转设备; :display.on(change) 触发; :KeyboardController.resizePanel(); :display.getDefaultDisplaySync()\n获取新的宽高; :重新判断 isLandscape; :StyleConfiguration.getInputStyle(\n newIsLandscape, isRkDevice, deviceType\n); :AppStorage.setOrCreate(inputStyle, newStyle); note right: StorageLink 自动通知\n所有键盘 UI 组件重新渲染 :panel.resize(newWidth, newHeight); note right: 同步更新面板尺寸\n保证键盘显示正确 enduml这种设计模式的通用价值StyleConfiguration的设计不只适合输入法任何需要多设备适配的应用都可以用类似的模式// 通用适配模式classThemeConfig{// 1. 定义统一接口interfaceAppTheme{fontSize:Resource;padding:Resource;buttonHeight:Resource;// ...}// 2. 根据设备类型选择具体值staticgetTheme(deviceType:string,isLandscape:boolean):AppTheme{if(deviceTypetablet){returnisLandscape?tabletLandscapeTheme:tabletPortraitTheme;}returnisLandscape?phoneLandscapeTheme:phonePortraitTheme;}}// 3. 应用启动时存入 AppStorageAppStorage.setOrCreate(appTheme,ThemeConfig.getTheme(deviceType,isLandscape));// 4. 组件通过 StorageLink 使用StorageLink(appTheme)theme:AppThemeThemeConfig.getTheme(phone,false);踩坑记录坑1getSavedInputStyle 的兜底逻辑要完整getSavedInputStyle会在组件初始化时调用这时KeyboardController.initWindow可能还没执行完Panel 还没创建好AppStorage里可能没有inputStyle。所以getSavedInputStyle必须有完整的兜底计算逻辑不能直接返回undefined。坑2resizePanel 要同时更新样式和面板尺寸旋转时只调panel.resize但不更新inputStyle键盘 UI 会显示旧样式只更新inputStyle但不调panel.resize面板大小不对。两个操作都要做。坑3$r() 资源引用在 StyleConfiguration 里不是问题StyleConfiguration是一个普通类不是 ArkUI 组件但$r()在非组件环境里仍然有效它返回的是Resource类型组件里用的时候才实际解析。写在最后StyleConfiguration AppStorage StorageLink这套组合拳用在输入法适配上效果很好运行时根据设备信息选一次样式存入 AppStorage所有组件响应式读取屏幕旋转时重新计算更新整个过程不需要手动通知任何组件。这个设计模式值得在其他多设备项目里复用。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2629137.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!