TornadoFx实现侧边栏菜单效果
原文地址:TornadoFx实现侧边栏菜单效果 - Stars-One的杂货小窝
之前年前研究的东西,给蓝奏批量下载器重构了页面,实现了侧边栏菜单的效果,稍微总结下把
效果
实现
首先,要说明的是,总体布局为一个Hbox,侧边栏在左边,是一个vbox,右侧则是各菜单对应的布局,使用StackPane布局
原理是,点击左侧vbox中的菜单项,更改右侧的布局(显示对应菜单项的布局)
侧边栏切换效果
//定义个侧边菜单的数据类
data class LeftMenuItem(val title: String)
class TestView : View("Hello TornadoFX") {
val model by inject<MainViewModel>()
override val root = vbox() {
prefWidth = 400.0
prefHeight = 200.0
hbox {
vbox {
val list = listOf(LeftMenuItem("首页"), LeftMenuItem("下载列表"), LeftMenuItem("资源搜索"))
list.forEachIndexed { index, leftMenuItem ->
button(leftMenuItem.title) {
action {
//点击按钮更改选中的下标数值
model.selectIndex.set(index)
}
}
}
}
stackpane {
//显示当前选中拿到下标数值
label(model.selectIndex.asString()){
prefWidth(120.0)
}
}
}
}
}
class MainViewModel : ViewModel() {
//当前选中的菜单项下标
val selectIndex = SimpleIntegerProperty(0)
}
效果如下图所示:
当然,这里右侧布局只是个简单的text,我们在修改下,让右侧布局根据当前所选的下标值更改显示即可
val list = listOf(LeftMenuItem("首页"), LeftMenuItem("下载列表"), LeftMenuItem("资源搜索"))
hbox {
vbox {
list.forEachIndexed { index, leftMenuItem ->
button(leftMenuItem.title) {
action {
model.selectIndex.set(index)
}
}
}
}
stackpane {
list.forEachIndexed { index, leftMenuItem ->
//这里以label演示,可以更改为布局或者是View类型
label(model.selectIndex.asString()) {
prefWidth(120.0)
visibleWhen {
model.selectIndex.eq(index)
}
}
}
}
}
效果如下所示:
关于使用View
这里的View,指的是TornadoFx中的View
我们不同页面都是写在View中,所以按照上面的代码,还需要调整下
首先,LeftMenuItem类中新增个对象,用来存储对应的View
data class LeftMenuItem(val title: String,val view:View)
右侧布局要这样写:
//右侧布局
stackpane {
//text(homeModel.selectIndex.asString())
list.forEachIndexed { index, leftMenuItem ->
val leftView = leftMenuItem.view
leftView.root.visibleWhen {
homeModel.selectIndex.eq(index)
}
this += leftMenuItem.view
}
}
上面省略了构造LeftMenuItem的初始化list的相关代码,相信各位知道该如何新建LeftMenuItem对象(View对象可以直接调用无参构造方法)
侧边栏美化
接下来就是侧边栏的美化工作,这样直接贴出样式的代码吧,关于css的使用,可以看下上一篇TornadoFx中的css美化
package site.starsone.xtool.app
import javafx.scene.layout.BorderStrokeStyle
import javafx.scene.paint.CycleMethod
import javafx.scene.paint.LinearGradient
import javafx.scene.paint.Stop
import javafx.scene.text.FontWeight
import tornadofx.*
class Styles : Stylesheet() {
companion object {
val leftMenu by cssclass()
val leftMenuSelect by cssclass()
}
init {
leftMenu {
prefWidth = 200.px
startMargin = 10.px
fontSize = 14.px
padding = box(15.px)
backgroundColor += c("white")
and(hover) {
textFill = c("#1890ff")
}
}
leftMenuSelect{
prefWidth = 200.px
startMargin = 10.px
fontSize = 14.px
padding = box(15.px)
backgroundColor +=c("#e6f7ff")
textFill = c("#1890ff")
borderColor += box(null,c("#1890ff"),null,null)
borderWidth += box(0.px,2.px,0.px,0.px)
borderStyle += BorderStrokeStyle.SOLID
}
}
}
View中使用样式:
class TestView : View("Hello TornadoFX") {
val model by inject<MainViewModel>()
override val root = vbox() {
prefWidth = 400.0
prefHeight = 200.0
//单独运行View的话,记得导入样式的操作
importStylesheet(Styles::class)
val list = listOf(LeftMenuItem("首页"), LeftMenuItem("下载列表"), LeftMenuItem("资源搜索"))
hbox {
vbox {
list.forEachIndexed { index, leftMenuItem ->
button(leftMenuItem.title) {
//给button添加样式
addClass(Styles.leftMenu)
//根据当前是否已选(下标是否一致)来切换button样式
toggleClass(Styles.leftMenuSelect, model.selectIndex.eq(index))
action {
model.selectIndex.set(index)
}
}
}
}
stackpane {
list.forEachIndexed { index, leftMenuItem ->
//这里以label演示,可以更改为布局或者是View类型
label("这是"+leftMenuItem.title) {
prefWidth(120.0)
visibleWhen {
model.selectIndex.eq(index)
}
}
}
}
}
}
}
效果如下图所示: