Live Activity compact timers

The Human Interface Guidelines for Live Activities provide several examples of compact presentations that have a timer counting down formatted like "3min" or "3m", similar to the timers in the Clock app. Such examples can be found in this Stack Overflow question: https://stackoverflow.com/questions/77551496/is-it-possible-to-make-an-only-minutes-1m-countdown-in-a-live-activity

A Timer initialized with init(timerInterval:pauseTime:countsDown:showsHours:) has provided a live countdown timer in widgets and live activities, but the formatting is limited. And since live activities come with limitations that prevent us from using Timers, there's no real way to implement this kind of thing ourselves.

What is Apple's official guidance for implementing this kind of timer for the compact presentation?

Hi @tjhorner ,

I think you're looking for this: https://developer.apple.com/documentation/swiftui/text/init(_:format:)-9d2x4

It's the newly introduced text formatter for dates.

As a heads up, here's a post I answered about what seems to be a bug in this timer-wise though: https://forums.developer.apple.com/forums/thread/756971

If you also run into this, I'd really appreciate it if you also file a feedback report and paste the FB number here.

same problem

Same. Hoping to find a non-beta solution as well.

I too have been searching for a way to get a timer to show within a Live Activity view in a format like 3m or 3min as is shown in the Apple Documentation.

From what I've found so far, the new TImeDataSource available in iOS 18 gets closest:

Text(TimeDataSource<Date>.durationOffset(to: startDate), format: .units(allowed: [.hours, .minutes], width: .narrow, fractionalPart: .hide(rounded: .down)))

This creates an updating Duration based on the difference between the current time and the offset date and will work within a LiveActivity view (mostly**).

This example formatting displays a timer that counts up from your startDate Date in Xm format. When reaching an hour, it would shift to Xh and subsequently Xh Xm.

There's a helpful resource created here that outlines FormatStyle options:

https://goshdarnformatstyle.com/duration-styles/

**Within a regular app view, the timer value updates as expected...at the top of a new minute. However, I notice that the values seem to update inconsistently within a LiveActivity view like the Dynamic Island. If anyone has a fix for that, I'd love to see it.

Other unsolved challenges:

  1. Because this requires TimeDataSource, it will not work with earlier iOS versions--I have not found an alternative there.
  2. The width of the generated Text frame is huge which creates a challenge, especially in compact Dynamic lsland views. The only way I've found to fit the timer is to use the TimeDataSource as an overlay above a hidden Text view. Unfortunately this approach makes it hard coded to a defined width so you either need to set your hidden Text to be the maximum potential timer width or push updates to redraw the Live Activity at key increments (e.g. 9m -> 10m, 60m to 1h, etc.)
Text("0m")
     .hidden()
     .overlay(alignment: .leading) {            
Text(TimeDataSource<Date>.durationOffset(to: startDate), format: xxxxx)
     }
  1. You can use this to format a countdown timer to a future date, but there's seemingly no way to remove the preceding negative sign within FormatStyle. The example below would show a countdown timer in Xh Xm format, but always with a negative sign.
Text(TimeDataSource<Date>.durationOffset(to: futureDate), format: .units(allowed: [ .minutes, .hours], width: .narrow, maximumUnitCount: 2, zeroValueUnits: .show(length: 1), valueLengthLimits: 2...3))
Live Activity compact timers
 
 
Q