My app, Class Clock, currently offers a Today Widget that displays a circular timer similar to the timer in iOS 13 and a few labels to show the user how much time is left in class. With the new WidgetKit, I understand the widget's timeline is only updated every so often. However, if the circular timer needs to load every minute, how can this be achieved? Could I perhaps tell the timeline that Class A is from 10 - 11 and the widget then animates between 10 and 11 on its own without calling a new timeline every minute? Ideally, the circular progress indicator would continue to animate its SwiftUI Circle trim percentage every second or minute.
Post
Replies
Boosts
Views
Activity
I am creating a widget that includes a countdown to the next period of the day using a
Text(entry.endDate, .timer)
I would like to modify the text so that it can simplify the time to the minutes and can be read as
5 min Is it possible to modify the format of the date with the timer textfield for the widget?
I have been trying to implement a sphere I have created from SceneKit into a widget I have made with WidgetKit. However, upon running, I receive a fatal error in the timeline stating
PlatformViewRepresentableAdaptor<UIKitSceneView>
Below is the relevant code to the SceneKit and WidgetKit along with the import statements
Please keep in mind that even when using an empty scene rather than one with all of the details below, I received the same error.
import WidgetKit
import SwiftUI
import Intents
import SceneKit
import UIKit
extension SCNMaterial {
convenience init(color: UIColor) {
self.init()
diffuse.contents = color
}
convenience init(image: UIImage) {
self.init()
diffuse.contents = image
}
}
func addBloom() -> [CIFilter]? {
let bloomFilter = CIFilter(name:"CIBloom")!
bloomFilter.setValue(0.2, forKey: "inputIntensity")
bloomFilter.setValue(35, forKey: "inputRadius")
return [bloomFilter]
}
func sceneSetup() -> SCNScene{
let scene = SCNScene()
let sphere = SCNSphere(radius: 1)
sphere.segmentCount = 100
let mat = SCNMaterial(image: UIImage(named: "desaturated.png")!)
sphere.materials = [mat]
sphere.firstMaterial?.diffuse.wrapS = SCNWrapMode.clamp
sphere.firstMaterial?.diffuse.wrapT = SCNWrapMode.clamp
let sphereNode = SCNNode(geometry: sphere)
sphereNode.filters = addBloom()
scene.rootNode.addChildNode(sphereNode)
let ambientLightNode = SCNNode()
ambientLightNode.light = SCNLight()
ambientLightNode.light!.type = SCNLight.LightType.ambient
ambientLightNode.light!.color = UIColor(white: 0.8, alpha: 1.0)
scene.rootNode.addChildNode(ambientLightNode)
let omniLightNode = SCNNode()
omniLightNode.light = SCNLight()
omniLightNode.light!.type = SCNLight.LightType.omni
omniLightNode.light!.color = UIColor(white: 0.99, alpha: 1.0)
omniLightNode.position = SCNVector3Make(0, 0, 50)
scene.rootNode.addChildNode(omniLightNode)
sphereNode.rotation = SCNVector4(x: 0.0, y: 1.0, z: 0.0, w: 0.0)
sphereNode.runAction(SCNAction.rotate(by: 0.9*CGFloat(Double.pi), around: SCNVector3(x: 0.0, y: 1.0, z: 0.0), duration: 0.0))
return scene
}
struct ClassClockWidgetEntryView : View {
var entry: Provider.Entry
var scene = SCNScene()
@Environment(\.colorScheme) var colorScheme
var body: some View {
ZStack() {
SceneView(scene: sceneSetup())
}
.padding(.all, 25)
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .center)
.background(LinearGradient(gradient: colorScheme == .dark ? Gradient(colors: [Color( colorLiteral(red: 0.2549019754, green: 0.2745098174, blue: 0.3019607961, alpha: 1)), Color( colorLiteral(red: 0.121719892, green: 0.131788787, blue: 0.1464163903, alpha: 1))]) : Gradient(colors: [Color( colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)), Color( colorLiteral(red: 0.9109456692, green: 0.9109456692, blue: 0.9109456692, alpha: 1))]), startPoint: .topTrailing, endPoint: .bottomLeading))
.edgesIgnoringSafeArea(.all)
}
}
Currently, I have developed a widget that relies on time sensitive information and creates a timeline divided into events that occur on a minute-basis. Because I am loading so many events into the timeline, I kept the length of the timeline small to prevent the timeline from storing thousands of events rather than less than a hundred or so. Then, at the end of that timeline, I request a new timeline with the next set of events.
However, I am now noticing that when the end of the timeline is reached, the device tends not to immediately request the new timeline. For that reason, I am considering loading the entire day's events into one timeline.
That brings me to my question - Is loading the entire day's timeline okay in this situation and/or are there any potential risks of the timeline refusing to accept so many events?
After coding in the SceneKit lab, I was able to produce a scene that displays a sphere that rotates over time. The Apple Engineer suggested that I use the new scene view snapshot() method in order to export the scene as an image. However, the image appears to render before the sphereNode.runAction(SCNAction.rotate()) method completed despite it having a duration of 0.0. I believe this is because that method is an animation method.
After testing, I have found that the use of the sphereNode.rotate() method does work with the snapshot. However, that method uses quaternions rather than the angles I was working with before.
I am having a hard time understanding how to convert from my original angles to the new quaternions to achieve the same result.
As of now, I am using
sphereNode.rotation = SCNVector4(x: 0.0, y: 1.0, z: 0.0, w: 0.0)
sphereNode.runAction(SCNAction.rotate(by: 1.1*CGFloat(Double.pi), around: SCNVector3(x: 0.0, y: 1.0, z: 0.0), duration: 0.0))
If somebody could explain how to either continue rotating with an angle while working with the snapshot method or how to convert from my current rotation to the quaternion method, I would greatly appreciate the help. Below is the full code for my scene.
var sceneView = SCNView(frame: CGRect(x: 0, y: 0, width: 500, height: 500))
extension SCNMaterial {
convenience init(color: UIColor) {
					...
}
convenience init(image: UIImage) {
					...
}
}
func addBloom() -> [CIFilter]? {
		...
return [bloomFilter]
}
func sceneSetup(completion: () -> ()) {
let scene = SCNScene()
sceneView.backgroundColor = UIColor(red: 0.09, green: 0.09, blue: 0.09, alpha: 1.00)
let sphere = SCNSphere(radius: 1)
sphere.segmentCount = 100
let mat = SCNMaterial(image: UIImage(named: "desaturated.png")!)
sphere.materials = [mat]
sphere.firstMaterial?.diffuse.wrapS = SCNWrapMode.clamp
sphere.firstMaterial?.diffuse.wrapT = SCNWrapMode.clamp
let sphereNode = SCNNode(geometry: sphere)
sphereNode.filters = addBloom()
scene.rootNode.addChildNode(sphereNode)
sceneView.scene = scene
let ambientLightNode = SCNNode()
ambientLightNode.light = SCNLight()
ambientLightNode.light!.type = SCNLight.LightType.ambient
ambientLightNode.light!.color = UIColor(white: 0.8, alpha: 1.0)
scene.rootNode.addChildNode(ambientLightNode)
let omniLightNode = SCNNode()
omniLightNode.light = SCNLight()
omniLightNode.light!.type = SCNLight.LightType.omni
omniLightNode.light!.color = UIColor(white: 0.99, alpha: 1.0)
omniLightNode.position = SCNVector3Make(0, 0, 50)
scene.rootNode.addChildNode(omniLightNode)
sphereNode.rotation = SCNVector4(x: 0.0, y: 1.0, z: 0.0, w: 0.0)
sphereNode.runAction(SCNAction.rotate(by: 1.1*CGFloat(Double.pi), around: SCNVector3(x: 0.0, y: 1.0, z: 0.0), duration: 0.0))
completion()
}