SwiftUI Widget真机/模拟器显示空白,Canvas正常问题求助
Hey there! Let's figure out why your widget works perfectly in the SwiftUI Canvas but goes blank when deployed to a simulator or real device. From looking at your code and the update you shared, here are the key issues to fix:
1. Custom Font Loading Problems
You're using custom fonts like HoeflerText-Italic and Copperplate in your widget. The SwiftUI Canvas often falls back to system fonts if the custom ones aren't properly set up, but devices won't do that. If the fonts aren't added correctly to your project, the Text views that use them won't render—this can cause the entire widget layout to collapse into a blank state.
Fix Steps:
- Make sure your font files (e.g.,
.ttfor.otf) are added to your Xcode project, and check the box for your widget target in the "Add to targets" section when importing. - Open your project's
Info.plist, add the keyFonts provided by application, and list each font file name as a string entry (include the full file name likeHoeflerText-Italic.ttf). - Verify the fonts are included in your widget target's Build Phases > Copy Bundle Resources.
2. Layout Overflow & Missing Text Constraints
The VStack you removed contains text with large font sizes (44pt and 26pt) plus padding. Widgets have very limited screen space, especially for the .systemMedium size. If the content exceeds the available bounds, SwiftUI might hide the entire view instead of clipping it.
Fix Steps:
Add text scaling and line limits to prevent overflow:
- Use
.minimumScaleFactor(_:)to let text shrink if needed. - Use
.lineLimit(1)to keep text on a single line.
3. Dangerous Force Unwrapping
Your code uses force unwrapping (!) for getDayOfWeekInString(date:). If this method returns nil (e.g., due to a date parsing error on the device), the view will crash silently—resulting in a blank widget. Always use optional bindings or default values instead.
Corrected WidgetEntryView Code
Here's your updated view with all these fixes applied:
struct WidgetEntryView : View { var entry: Provider.Entry var body: some View { HStack() { VStack { Spacer() VStack(alignment: .leading) { // Replace force unwrap with default value Text(DateManager().getDayOfWeekInString(date: entry.date) ?? "") // Fallback to system font if custom one fails .font(Font(UIFont(name: "HoeflerText-Italic", size: 44) ?? .systemFont(ofSize: 44, weight: .italic))) .foregroundColor(.white) .multilineTextAlignment(.trailing) // Allow text to shrink to fit .minimumScaleFactor(0.5) .lineLimit(1) Text("\(DateManager().getDayAsString(date: entry.date)) \(DateManager().monthAsString(date: entry.date))") .font(Font(UIFont(name: "Copperplate", size: 26) ?? .systemFont(ofSize: 26))) .multilineTextAlignment(.trailing) .foregroundColor(.gray) .minimumScaleFactor(0.6) .lineLimit(1) } } .padding(.leading, 20) .padding(.bottom, 20) Spacer() VStack(alignment: .trailing, spacing: -20) { Text(DateManager().getHour(date: entry.date)) .font(Font(UIFont(name: "Copperplate-Bold", size: 86) ?? .systemFont(ofSize: 86, weight: .bold))) .foregroundColor(.white) .multilineTextAlignment(.trailing) .minimumScaleFactor(0.4) .lineLimit(1) Text(DateManager().getMinuteWithTwoDigits(date: entry.date)) .font(Font(UIFont(name: "Copperplate-Bold", size: 86) ?? .systemFont(ofSize: 86, weight: .bold))) .multilineTextAlignment(.trailing) .foregroundColor(.gray) .minimumScaleFactor(0.4) .lineLimit(1) } .padding(.trailing, 15) } .frame(maxWidth: .infinity, maxHeight: .infinity) .background(Image(uiImage: #imageLiteral(resourceName: "moon")), alignment: .center) // Add a fallback background color to debug layout issues .background(Color.black) } }
Additional Debug Tips
- Add previews for all widget sizes to catch layout issues early:
struct Widget_Previews: PreviewProvider { static var previews: some View { Group { WidgetEntryView(entry: SimpleEntry(date: Date())) .previewContext(WidgetPreviewContext(family: .systemSmall)) WidgetEntryView(entry: SimpleEntry(date: Date())) .previewContext(WidgetPreviewContext(family: .systemMedium)) WidgetEntryView(entry: SimpleEntry(date: Date())) .previewContext(WidgetPreviewContext(family: .systemLarge)) } } } - Use Xcode's Debug View Hierarchy (button in the debug bar) on the simulator/device to inspect the widget's view tree—you'll be able to see if views are hidden, out of bounds, or missing entirely.
- Double-check your
DateManagermethods to ensure they handle time zones correctly and never returnnil(add guard clauses or default values inside those methods).
内容的提问来源于stack exchange,提问作者Bernard

