目的是要做一个这样的音乐列表组件:
包含:
需要在标题栏上显示排序图标,实现点击排序功能,因此额外需要定义一个枚举类型SortKey
指示排序依据。这里的排序图标也手动绘制,不使用网络上的图标:
@rust-attr(derive(serde::Serialize, serde::Deserialize))
export enum SortKey {
BySongName,
BySinger,
ByDuration,
}
component SortIcon inherits Window {
in-out property <bool> ascending:true;
in-out property <bool> display:true;
height: 15px;
width: 15px;
background: transparent;
if !ascending && display: Path {
MoveTo {
x: 5;
y: 1;
}
LineTo {
x: 5;
y: 9;
}
LineTo {
x: 7;
y: 7;
}
stroke: gray;
stroke-width: 1px;
}
if ascending && display:
Path {
MoveTo {
x: 5;
y: 9;
}
LineTo {
x: 5;
y: 1;
}
LineTo {
x: 3;
y: 3;
}
stroke: gray;
stroke-width: 1px;
}
}
component TitleBarItem inherits Window {
in property <string> name:"name";
in-out property <bool> display-sort-icon <=> arrow.display;
in-out property <bool> ascending-sort <=> arrow.ascending;
Rectangle {
width: 100%;
height: 100%;
text := Text {
text: name;
color: dimgray;
x: parent.width * 0.4;
y: parent.height / 2 - self.height / 2;
}
arrow := SortIcon {
ascending: true;
width: 12px;
height: 12px;
x: text.x + text.width + 5px;
y: parent.height / 2 - self.height / 2;
}
}
}
export component TitleBar inherits Window {
height: 30px;
in-out property <SortKey> key;
in-out property <bool> ascending;
callback sort-items(SortKey, bool);
VerticalLayout {
HorizontalLayout {
alignment: space-between;
area1 := TouchArea {
width: 33%;
clicked => {
sort-items(SortKey.BySongName, ascending);
}
TitleBarItem {
width: 100%;
height: 100%;
name: @tr("Title");
background: area1.has-hover ? Palette.control-background : transparent;
display-sort-icon: key == SortKey.BySongName;
ascending-sort: ascending;
}
}
area2 := TouchArea {
width: 33%;
clicked => {
sort-items(SortKey.BySinger, ascending);
}
TitleBarItem {
name: @tr("Artist");
height: 100%;
width: 100%;
background: area2.has-hover ? Palette.control-background : transparent;
display-sort-icon: key == SortKey.BySinger;
ascending-sort: ascending;
}
}
area3 := TouchArea {
width: 33%;
clicked => {
sort-items(SortKey.ByDuration, ascending);
}
TitleBarItem {
name: @tr("Duration");
height: 100%;
width: 100%;
background: area3.has-hover ? Palette.control-background : transparent;
display-sort-icon: key == SortKey.ByDuration;
ascending-sort: ascending;
}
}
}
Path {
width: 100%;
height: 5px;
MoveTo {
x: 0;
y: 0;
}
LineTo {
x: 100%;
y: 0;
}
stroke: Palette.foreground;
stroke-width: 0.3px;
}
}
}
每个列表项关联一首歌曲,显示其相关信息:
因此额外定义了一个SongInfo
结构体。此外,双击该列表项会触发音乐播放,所以对外暴露一个double-clicked
回调函数:
export struct SongInfo {
id:int,
song_name:string,
singer:string,
duration:string,
song_path:string,
}
export component SongItem inherits Window {
height: 30px;
in property <SongInfo> info:{ id:0, song_name:"xxx", singer:"xxx", duration:"xxx", song_path:"xxx" };
callback double_clicked();
background: area.has-hover ? Palette.control-background : transparent;
VerticalLayout {
area := TouchArea {
double-clicked => {
double_clicked();
}
HorizontalLayout {
alignment: space-between;
Rectangle {
width: 33%;
Text {
width: 100%;
x: parent.width * 0.4;
text: info.song-name;
overflow: elide;
}
}
Rectangle {
width: 33%;
Text {
width: 100%;
x: parent.width * 0.4;
text: info.singer;
overflow: elide;
}
}
Rectangle {
width: 33%;
Text {
x: parent.width * 0.4;
text: info.duration;
}
}
}
}
Path {
width: 100%;
height: 1px;
MoveTo {
x: 0;
y: 0;
}
LineTo {
x: 100%;
y: 0;
}
stroke: Palette.foreground;
stroke-width: 0.15px;
}
}
}
使用Slint UI的内置ListView
组件来渲染多个音乐项,然后竖直堆叠标题栏和这个ListView
:
export component SongListView inherits Window {
in-out property <bool> ascending;
in-out property <SortKey> sort-key;
in-out property <SortKey> last-sort-key;
in-out property <[SongInfo]> song-list;
callback sort-songs(SortKey, bool);
callback play-song(SongInfo, TriggerSource);
VerticalLayout {
width: 100%;
height: 100%;
TitleBar {
ascending: root.ascending;
key: root.sort-key;
sort-items(key, ascending) => {
if (root.last-sort-key == key) {
root.sort-songs(key, !ascending);
} else {
root.sort-songs(key, true)
}
}
}
ListView {
for item in root.song-list: SongItem {
info: item;
double_clicked => {
root.play-song(item, TriggerSource.ClickItem);
}
}
}
}
}
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。