Like many things in Apple’s widgets, they are doing things we don’t have access to. If there is a way to do what you are looking for, I would love to know what it is, but based on my testing there is literally no way to make text be any color other that white or the accent color with some level of opacity.
On top of that, the Widget views have no way of knowing what the accent color is so there is no way to adjust based on having a light or dark accent color.
Our inability to really layer things and maintain readibility is one of the many shortcomings in the tinted widget system that came out this year
Post
Replies
Boosts
Views
Activity
The today widgets have been deprecated for years. I believe that was done in 2020 when they introduced the new style of widgets, but maybe it was a year later. With iOS 18, the Today Extension Widgets are being completely removed. You can keep them in your app for the benefit of iOS 17 or older users, but there is no option to support them on iOS 18. Any widgets should be implemented using WidgetKit
It isn’t covered because it isn‘t a new mode. It is just new to the Home Screen. The answer to your question depends on which thing you are referring to.
if you need to know in your code that you are in the tinted mode, to choose a different image for instance, you can check the widgetRenderingMode environment variable
when it is in the tinted mode, this should be accented
if you are specifically asking about how to color something in the accent color, you just need to add the widgetAccentable() modifier to what ever view you want to take on the accent color
What you are trying to do is not possible and not how the mentioned methods are intended to work.
when you interact with a widget, your app intent will be called and when that intent finishes the perform method your widget will get one guaranteed reload that will happen immediately. There is no way for it to update the widget multiple times. note That even that one update only applies to the widget that was interacted with. If you have multiple widgets, they may or may not get updated automatically.
Calls to reloadAllTimelines is always a suggestion to the system and should never be expected to immediately refresh the widgets. Apple has never really documented what the algorithm is here, but things like how often you are refreshing the widget, how often the user is using your app, and the systems battery power seem to play a role in that decision.
There is nothing you can do because that is not how the widget update system works at all. Any request to update the widgets is a suggestion and the system will schedule the update as it wants. The only way to get your widget to change at an exact time is to schedule a timeline entry for that time, but that requires knowing what it will look like in advance.
Notice that the policy you are using is “after” and not “at”. It is telling the system to wait until at least the specified time.
The time when a particular timeline entry is show is 100% controlled by the date field in your TimelineEntry. I can think of two possible things they might be going on. One is that you aren’t actually providing all the timeline entries you think you are. The second, and more likely, possibility is that you aren’t being specific enough with your time. If you generate timeline entries on Monday at 2pm create the first entry at the current time and then just add 1 day to get the Tuesday entry, the actual time will end up at Tuesday at 2pm which is when it will change. If you want it to show correctly you need to make sure the time is zeroed out to midnight For your entries.
You are 100% right that the timer text field desperately needs formatting controls. I could delete a massive amount of code if it would just stop including the seconds field.
As to your problem, keep in mind that since you have no control over when the timeline generation code runs, it is almost certainly not happening right on a minute mark. Before you start generating your timeline entries take “now” and remove the seconds part of the time. the easiest way to do this is break the date into components and then rebuild it with the seconds hard-coded to zero. Start with that date and continue on. That will make all of the timeline entries at exactly the minute mark
What you have above is invalid, because you are trying to make two different widget definitions with the same “kind”. That value serves as the unique identifier for a widget definition. For a single given widget, they cannot have differences between configuration options at the various sizes (much to my own frustration). The only way to do what you are trying to do is make one widget for small/medium and a different widget for large (which means specifying a different ”kind”. The two different widgets can share a name and description so they sort of look like the same widget but there are a number of places that that it will be obvious they are split
There is no way to do that by design. If a user has multiple copies of a widget with matching configurations, I think Apple uses the same timeline to feed those multiple widgets.
The thing you want to do is possible using disfavoredLocations(for:).
https://developer.apple.com/documentation/swiftui/widgetconfiguration/disfavoredlocations(_:for:)
That seems like it should work. I am using a very similar form without problem and I am deploying back to iOS 15
extension View {
func widgetBackground(_ color: Color) -> some View {
if #available(iOSApplicationExtension 17.0, macOSApplicationExtension 14.0, *) {
return containerBackground(color, for: .widget)
} else {
return background(color)
}
}
}
Home screen widgets are drawn twice per timeline entry: once for light mode and once for dark mode. That allows it to switch between the modes instantly without having to rerun the widget extension.
Lock screen widgets are drawn many more times that that: they render once for every combination of: dark/light mode, vibrancy, privacy, etc.
That is not possible. Lock screen widgets, at least as of iOS 16 beta 4, always use the vibrant mode. That mode renders varying opacity with a frosted glass look based on the gray scale version of colors in the view. The other render modes are primarily meant for watchOS at this time. There is no way to show color in lock screen widgets.
I don't know if this is the full code or reduced for display but there are a couple things I would suggest looking at:
Your View is not valid. You can't put a bunch of Text() views directly in the body. Try putting a VStack around the ForEach loop.
Inside of the dataTask block, make sure that the data object is not nil. You are force unwrapping the optional, but without ever making sure that it isn't nil.
It is not possible for 3rd party widgets to animate on the scale of seconds. The only way your widget can change that fast is if you use the provided relative time text strings which can tick seconds. Attempting to create timeline entries for every second will not work correctly. In my testing it doesn't end up refreshing any faster than every 5 seconds in the best case scenario.. Hour/minute dials are certainly possible since 1 timeline entry every minute is well within reason, just don't try to create an entire day's worth of entries at one time.
Pro tip: If you are trying to update on the minute, make sure you zero out the seconds for your timeline entires since it is really easy to end up using whatever seconds value gets returned by Date()