索引
和核心包一样,UI
支持 htconfig 全局变量配置全局字体、文字颜色等,格式如下:
<script>
htconfig = {
uiTheme: {
font: '14px arial', // 所有组件的字体
inputBackground: 'rgb(22,27,34)' // 所有输入框背景色
}
}
</script>
<script src="ht.js"></script>
<script src="ht-ui.js"></script>
如上所示,在 htconfig
对象中通过 uiTheme
可以为页面中的所有 UI
组件统一指定某些配置,如字体等;
需要注意,htconfig
必须在 ht.js
和 ht-ui.js
之前声明;uiTheme
中可用的配置属性列举如下:
baseColor
用于 RadioButton
、CheckBox
、ToggleButton
,普通按钮的文字颜色和边框,文本框选中文本的背景色等font
字体,可统一修改所有组件中文字的字体textColor
文字颜色,可统一修改所有组件中文字的颜色borderColor
边框颜色,可统一修改有边框组件(TextField
、TextArea
、Panel
、Dialog
、ColorPane
、 DateTimePane
等)的边框颜色headerBackground
头背景,可统一修改 TableHeader
、PropertyPane
、Dialog
、Panel
的头部背景颜色iconColor
图标颜色,可统一修改 RadioButton
、CheckBox
未选中状态的边框颜色,ComboBox
的下拉图标的颜色,Panel
和 Dialog
的 tool
按钮图标的颜色,TreeView
和 TreeTableView
的展开合并图标的颜色lineColor
分割线颜色,可统一修改列表类组件(列表、树、表格等)的行列分割线hoverBackground
hover
状态的背景色,可统一修改 RadioButton
、CheckBox
未选中状态的 hover
背景色,ComboBox
下拉图标的 hover
状态的背景色,列表类组件(列表、树、表格等)的 hover
背景色、普通按钮 hover
状态的背景色activeBackground
active
状态的背景色,可统一修改 RadioButton
、CheckBox
未选中状态的 active
背景色,ComboBox
下拉图标的 active
状态的背景色,普通按钮 active
状态的背景色inputBackground
输入框组件的背景色popupBackground
弹出类组件,如:Dialog
、ContextMenu
、下拉列表等组件的背景popupBoxShadow
弹出类组件,如:Dialog
、ContextMenu
、下拉列表等组件的阴影okFirst
颜色选择器和日期选择器的弹出面板中的确定按钮是否显示在左侧,默认为 false
(即显示在右侧)rowSelectBackground
列表类组件(ListView
、TreeView
、TableView
、TreeTableView
、PropertyView
)选中的行背景色UI
库对界面外观提供了一套类似 CSS
的配置方式(Style
机制),允许开发者在页面内部或外部文件配置界面风格,从而使界面风格和业务代码分离,便于维护和复用。
内部页面方式:
<!-- 在页面中创建 script 标签,ref 值为 ht-style,内容遵循下面的格式 -->
<!-- type 可以为任意值,但是不要指定为 javascript,因为这会导致 script 标签内的内容被当作 JavaScript 解析 -->
<script rel='ht-style' type='any'>
({
'ht.ui.Button': {
icon: 'node_image' // 所有按钮的图标改为 'node_image'
}
})
</script>
外部文件方式:
<!-- 在页面中创建 link 标签,rel 值为 ht-style,href 值为样式文件路径,mystyle.style 文件格式遵循上面方式中 script 标签的内容格式 -->
<link rel='ht-style' href='mystyle.style'>
本质上来说,样式文件是一段 JavaScript
代码,因此在这里面声明变量也是允许的:
<script rel='ht-style' type='any'>
var nodeIcon = 'node_image'; // Button 和 TextField 的 icon 样式都指向这个变量,方便统一修改
@import(./test.style) // 引入 test.style 文件,注意 @import 必须独占一行
({
'ht.ui.Button': {
icon: nodeIcon,
border: new MyLineBorder('red') // test.style 引入了 MyLineBorder
},
'ht.ui.TextField': {
icon: nodeIcon
}
})
</script>
注意上面代码中的 通过 @import
引入了其它文件,./test.style
的文件内容:
// 自定义一个 Border
var MyLineBorder = function(color) {
MyLineBorder.superClass.constructor.call(this, 2, color);
}
ht.Default.def(MyLineBorder, ht.ui.border.LineBorder, {});
script
和 link
这两种方式可以混用,也可以在一个页面中创建多个 script
和 link
;但是需要注意:无论使用哪种方式,script
或 link
标签一定要放置在引入 ht-ui.js
之前。
每个组件可用的样式属性请查阅相应的 API
文档。
基础选择器
*
通用选择器,匹配任何组件;优先级:1
element
类型选择器,如 ht.ui.Button: {background: 'red'}
匹配所有按钮;优先级:1
&style
样式选择器,如 &styleName: {background: 'red'}
匹配 view.setStyle('styleName')
这种设置了 style
属性的组件;优先级:10
element&style
类型样式选择器,如 ht.ui.Button&styleName: {background: 'red'}
匹配所有 style
属性值为 styleName
的 Button
element*
子组件选择器,如 ht.ui.ButtonBase: {background: 'red'}
匹配 ButtonBase
类或子类:nth-child()
子组件位置选择器,如 ht.ui.ButtonBase:nth-child(1): {background: 'red'}
匹配容器中第一个 ButtonBase
类或子类;优先级:10
,括号内的位置支持:1
开始的last
:匹配最后一个子组件odd
: 匹配下标为奇数的子组件even
: 匹配下标为偶数的子组件组合选择器(basic
代表任意基础选择器, any
指任意基础选择器或组合选择器)
basic basic
后代选择器(可多层嵌套),如 ht.ui.BorderLayout &styleName: {background: 'red'}
匹配 BorderLayout
容器中所有 style
属性值为 styleName
的子孙组件basic>basic
直接后代选择器(可多层嵌套,注意>
左右不要有空格),如 ht.ui.BorderLayout>&styleName: {background: 'red'}
匹配 BorderLayout
容器中所有 style
属性值为 styleName
的子组件(TableLayout
比较特殊,直接子组件是指 TableRow
中的子组件,而不是指 TableRow
)any, any
多组件选择器(可多个组件),如 ht.ui.Button&styleName, ht.ui.TextField: {background: 'red'}
匹配所有 TextField
和 style
属性值为 styleName
的 Button
现在,后代选择器有更简单和明确的书写方式:
'&header': {
font: '12px arial'
},
'&header &title': {
background: 'red'
},
'&header &button': {
icon: 'node_image'
}
可以简化成下面的写法:
'&header': {
font: '12px arial',
'&title': {
background: 'red'
},
'&header': {
icon: 'node_image'
}
}
可以看到,通过嵌套的方式,不但代码量更少,层次结构也更加明确
上面的列表中,只有通用选择器、类型选择器、样式选择器说明了优先级,其它选择器的优先级如何计算?答案是:相加。下面是几个例子:
ht.ui.BorderLayout &styleName: {background: 'red'}
优先级为:(ht.ui.BorderLayout)1 + (&styleName)10 = 11
ht.ui.BorderLayout>&styleName: {background: 'red'}
优先级为:(ht.ui.BorderLayout)1 + (&styleName)10 = 11
ht.ui.BorderLayout>&styleName:nth-child(odd): {background: 'red'}
优先级为:(ht.ui.BorderLayout)1 + (&styleName)10 + (:nth-child(odd))10 = 21
ht.ui.BorderLayout ht.ui.Button: {background: 'red'}
优先级为:(ht.ui.BorderLayout)1 + (ht.ui.Button)1 = 2
ht.ui.Button&styleName, ht.ui.TextField: {background: 'red'}
当组件匹配 ht.ui.Button&styleName
规则时,优先级为 1 + 10 = 11
;当组件匹配 ht.ui.TextField
规则时,优先级为 1
样式值类型支持 JavaScript
中的所有标准数据类型,如 int
、number
、boolean
等,如果值需要经过某些特殊运算,则需要通过 function
指定:
// 样式配置:
({
'ht.ui.Button': {
textColor: 'black',
text: function() {
return 'test' + '2'; // 简单运算
},
// 创建并返回自定义的 Drawable
backgroundDrawable: new ht.ui.drawable.ColorDrawable('yellow'),
border: [ht.ui.border.LineBorder, 1, 'red] // 创建并返回自定义的 Border
}
})
当多个选择器选中了同一个组件,并且样式冲突时怎么处理?这就涉及到样式优先级的问题;看下面的例子:
// 样式配置:
({
'ht.ui.Button': { // 优先级:1
background: 'yellow',
textColor: 'black'
},
'ht.ui.HBoxLayout ht.ui.Button': { // 优先级: 2,ht.ui.HBoxLayout 优先级 1 + ht.ui.Button 优先级 1 = 2
background: 'green'
},
'ht.ui.Button&button-blue': { // 优先级 11,ht.ui.Button 优先级 1 + &button-blue 优先级 10 = 11
background: 'blue'
}
})
// JavaScript 代码,创建布局
var button1 = new ht.ui.Button(),
button2 = new ht.ui.Button(),
button3 = new ht.ui.Button(),
hBox = new ht.ui.HBoxLayout();
button3.setStyle('button-blue');
hBox.addView(button2, {marginLeft: 20, height: 'match_parent'});
hBox.addView(button3, {marginLeft: 20, height: 'match_parent'});
上面例子中,三条样式规则都配置了 Button
组件的 background
属性,其中 button1
只能匹配第一条规则,所以背景色为 yellow
;button2
能匹配第一条和第二条规则,由于第二条规则优先级比较高,所以 button2
的背景色为 green
;button3
能匹配三条样式规则,但是第三条规则优先级最高,所以 button3
的背景色为 blue
有时候我们需要为页面中所有的文本框设置 focus
状态的边框,参考下面的例子:
// 样式配置:
({
'ht.ui.TextField*': {
border: [ht.ui.border.FocusLineBorder, 1, '#d9d9d9', '#5cb85c'],
redrawOnFocus: true
}
})
自 4.0
开始 UI
库提供了一套全新的样式,这套样式中很多默认值可以通过 htconfig
对象重新配置,如文字颜色、字体等,参考下面的例子(点击顶部色块可切换整体风格):
如果直接从本地磁盘中打开
html
可能会遇到浏览器跨域问题,如果碰到此类问题,可以访问在线版本:在线访问; 或尝试用Firefox
浏览器打开
在这里例子中,通过 htconfig
对象配置了 baseColor
属性:
<script>
htconfig = {
uiTheme: { // 配置 UI 样式属性
baseColor: '#xxxxxx'
},
extendedUIStyles: { // 扩展样式
'ht.ui.Button': {
textColor: 'black'
}
}
}
</script>
uiTheme
中可以使用 extendUIStyles
配置样式规则(就像 <script rel="ht-style"></script>
那样),和 script
标签方式本质是一样的,只是通过 extendUIStyles
的方式定制的风格可以放到同一个文件中,方便传递共享
如果使用上面提到的静态样式,切换页面整体风格时不可避免的要刷新页面,用户在页面中的操作可能会丢失(比如文本框输入的内容),使用动态样式可以在不刷新页面的前提下切换风格,动态样式需要用到下面的 API
:
ht.Default.loadUIStyle(name, config, callback)
加载动态样式ht.Default.removeLoadedUIStyle(name)
删除某个动态加载的样式ht.Default.clearLoadedUIStyles()
清除所有动态加载的样式ht.Default.invalidateUIStyles()
刷新页面中的组件适配新样式下面的代码展示了如何使用这几个 API
:
// 假设之前加载过一个名为 green 的动态样式,现在要改为 dark 样式:
// 先删除 green 样式;如果要清除所有动态样式,也可以调用 ht.Default.clearLoadedUIStyles();
ht.Default.removeLoadedUIStyle('green');
// 加载 dark 样式
ht.Default.loadUIStyle('dark', 'styles/dark.style', function() {
// 样式是异步加载的,需要在加载完成的回调函数里刷新页面中的组件
ht.Default.invalidateUIStyles();
});
下面是一个例子:
如果直接从本地磁盘中打开
html
可能会遇到浏览器跨域问题,如果碰到此类问题,请访问在线版本:在线访问; 或尝试用Firefox
浏览器打开
UI
库内置了几个候选样式,如 button-obvious
,如果需要着重提示某个按钮,只需要设置:
button.setStyle('button-obvious');
内置的候选样式列举如下:
button-warn
警告按钮button-obvious
重要按钮button-minor
次要按钮buttongroup
按钮组,此样式需要设置到 HBoxLayout
或 VBoxLayout
容器上,容器内部只能放 ToggleButton
progressbar-thin
细长条进度条tablayout-line-outside
Tab
头外部显示分割线tablayout-buttongroup
Tab
头显示为按钮组textfield-search
搜索框样式通过 ht.Default.uiStyles
可以查看这些候选样式的定义