Swiftui在切换/true或false上显示不同的图像/文本
我正在尝试创建一个按钮,该按钮根据任务的当前状态显示不同的图像/文本。
我发现以下内容不起作用:
Button {
taskViewModel.completeTask(id: task.id)
} label: {
if task.taskCompleted {
Image(systemName: "square")
.foregroundStyle(.black)
.padding(10)
.background(Color(.white), in: RoundedRectangle(cornerRadius: 10))
} else {
Image(systemName: "checkmark.square")
.foregroundStyle(.black)
.padding(10)
.background(Color(.white), in: RoundedRectangle(cornerRadius: 10))
}
}
但这确实有效:
if task.taskCompleted {
Button {
taskViewModel.completeTask(id: task.id)
} label: {
Image(systemName: "checkmark.square")
.foregroundStyle(.black)
.padding(10)
.background(Color(.white), in: RoundedRectangle(cornerRadius: 10))
}
} else {
Button {
taskViewModel.completeTask(id: task.id)
} label: {
Image(systemName: "square")
.foregroundStyle(.black)
.padding(10)
.background(Color(.white), in: RoundedRectangle(cornerRadius: 10))
}
}
无效的代码更加干净!当然,有一种比我在这里所做的更好的方法?
不起作用的完整代码是:
func TasksView(completed: Bool)->some View {
LazyVStack(spacing: 20) {
if let tasks = taskViewModel.filteredTasks{
if tasks.isEmpty{
Text("No Tasks Today")
.offset(y: 100)
}else{
ForEach(tasks){ task in
if completed && task.taskCompleted || !task.taskCompleted {
HStack(alignment: .top, spacing: 20) {
VStack(spacing: 12) {
Circle()
.fill(taskViewModel.isCurrentHour(date: task.taskDate) ? .black : .clear)
.frame(width: 13, height: 13)
.background(
Circle()
.stroke(.black, lineWidth: 2)
.padding(-4)
)
.scaleEffect(taskViewModel.isCurrentHour(date: task.taskDate) ? 1.2 : 0.8)
Rectangle()
.fill(.black)
.frame(width: 3)
}
VStack {
HStack(alignment: .top, spacing: 10) {
VStack(alignment: .leading, spacing: 12) {
Text(task.taskTitle)
.font(.title2.bold())
Text(task.taskDescription)
.font(.callout)
.foregroundStyle(.secondary)
}
.headerLeading()
Text(task.taskDate.formatted(date: .omitted, time: .shortened))
}
HStack(spacing: 8) {
if taskViewModel.isCurrentHour(date: task.taskDate) {
HStack(spacing: 5) {
ForEach(1...3, id: \.self) { user in
Image(systemName: "person")
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 25, height: 25)
}
}
.headerLeading()
}
Button{
taskViewModel.completeTask(id: task.id)
} label: {
Image(systemName: task.taskCompleted ? "checkmark.square" : "square")
.foregroundStyle(.black)
.padding(10)
.background(Color(.white), in: RoundedRectangle(cornerRadius: 10))
}
Button{
taskViewModel.deleteTask(id: task.id)
} label: {
Image(systemName: "bin.xmark")
.foregroundStyle(.black)
.padding(10)
.background(Color(.white), in: RoundedRectangle(cornerRadius: 10))
}
}
.padding(.top)
.headerTrailing()
}
.padding(taskViewModel.isCurrentHour(date: task.taskDate) ? 15 : 0)
.padding(.bottom, taskViewModel.isCurrentHour(date: task.taskDate) ? 0 : 10)
.headerLeading()
.background(
Color(.black)
.cornerRadius(20)
.opacity(taskViewModel.isCurrentHour(date: task.taskDate) ? 1 : 0)
)
.foregroundColor(taskViewModel.isCurrentHour(date: task.taskDate) ? .white : .black)
}.headerLeading()
}
}
}
}else{
ProgressView()
.offset(y: 100)
}
}
.padding()
.padding(.top)
.onChange(of: taskViewModel.currentDay) { newDate in
taskViewModel.filterTodaysTasks()
}
}
当我尝试运行此问题时,以下错误是由Xcode抛出的:
编译器无法在合理的时间内键入该表达式;尝试将表达式分解为不同的子表达
I'm trying to create a button that displays a different images/text depending on the current state of a task.
I've found the following doesn't work:
Button {
taskViewModel.completeTask(id: task.id)
} label: {
if task.taskCompleted {
Image(systemName: "square")
.foregroundStyle(.black)
.padding(10)
.background(Color(.white), in: RoundedRectangle(cornerRadius: 10))
} else {
Image(systemName: "checkmark.square")
.foregroundStyle(.black)
.padding(10)
.background(Color(.white), in: RoundedRectangle(cornerRadius: 10))
}
}
But this does work:
if task.taskCompleted {
Button {
taskViewModel.completeTask(id: task.id)
} label: {
Image(systemName: "checkmark.square")
.foregroundStyle(.black)
.padding(10)
.background(Color(.white), in: RoundedRectangle(cornerRadius: 10))
}
} else {
Button {
taskViewModel.completeTask(id: task.id)
} label: {
Image(systemName: "square")
.foregroundStyle(.black)
.padding(10)
.background(Color(.white), in: RoundedRectangle(cornerRadius: 10))
}
}
The code that doesn't work is far cleaner!. Surely there is a better way to do this than what I've done here?
The full code that isn't working is:
func TasksView(completed: Bool)->some View {
LazyVStack(spacing: 20) {
if let tasks = taskViewModel.filteredTasks{
if tasks.isEmpty{
Text("No Tasks Today")
.offset(y: 100)
}else{
ForEach(tasks){ task in
if completed && task.taskCompleted || !task.taskCompleted {
HStack(alignment: .top, spacing: 20) {
VStack(spacing: 12) {
Circle()
.fill(taskViewModel.isCurrentHour(date: task.taskDate) ? .black : .clear)
.frame(width: 13, height: 13)
.background(
Circle()
.stroke(.black, lineWidth: 2)
.padding(-4)
)
.scaleEffect(taskViewModel.isCurrentHour(date: task.taskDate) ? 1.2 : 0.8)
Rectangle()
.fill(.black)
.frame(width: 3)
}
VStack {
HStack(alignment: .top, spacing: 10) {
VStack(alignment: .leading, spacing: 12) {
Text(task.taskTitle)
.font(.title2.bold())
Text(task.taskDescription)
.font(.callout)
.foregroundStyle(.secondary)
}
.headerLeading()
Text(task.taskDate.formatted(date: .omitted, time: .shortened))
}
HStack(spacing: 8) {
if taskViewModel.isCurrentHour(date: task.taskDate) {
HStack(spacing: 5) {
ForEach(1...3, id: \.self) { user in
Image(systemName: "person")
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 25, height: 25)
}
}
.headerLeading()
}
Button{
taskViewModel.completeTask(id: task.id)
} label: {
Image(systemName: task.taskCompleted ? "checkmark.square" : "square")
.foregroundStyle(.black)
.padding(10)
.background(Color(.white), in: RoundedRectangle(cornerRadius: 10))
}
Button{
taskViewModel.deleteTask(id: task.id)
} label: {
Image(systemName: "bin.xmark")
.foregroundStyle(.black)
.padding(10)
.background(Color(.white), in: RoundedRectangle(cornerRadius: 10))
}
}
.padding(.top)
.headerTrailing()
}
.padding(taskViewModel.isCurrentHour(date: task.taskDate) ? 15 : 0)
.padding(.bottom, taskViewModel.isCurrentHour(date: task.taskDate) ? 0 : 10)
.headerLeading()
.background(
Color(.black)
.cornerRadius(20)
.opacity(taskViewModel.isCurrentHour(date: task.taskDate) ? 1 : 0)
)
.foregroundColor(taskViewModel.isCurrentHour(date: task.taskDate) ? .white : .black)
}.headerLeading()
}
}
}
}else{
ProgressView()
.offset(y: 100)
}
}
.padding()
.padding(.top)
.onChange(of: taskViewModel.currentDay) { newDate in
taskViewModel.filterTodaysTasks()
}
}
When I try to run this the following error is thrown by Xcode:
The compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
根据完成的任务状态,有一种更好,更干净的方法。
There is a better and a cleaner way to do it, based on the state of the task completed.
代替更多细节,通常在对象的属性结果下调整视图的最佳方法是进行最小的调整。在这种情况下,您可以将更改限制为图像的
systemName
:更有可能发生的是
task
不会向SwiftUI渲染系统的更改表示,,因此,在完成后
运行后,没有迹象表明需要对视图进行重新评估。In lieu of more details, generally the best way to adjust your view in the result of an object's property is to make the smallest adjustment necessary. In this case, you can limit the change to the
systemName
of the image:What is more likely happening is that
task
isn't signalling its change to the SwiftUI rendering system, so aftercompleteTask
has run there's no indication that the view needs to be re-evaluated.对于SwiftUi,第一个示例中的按钮的身份没有改变。您可以通过添加显式
.id(…)
来解决此问题。例如:一旦任务的
完成
更改,SwiftUI正在重新评估UI,它将检测到该按钮具有不同的ID,然后将使用您的新映像重新呈现。To SwiftUI, the identity of the button hasn't changed in the first example. You could fix this by adding an explicit
.id(…)
. For example:As soon as the task's
completed
changes, and SwiftUI is re-evaluating the UI, it will detect that the button has a different ID and will then re-render it with your new image.