什么是换肤?
随组件状态变化而变化的外观就是皮肤。文字的变化属于逻辑范畴,因此文字不属于皮肤。
广义的换肤意味着外观的更换,包括:形状,颜色(包括背景图片)。
而狭义的换肤仅仅指代颜色的变化,不包含形状的变化。举例: 搜狗语言输入法,迅雷
为什么?
形状的变化会影响全局外观。通常,全局性设计对UI组件形状,大小,颜色和布局都是多角度考量的,哪怕移动一个像素,都可能影响全局。
典型例子:iPhone、iPad等苹果公司的工业设计就是这样。换个颜色,边角做的圆润些,山寨版的“苹果产品” 哪怕只改动了一点点,都大大消弱原设计带给用户的感观体验。
我们的UI显然是也是需要设计的,改变了UI组件的形状,无疑,对原设计产生重大的影响。
UI组件换肤的必要性:
追求丰富多彩,追求个性,这是市场需求。
UI组件根据不同的需要,会被设计成为不同的外观(哪怕功能都一样)。
如果不将外观分离出去,UI组件的功能部分将连同外观一起被“复制”成多份儿,产生大量的重复代码,不方便维护。还影响开发效率。
所以,UI组件从结构上必须将外观分离出去。
实现的理念
(1)如何定义UI组件?
UI组件 = 结构定义(固定的,不可见) + 功能定义部分(固定的,不可见) + 外观显示部分(可变的,可见)
结构定义部分规定了UI组件是由其他哪些更小的UI组件构成。
功能定义部分驱动着外观部分的变化。
外观部分与功能定义部分通过事先约定(契约)的接口,达到彼此了解的目的。
也就是说,只要符合接口的外观都可以被功能部分所使用。
以文字标签组件为例(功能定义只有一个,而外观定义可以有无数):
<结构定义>
文字标签 = 背景Sprite + 文本输入框TextField
<功能定义>
能够显示文字,并且能够设置文字属性的组件。
鼠标置于其上时,外观有所变化;鼠标移开,回复原状。
<外观1定义>
状态1:鼠标置于其上
外观1:圆形,红色
状态2:鼠标移开
外观2:方形,蓝色
<外观n定义>
状态1:鼠标置于其上
外观1:.......
状态2:鼠标移开
外观2:.......
*可以粗略这样理解:
外观是状态以及与状态相匹配的绘图逻辑的集合体。
(2)外观是可视化对象(DisplayObject)吗?
不需要是可视化对象。使用可视化对象会增加显示列表的嵌套,带来结构上的复杂性,同时也对性能有负面影响(东西越复杂,花费的心思也就要越多,对计算机来说也是一样,不是吗)。
(3)既然外观不是可视化对象,那么外观在哪里绘制呢?
结构定义部分
(4)事先约定(契约)的内容
- Inputs:结构定义部分向外观部分公开自身(DisplayObject),作为外观绘图的画板
- 状态: 事先约定了该UI组件有哪些影响外观的状态
- 绘图逻辑:每个状态对应一个绘图逻辑。绘图逻辑可被不同状态共用。
皮肤如何应用到组件上?
通过逻辑部分代码的编写,把结构部分和皮肤绑定
皮肤的变化由状态的变化驱动。
如何动态换肤?
UI组件的逻辑部分会预先设定事件监听器,用于监听“换肤”事件。
另外一种设计思路: 不支持应用程序运行期间的换肤,只支持程序启动之初的“指定皮肤”。这样做可以减少事件监听器的数量,降低UI组件体系的复杂度,间接提高性能。
外观的动画效果如何实现?
=====================================================================
皮肤状态
1. 有效(默认)
2.无效
3.鼠标移入
4.鼠标移出
5.键盘按下
6.键盘弹起
通知:
尺寸发生变化