支持 iOS 15。使用此代码,我会得到一个带有图像和文本的垂直单元格,如果有通知,我会显示红色圆形文本。事情发生在我的手机上,我的手机延伸得太远,通知距离太远。我尝试的任何解决方案如果解决了 iPad 问题,也许会将红色标签居中,而不是将其放在右上角。
iPhone 肖像
iPad 横向
导入 SwiftUI
struct FavouritesWebAppsMainView: View {
@EnvironmentObject var classFromEntryPoint: ClassFromEntryPoint
//code for presenting sheet.
@State private var selectedItem: WebAppModel?
//related to customized wkwebViews
@State private var errorMessage: String = "none"
@State private var showAlert = false
let columns = [
GridItem(.flexible()),
GridItem(.flexible()),
GridItem(.flexible()),
]
var body: some View {
VStack {
headerView
mainBodyWithGrid
.sheet(item: $selectedItem) { webApp in
let test = webApp.appUrl
if let url = URL(string: test) {
CustomWebView(url: url, messageErrorFromWebView: $errorMessage)
HStack {
Spacer()
Button(action: {
selectedItem = nil //Used to dismiss the sheet
}) {
Label("", systemImage: "xmark")
}
}
.padding()
.background(Color.gray.opacity(0.2))
} else {
//never called
let _ = self.errorMessage = "Not valid URL"
let _ = self.showAlert = true
let _ = Logger.error("failed url: \(webApp.appUrl)")
}
}
} //most external view
.backgroundImage()
.onChange(of: errorMessage, perform: { newValue in
self.showAlert = true
})
.alert("Errore", isPresented: $showAlert) {
Button("ok", role: .cancel) {}
} message: {
Text(self.errorMessage)
}
}
//MARK: single views
private var headerView: some View {
VStack {
HStack {
Text("Welvome")
.font(.largeTitle)
.foregroundColor(.blue)
.lineLimit(1)
.minimumScaleFactor(0.5)
.padding()
Spacer()
}
Text("Le tue app")
.padding(.bottom)
}
}
private var mainBodyWithGrid: some View {
ZStack(alignment: .bottom) {
ScrollView {
if classFromEntryPoint.preferredAppList.isEmpty {
Text("Add App to the store")
} else {
LazyVGrid(columns: columns, spacing: 30) {
ForEach(classFromEntryPoint.preferredAppList) { item in
VerticalCellView(item: item)
.onTapGesture {
self.selectedItem = item
}
}
}
.padding(.horizontal)
}
}
logoutButton
}
}
private var logoutButton: some View {
HStack {
Button("Logout") {
Logger.debug("logout")
classFromEntryPoint.performLogout()
}
.padding()
.background(.red)
.foregroundStyle(.white)
.clipShape(Capsule())
.padding()
Spacer()
}
}
}
//MARK: - cell
struct VerticalCellView: View {
var item: WebAppModel
var body: some View {
ZStack(alignment: .topTrailing) {
GeometryReader { geometry in
VStack {
ImageDownloadedFromWeb(url: item.logoUrl ?? "N/D")
.frame(width: min(geometry.size.width, 100), height: min(geometry.size.width, 100))
Text(item.name)
.font(.headline)
.frame(maxWidth: .infinity)
// Text(item.description)
// .font(.subheadline)
// .lineLimit(2)
// .truncationMode(.tail)
}
.frame(width: geometry.size.width)
}
let notificationCount = (Int.random(in: 0...20))
Text(notificationCount > 10 ? "99+" : "\(notificationCount)")
.font(.system(size: 12))
.frame(width: 25, height: 25)
.background(.red)
.foregroundColor(.white)
.clipShape(Circle())
}
.frame(height: 150)
}
}
可能的解决方案,但不清楚为什么它有效
struct VerticalCellView: View {
var item: WebAppModel
var body: some View {
VStack {
ImageDownloadedFromWeb(url: item.logoUrl ?? "N/D")
.frame(width: 100, height: 100)
.overlay(
notificationBadge,
alignment: .topTrailing
)
Text(item.name)
.font(.headline)
// Text(item.description)
// .font(.subheadline)
// .lineLimit(2)
// .truncationMode(.tail)
}
.frame(height: 150)
}
private var notificationBadge: some View {
let notificationCount = (Int.random(in: 0...20))
return Text(notificationCount > 10 ? "99+" : "\(notificationCount)")
.font(.system(size: 12))
.frame(width: 25, height: 25)
.background(.red)
.foregroundColor(.white)
.clipShape(Circle())
.offset(x: 10, y: -10)
}
}
为了跟进评论,我建议将徽章显示为图像上的叠加层。这样,徽章就永远不会与图像分离。
你说你试过了,但没有成功,所以我自己也尝试了一下。我发现自己在想,你为什么要使用
GeometryReader
?它给你的大小是网格单元的大小,但这并不是特别有用。
这是示例的精简版本,用于说明如何使用叠加层来实现此目的。本着最小可重现示例的精神,我遗漏了所有不需要或相关的内容。
struct WebAppModel: Identifiable {
let id = UUID()
let logo: String
let name: String
}
struct FavouritesWebAppsMainView: View {
let items: [WebAppModel] = [
WebAppModel(logo: "lizard", name: "test1"),
WebAppModel(logo: "ant", name: "test2"),
WebAppModel(logo: "tortoise", name: "test3"),
WebAppModel(logo: "fossil.shell", name: "test4"),
]
let columns = [
GridItem(.flexible()),
GridItem(.flexible()),
GridItem(.flexible()),
]
var body: some View {
mainBodyWithGrid
}
private var mainBodyWithGrid: some View {
ScrollView {
LazyVGrid(columns: columns, spacing: 30) {
ForEach(items) { item in
VerticalCellView(item: item)
}
}
.padding(.horizontal)
}
}
}
struct VerticalCellView: View {
var item: WebAppModel
private var randomNotificationBadge: some View {
let notificationCount = (Int.random(in: 0...20))
return Text(notificationCount > 10 ? "99+" : "\(notificationCount)")
.font(.system(size: 12))
.frame(width: 25, height: 25)
.background(.red)
.foregroundColor(.white)
.clipShape(Circle())
}
var body: some View {
VStack {
Image(systemName: item.logo)
.resizable()
.scaledToFit()
.background(.yellow.opacity(0.2))
.overlay(alignment: .topTrailing) {
randomNotificationBadge
}
Text(item.name)
.font(.headline)
}
.frame(height: 150)
}
}
屏幕截图来自 iPad 10 代。