用Bolt引擎实现换肤指南
提到界面引擎,大家一定会想到“换肤”这个关键字。的确,使用界面引擎开发的产品,其换肤功能的实现会比使用系统API开发的简单很多。也有很多朋友经常问我们:“你们的界面引擎支持换肤么? ”其实在不同产品之间,换肤的需求千变万化,引擎的开发者也不可能开发出一个“万金油”型的换肤功能来,而固定的换肤功能又往往不能满足开发者的需要。
在这一点上,Bolt引擎认为:换肤功能应该被放在产品层面,而不是引擎层面;引擎则提供完成换肤功能所必要的自由度和基础功能。基于这些功能,产品可以定制自己的换肤需求,然后使用界面引擎将其方便快速地实现。
常见的换肤需求一般有以下几种:
1. 控件资源换肤(比如windows XP的主题改变),但控件的布局不变
2. 换肤同时改变整个界面布局(比如WindowsMeidaPlayer)
3. 用户可以通过自定义的图片改变产品的界面(win7的主题)
在原有Windows API下这些需求的实现,使用简单的伪代码描述如下:
1. 假设按钮控件资源换肤
LRESULT MyButton::OnDrawItem()
{
Const char* resid = ResManager.GetResidByCtrlId(m_id);
//换肤后得到不同的hBitmap
HBITMAP hBitmap = SkinManager.GetBitmapByResid(resid);
HDC dc = GetDC();
DrawBitmap(dc,hBitmap)
}
Void SkinManager::ChangeSkin(skinName)
{
ResManager.LoadFrom(skinName.zip);
UpdateAllWindowInProcess();
}
2. 改变界面布局
LRESULT MyWind::OnDrawItem()
{
PosInfo nowpos = SkinManager.GetPosByCtrlId(m_id);
MoveWindow(m_hWnd, nowpos.left, nowpos.top, nowpos.width, nowpos.height);
UpdateWindow();
}
3. 自定义图片
LRESULT MyBkg::OnDrawItem()
{
Const char* imagePath = GetBkgPath();
Int nWidth = 0, nHeight = 0;
HBITMAP hBitmap = SkinManager.LoadBitmapFromPath(imagePath, &nWidth, &nHeight);
DrawState(dc, NULL, NULL, hBitmap, 0, 0, 0, 0, 0, DST_BITMAP|DSS_NORMAL);
UpdateWindow();
}
以使用Bolt引擎开发的迅雷7为例,迅雷7的换肤功能相当强大,除了提供毛玻璃效果、部分透明度调整、任意图片做背景图片之外,还有界面元素调色方案、自动调色、字体效果更换等进阶的换肤功能,而这些功能在其他的产品中是难以见到的。总而言之,迅雷7中的换肤需求有以下几点:
1. 任意图片作为背景图片
2. 界面元素的透明度调整,可以整体调整也可以分块调整
3. 界面边缘阴影
4. 界面毛玻璃效果
5. 界面元素的统一调色
6. 字体的统一更换
引擎按照粒度的层级,将换肤的层次由低到高分为4个层次:对象层、资源层、XAR包层、逻辑层。层次越低,换肤涉及到的对象就越底层,自由度就相对越小。迅雷7的换肤功能主要集中在对象层和资源层,以不改变基本界面样式为前提。应用后两层的换肤方法,可以将换肤应用到产品的每一个角落,实现真正意义上的“随意换”。
在以下的章节中,我们会按照由低到高的层次顺序,辅以迅雷7的换肤需求,讲解不同层面上换肤效果的设计思路。
2. 初级换肤:第一层,对象层面的换肤处理
对象层面的换肤,是通过对对象树上单个元素的改变,达到换肤的效果。迅雷7换肤需求中的1、2、3三点,就属于对象层面。
产品中最大的界面元素,也是最容易被人忽略的元素,就是软件背景。不像传统基于Windows的开发,在引擎中窗口的背景也是界面对象树的一部分。由于引擎的分层设计特性,对象树必须需要一个足够大的根元素来承载上层的其他元素,此时这个“根元素”就可以作为产品的背景使用。再加上引擎可以实时更改元素的特性,这样最初级的换肤功能就实现了。
下面是一个简单实现了自定义图片背景,填充背景和毛玻璃效果的背景控件的结构,产品的布局可以建立在这个背景控件的基础之上。在这个结构中,几个Object的大小都是相同的,图上这种表示方式是为了清晰地显示出控件结构。其中,ImageObject用于放置自定义的背景图片,FillObject则是为了当背景图片不够大,或者没有背景图片时充当填充背景所用。
BkgCtrl的控件结构
通常情况下,充当背景元素的对象一般是ImageObject,TextureObject和FillObject三种。
ImageObject是位图对象,可以显示一张位图,并且有平铺、拉伸、原图三种显示方式,水平和垂直对齐方式也是可调的。迅雷7的图片背景就是使用ImageObject实现的。从文件中读取图片和图片大小等信息,可以使用XLGraphic中的对应C接口来完成。TextureObject是纹理对象,可以按照资源文件中配置的方式,显示一张符合Bolt引擎定义的纹理。若是不想放置图片,也可以用填充对象(FillObject)来充当背景。FillObject可以用单色、线性、圆形这几种填充方法,将指定的颜色填充到其中去。迅雷7的默认背景就是用FillObject做出的。
关于界面透明的实现,引擎中所有元对象都可以通过SetAlpha函数来单独地调整透明度。注意此处透明度的调整只限于该对象本身,对该对象的子对象没有影响。
另外要注意的是,界面透明,边缘阴影和Vista以后系统下毛玻璃效果的实现,都依赖于开启主窗口的layer属性。层窗口(Layered窗口)是Windows XP以后支持的窗口特性。开启了layer属性的窗口渲染时可以进行alpha混合,而没开启layer属性的窗口在绘制时则忽略alpha属性。由于系统实现上的原因,XP系统下,非layer窗口的渲染效率要比layer窗口高;Vista及以后系统则相反,layer窗口的绘制效率更高。
那么,在bolt引擎中又该如何实现毛玻璃效果呢?毛玻璃效果是通过在界面上放置BlurObject来实现的,想要毛玻璃效果生效,还需配置主窗口的blur属性为1。另外,BlurObject也属于元对象,可以任意调整大小,移动位置。因此,在界面上实现部分毛玻璃效果也是可行的。
3. 中级换肤:第二层,现有资源层面的换肤处理
现有资源层面的换肤,指对现有资源包中的资源进行处理,比如调色、更换字体等。由于一个资源可以被多个对象使用,改变一个资源就可以改变多个对象的视觉效果。
在Bolt引擎中,每一个能被加载的资源(包括位图、纹理、颜色、字体等),都有一个在本资源包中不重复的id,引擎可以根据id来对指定的资源进行处理。
能做到这一点,正是基于引擎的资源预处理(Pretreat)机制,用户可以对一类资源设置自己的预处理函数。预处理机制在渲染这类资源之前,使用者可以通过预处理函数来改变资源渲染的结果,包括调色、划线、增加文字等;具体可参见引擎参考手册。
下面是一个有关设置Pretreat函数的小例子,用Lua代码写成:
local function ModifyWith(h, s, v, bepaint)
local function Pretreat(resId, resObj)
resObj:ModifyColor(h, s, v, bepaint)
end
return Pretreat
end
local xarManager = XLGetObject("Xunlei.UIEngine.XARManager")
xarManager:SetBitmapPretreater(“mainxar::default.bitmap”, ModifyWith(h,s,v,1))
xarManager:CommitPretreater()
其中,SetBitmapPretreater函数是设置预处理函数的关键,函数原型为SetBitmapPretreater(resID, function),其中ResID为想要设置预处理函数的资源ID,例子中“mainxar::default.bitmap”代表了mainxar包中的default.bitmap资源;为处理大型产品有多个xar包的情况,SetBitmapPretreater函数是xar相关的,可以通过”xar包名::资源ID”的形式来指定某个xar包中的资源。如果不指定包名,则该函数会被设置到所有加载的xar包中。Function是一个自定义的lua函数,这个lua函数必须返回一个原型为preatret(resID, resObj)的lua函数,当被设置的资源ID被渲染时,引擎会主动调用该preatret(resID, resObj)函数,用户可以在函数内对resObj进行操作,改变渲染结果。
要注意的是,对于不同种类的资源,设置预处理的函数也是不同的,目前已经支持的有:
l SetBitmapPretreater
l SetColorPretreater
l SetTexturePretreater
l SetImageSeqPretreater
该例中,设置的预处理函数只对资源做了ModifyColor操作,即对资源进行调色。ModifyColor使用HSV颜色空间进行调色,与一般的RGB颜色空间不同,可以使用XLGraphic提供的C函数来进行RGB和HSV之间的转换。
最重要的一点:设置完成后不要忘了调用CommitPretreater来提交预处理函数的修改,否则设置的预处理函数会不起作用。
为了方便大家调色,XLGraphic提供了C函数XL_GetBitmapMainColor,用于获取位图的主色调,方便大家调色使用,达到界面一致的效果。
4. 高级换肤:第三层,xar层面的换肤处理
前两层的换肤处理,都是通过改变已有的对象来达到目的。引擎支持一个xar包中带有多个资源包,并且在运行过程中可以实时更换资源包来达到换肤的效果。
更换资源包可以调用xarManager的SelectResPackage方法,注意新包加载完成以后,之前资源包中所有的资源对象都会被释放。具体可参见开发文档。资源包可以在xar的package.cfg文件中配置。
在资源包的resource.cfg文件中,可以通过添加loadscript和unloadscript节点,自定义资源包load和unload时的脚本,给予开发者更大的自由度。
这里要注意一下,资源替换和资源预处理的区别。资源预处理只能针对已经加载完成的资源包,即只能对现有资源的基础上进行一些小的改变,改变针对的是某个特定的资源;而资源替换则是将旧有的资源包整个替换成为新的资源包,这是针对所有资源的改变。
5. 终极换肤:第四层,逻辑层面的换肤处理
到了这一层,“换肤”已经不是一个具体的功能或者函数,而是一种思想。利用Bolt引擎运行中更改对象状态的特性,“换肤”可以不局限在调整资源和颜色的范畴中,对界面元素的位置,层次甚至个数的调整也是可能的。这一层次的定制灵活性最大,要根据需求的具体情况具体分析。
具体来说,就是通过XLLuaRuntime的相关功能,在换肤的时候执行一段自定义的脚本,通过脚本来实现对布局的修改。
6. 皮肤包和皮肤管理器设计指南
上面的4个换肤层次,主要解释了引擎在换肤方面提供的功能。要将这些功能整合起来,一般会需要开发者自己实现一个“皮肤管理器”,将以上的几部分功能统合起来,真正为己所用。接下来我们就简单看一下,皮肤包和皮肤管理器所应该具有的功能。
要实现第一层级的换肤,更换背景图片、调整透明度等,皮肤包中就要有一个存储了背景图片、透明度设定等的皮肤配置文件;皮肤管理器可以从配置文件中读取各种设定,来通知界面进行改变。管理器最好还能有事件注册机制,界面Lua可以向皮肤管理器中注册事件,当设定更改之后,管理器可以通知Lua,让Lua部分作更灵活的调整。
实现第二层级的换肤,皮肤包应该有一个调色配置文件,调色配置文件包含可调色的资源id,皮肤管理器通过读取配置文件,得到可调色的资源id。当背景图片或者填充对象发生变化时,可以通过这些资源id来调用相对应的SetPretreater函数,达到配色效果。
实现第三层次的换肤效果,可以将额外的资源包放在皮肤包中,管理器通过XLFSIO的映射函数将资源包映射到资源目录中去,就可以通过SelectResPackage函数来更换资源包了。
对于第四层次,逻辑层面的换肤,皮肤包也可以包括一些lua脚本文件作为换肤脚本,皮肤管理器在加载皮肤包的时候,通过XLLuaRuntime的相关接口来执行换肤脚本,达到完全自定义的效果。
用Bolt引擎实现换肤指南相关推荐
- android 第三方登录界面,Android App集成第三方登录与换肤指南
Android App集成第三方登录与换肤指南 文档编辑 概述 本文主要是介绍了如何通过开源框架快速支持QQ和微信登录,并介绍了如何实现app快速换肤 QQ登录接入 APP要支持QQ登录,需要先到腾讯 ...
- Android 换肤指南
一.换肤方案 目前,市面上Android的换肤方案主要有Resource方案和AssetManager替换方案两种方案. 其中,Resource方案是用户提前自定义一些主题,然后将指定主题对应的 id ...
- Android-skin-support换肤框架使用指南
1.介绍 针对Android应用的换肤需求,通过Android-skin-support框架可以很好地优化APP的代码结构,不需要将所有皮肤的图片资源和xml放在一起,通过相关接口,加载相应主题的皮肤 ...
- Qt - 换肤功能实现
文章目录 前言 Qt内置风格 QPalette QSS QSS样式 一般样式 选择器 子控件 伪状态 属性 使用 分离QSS 推荐工具 Qsseditor QssStylesheetEditor QS ...
- Wince输入法换肤换语言机制
需求描述: 最近由于邦健客户提出新需求:需要在一个系统内同时实现中英文两个语种的输入法. 即,客户的wince系统语言版本是中文,但在其中的应用软件有中文和英文两个版本,所以相应的输入法也需要做调整, ...
- opengl源码 实现无缝切换图片过场_手把手讲解 Android hook技术实现一键换肤
前言 产品大佬又提需求啦,要求app里面的图表要实现白天黑夜模式的切换,以满足不同光线下都能保证足够的图表清晰度. 怎么办?可能解决的办法很多,你可以给图表view增加一个toggle方法,参数Str ...
- JXTheme:iOS9+换肤/暗黑模式最佳方案之一,轻量级、高度自定义、swift编写
简介 2018年苹果在macOS系统引入了暗黑模式,一经推出广受好评.尤其是我们程序员,经常与代码.文本打交道,亮色风格的界面看久了,眼睛会特别累.有了暗黑模式之后,我们的眼睛终于能被温柔对待了.而且 ...
- 前端JavaScript(1) --Javascript简介,第一个JavaScript代码,数据类型,运算符,数据类型转换,流程控制,百度换肤,显示隐藏...
一.Javascript简介 Web前端有三层: HTML:从语义的角度,描述页面结构 CSS:从审美的角度,描述样式(美化页面) JavaScript:从交互的角度,描述行为(提升用户体验) Jav ...
- 一键换肤丨酷雷曼VR全景系统皮肤高燃登场
重磅更新,酷雷曼VR全景系统皮肤高燃登场,一键换肤,全景作品外观皮肤随意选择,想用哪款用哪款. 酷雷曼VR全景皮肤功能,为各行各业定制更适合行业属性以及行业需求的实用性功能皮肤,采用一键换肤的快捷方式 ...
- python 全栈开发,Day50(Javascript简介,第一个JavaScript代码,数据类型,运算符,数据类型转换,流程控制,百度换肤,显示隐藏)...
一.Javascript简介 Web前端有三层: HTML:从语义的角度,描述页面结构 CSS:从审美的角度,描述样式(美化页面) JavaScript:从交互的角度,描述行为(提升用户体验) Jav ...
最新文章
- als算法参数_Spark2.0协同过滤与ALS算法介绍
- java 压缩多个文件_java实现一次性压缩多个文件到zip中的方法示例
- eclipse远程调试失败
- 第九章 转移指令的原理
- 在nodejs中创建cluster
- SAP CRM WebClient UI根据扩展字段搜索出结果的实现原理
- JavaEE Tutorials (25) - 使用Java EE拦截器
- mongodb的副本集总结
- Spring Boot + WebMagic 实现网页爬虫,写得太好了!
- 判断数组是否为某二叉搜索树的后序遍历
- 星辰数据空号检测API文档
- CS5216 Capstone DP to hdmi 1080p转换器或者转接线设计原理|CS5216 DP转HDMI转换电路原理图
- CSDN博客给我带来的一些诱惑和选择机会
- Python学多久才能独立接单赚钱?一个月足够了,本人私藏的学习计划分享给大家
- PCFG句法分析之CYK算法
- 关于陌陌和微信表情页与输入法之间切换的问题
- 在EXCEL下用VBA编程提高人事数据的管理效率
- 【Simulink】粒子群算法(PSO)整定PID参数(附代码和讲解)
- ChemDraw Professional for Mac 16.0.1.4 专业的生物化学绘图软件
- 视觉惯性里程计 VIO
热门文章
- CSDN VIP 常见问题解答
- 京瓷1020怎么打印自检页_惠普打印机怎样打印测试页
- 统计项目代码行数的工具——SLOCCount
- [双十二优惠大放送] 我是小册姐,我因掘金小册而被创造,谢谢你们20天的陪伴...
- fortran语言能用matlab,fortran语言与matlab
- 6天掌握记忆宫殿,你就是记忆大师
- 集装箱装柜计算机器在线,装箱大师在线计算教程
- scratch3文件转exe文件方法
- 北京理工大学计算机学院2021拟录取名单,北京理工大学管理与经济学院2021年硕士研究生拟录取通知...
- Latex笔记:IEEE Access模板 图片排版问题汇总