问题描述
我正在尝试使用SwiftUI和WidgetKit布局tableView,并希望获得与Apple的Notes小部件类似的结果。
我当前的实现成功地在.systemLarge
小部件中布置了视图,但没有在.systemMedium
小部件中布置视图。我想将视图固定在窗口小部件的顶部,以便在.systemMedium
中可见“ FAVOURITES”的标题。
struct PlacesWidgetEntryView : View {
var entry: Provider.Entry
let places = [
Place(name: "Place 1",imageName: "baseline_star_black_24pt"),Place(name: "Place 2",Place(name: "Place 3",Place(name: "Place 4",Place(name: "Place 5",]
var body: some View {
vstack {
//Header
HStack {
Text("FAVOURITES")
.bold()
.frame(height: 8)
Spacer()
}
.padding()
.background(Color.blue)
//TableView
Lazyvstack {
ForEach(places,id: \.self) { place in
PlaceRow(place: place)
}
}
Spacer()
}
}
}
struct PlaceRow: View {
let place: Place
var body: some View {
HStack {
Text(place.name)
.font(.body)
Spacer()
Image(place.imageName)
.resizable()
.frame(width: 28,height: 28,alignment: .center)
}
.padding(.horizontal)
.padding(.vertical,4)
}
}
执行结果:
Parse JSON from JQuery.ajax success data
上面是.systemLarge
,很好,符合我的期望。
上面是.systemMedium
,这不是我期望的。我希望看到“收藏夹”锚定在widgetView的顶部,并且有可能tableView溢出到底部。
解决方法
这是可能的布局解决方案。经过Xcode 12测试。
var body: some View {
VStack(spacing: 0) {
HStack {
Text("FAVOURITES")
.bold()
.frame(height: 8)
Spacer()
}
.padding()
.background(Color.blue)
Color.clear
.overlay(
LazyVStack {
ForEach(places,id: \.self) { place in
PlaceRow(place: place)
}
},alignment: .top)
}
.frame(maxWidth: .infinity,maxHeight: .infinity)
}
,
因此,通过在WidgetKit中玩耍,看起来如果小部件中的视图过多,它将开始将上方的视图推离屏幕。如果将更多位置添加到数组,则大型部件也会发生相同的情况。您可以做的是创建单独的视图:一个用于中型视图,一个用于大型窗口小部件,对于中型一个,只需使用1-3个位置对象来填充它即可。
您可以在PlacesEntryWidgetView中将switch语句与widgetFamily一起使用,以决定要在视图上显示的内容。我还将图像的高度从28降低到24。
struct PlacesWidgetEntryView : View {
var entry: Provider.Entry
@Environment(\.widgetFamily) var family
let places = [
Place(name: "Place 1",imageName: "blackStar"),Place(name: "Place 2",Place(name: "Place 3",Place(name: "Place 4",Place(name: "Place 5",Place(name: "Place 6",Place(name: "Place 7",Place(name: "Place 8",imageName: "blackStar")
]
@ViewBuilder
var body: some View {
switch family {
case .systemMedium:
// widget can only show so many views so I only took first 3 places
WidgetView(places: Array(places.prefix(3)))
case .systemLarge:
WidgetView(places: places)
// I only have it set to show system medium so you can ignore
// the last case
case .systemSmall:
Text("")
@unknown default:
Text("")
}
}
}
struct WidgetView: View {
let places: [Place]
var body: some View {
VStack {
//Header
HStack {
Text("FAVOURITES")
.bold()
.frame(height: 8)
Spacer()
}
.padding()
.background(Color.blue)
//TableView
LazyVStack {
ForEach(places,id: \.self) { place in
PlaceRow(place: place)
}
}
Spacer()
}
}
}
struct PlaceRow: View {
let place: Place
var body: some View {
HStack {
Text(place.name)
.font(.body)
Spacer()
Image(place.imageName)
.resizable()
.frame(width: 28,height: 24,alignment: .center)
}
.padding(.horizontal)
.padding(.vertical,4)
}
}
这是预览:
请记住,您可能希望在模拟器之间进行切换,以确保您的小部件在所有设备上看起来都很好。