Swift animation freezes when page loads, swiftui - animation

I use a Lottie animation in SwiftUI. Sometimes, when pages loads, animation freezes for a couple of seconds. I would like to know if it is possible to dispatch task or do anything in order to have the animation never freeze. File is stores locally in the app, Lottie is displayed in SwiftUI:
if condition { LottieLoading() }
import SwiftUI import Lottie
struct LottieLoading: UIViewRepresentable {
func makeUIView(context: UIViewRepresentableContext<LottieLoading>) -> UIView {
let view = UIView(frame: .zero)
let animationView = AnimationView()
let animationLottie = Animation.named("progress_relat")
animationView.animation = animationLottie
animationView.contentMode = .scaleAspectFit
animationView.loopMode = .loop
animationView.animationSpeed = 2
animationView.play()
animationView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(animationView)
NSLayoutConstraint.activate([
animationView.heightAnchor.constraint(equalTo: view.heightAnchor),
animationView.widthAnchor.constraint(equalTo: view.widthAnchor)
])
return view
}
func updateUIView(_ uiView: UIViewType, context: Context) {
}
}

Related

SwiftUI 2.0 can't remove .titled from styleMask on NSWindow using NSViewRepresentable

I'm reworking my app for SwiftUI 2.0 but have come across a problem when replicating what I could do with AppDelegate.
I'm using NSViewRepresentable to get access to NSWindow so I can remove the titlebar of the window (I know it's not in the guidelines but this will never be submitted). When removing .titled from styleMask, the app crashes.
struct WindowAccessor: NSViewRepresentable {
#Binding var window: NSWindow?
func makeNSView(context: Context) -> NSView {
let view = NSView()
DispatchQueue.main.async {
self.window = view.window
self.window?.isOpaque = false
self.window?.titlebarAppearsTransparent = true
self.window?.backgroundColor = NSColor.clear
self.window?.styleMask = [.fullSizeContentView]
self.window?.isMovableByWindowBackground = true
self.window?.backingType = .buffered
}
return view
}
func updateNSView(_ nsView: NSView, context: Context) {}
}
#main
struct MyApp_App: App {
#State private var window: NSWindow?
var body: some Scene {
WindowGroup {
ContentView().background(WindowAccessor(window: $window))
}
}
}
struct ContentView: View {
var body: some View {
Text("Hello, world!").padding().background(Color(NSColor.windowBackgroundColor))
}
}
When I run the app I get Thread 1: EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
All I'm trying to achieve with my app is a Menu Bar application that looks exactly like Spotlight. No dock icon, no title bar, all preferences to be handled by a popover or another window.
EDIT:
Is this something to do with the canBecomeKey property?

SwiftUI 2.0 disable window's zoom button on macOS

I am writing a small App for the Mac..
I need to disable to (Green Button) for full screen.
I am using SwiftUI App not AppKit App Delegate
Cant find how to disable the Full Screen Button for my app.
Any thoughts?
Because no one answered with a cleaner SwiftUI only version:
struct ContentView: View {
var body: some View {
HostingWindowFinder { window in
window?.standardWindowButton(.zoomButton)?.isHidden = true //this removes the green zoom button
}
Text("Hello world")
}
}
struct HostingWindowFinder: NSViewRepresentable {
var callback: (NSWindow?) -> ()
func makeNSView(context: Self.Context) -> NSView {
let view = NSView()
DispatchQueue.main.async { [weak view] in
self.callback(view?.window)
}
return view
}
func updateNSView(_ nsView: NSView, context: Context) {}
}
HostingWindowFinder concept taken from https://lostmoa.com/blog/ReadingTheCurrentWindowInANewSwiftUILifecycleApp/

Approach to use a SwiftUI view together with a UIView

I'm using a 3rd party library developed with UIKit. It's API needs a reference to a UIView.
How can I use this library inside SwiftUI? And how can I convert a SwiftUI view to a UIView?
I've tried creating a UIViewRepresentable like this:
struct SomeView: UIViewRepresentable {
let contentViewController: UIViewController
init<Content: View>(contentView: Content) {
self.contentViewController = UIHostingController(rootView: contentView)
}
func makeUIView(context: Context) -> UIKitView {
// Whatever I do here doesn't work. Frame is always 0
contentViewController.loadViewIfNeeded()
contentViewController.view.setNeedsDisplay()
contentViewController.view.layoutIfNeeded()
print(contentViewController.view.frame)
let uikitView = UIKitView()
uikitView.show(contentViewController.view)
return popover
}
func updateUIView(_ uiView: UIKitView, context: Context) {
}
}

Xcode 11.1 Only Takes Square Photos - Need 4:3

I'm using the camera to capture images for an app. Once I touch the photo button, I am
only able to save the photo in a square format. I want to preserve the 4:3 format for
older cameras and eventually allow the user to choose 16:9 if desired. I have not been
able to find any code to programmatically chose aspect ratio. I only get square. I even
tried locking the Camera Mode in Camera Settings on the device. Thankfully, that
didn't work.
It is a SwiftUI app. In the CameraViewController below, if I remove the allowsEditing
option, the picker freezes - neither the Use Photo, nor Retake buttons function. The
app does not crash, just the view is frozen. I am able to swipe down the view to
dismiss and continue using the app.
I call the PhotoCaptureView below from a button in what would be the detail view of
a master/detail equivalent.
PhotoCaptureView:
import SwiftUI
struct PhotoCaptureView: View {
#EnvironmentObject var cameraSettings: CameraSettings
#Binding var photos: [UIImage]
var body: some View {
return VStack {
CameraViewController(photos: $photos)
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
}.edgesIgnoringSafeArea(.all)
}
}
And the model view CameraViewController:
import UIKit
import SwiftUI
import MobileCoreServices
import AVFoundation
struct CameraViewController: UIViewControllerRepresentable {
#EnvironmentObject var cameraSettings: CameraSettings
#Binding var photos: [UIImage]
func updateUIViewController(_ uiViewContyroller: UIImagePickerController, context: Context) {
//no code here
}
func makeUIViewController(context: UIViewControllerRepresentableContext<CameraViewController>) -> UIImagePickerController {
let vc = UIImagePickerController()
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerController.SourceType.camera) {
vc.sourceType = .camera
vc.allowsEditing = true
vc.delegate = context.coordinator
return vc
}
return UIImagePickerController()
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
var parent: CameraViewController
init(_ imagePickerController: CameraViewController) {
self.parent = imagePickerController
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
guard let image = info[.editedImage] as? UIImage else {
print("no image found")
return
}
print("Image taken successfully, with size \(image.size)")
parent.photos.append(image)
picker.dismiss(animated: true) {
print("in dismiss after successful picture")
}
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
picker.dismiss(animated: true) {
print("in did cancel")
}
}
private func pickerController(_ controller: UIImagePickerController, didSelect image: UIImage?) {
controller.dismiss(animated: true, completion: nil)
}
}
}
The CameraSettings are just Bools to determine whether to present the camera option.
class CameraSettings: ObservableObject {
#Published var isAuthorized: Bool = false
#Published var isCameraAvailable: Bool = false
}
Xcode 11.1 (11A1027) I am using an iPhone X iOS 13.1.2
Any guidance would be appreciated.
The info setting of didFinishPickingMediaWithInfo needs to specify "originalImage" to avoid the square only picture. Even with the edited version, however, it seems you can only move the image around - not change the aspect.
change the info line above to:
guard let image = info[.originalImage] as? UIImage else {
Then set:
vc.allowsEditing = false
Importantly the documentation tells me that: "The UIImagePickerController class supports portrait mode only."

Using SwiftUI in Xcode 11 playground

I know how to use SwiftUI in Xcode 11 in a regular app project, but I was wondering if there was a way to use it in playgrounds as well, even if I couldn't use the live editor?
Sure, it's pretty easy:
import PlaygroundSupport
PlaygroundPage.current.liveView = UIHostingController(rootView: PlaygroundRootView())
public struct PlaygroundRootView: View {
public init() {}
public var body: some View {
Text("Hello World!")
}
}
see more here:
https://github.com/attoPascal/SwiftUI-Tutorial-Playground
On macOS Mojave besides using PlaygroundPage.current.liveView you can draw your SwiftUI view into an image. That way you can have multiple "live views" in your playground.
Check out this article: https://ericasadun.com/2019/06/20/swiftui-render-your-mojave-swiftui-views-on-the-fly/
The sample code is hosted here
https://gist.github.com/erica/fb5005f625207e108836175ff201d8f2
The renderedImage utility code (copyright by Erica Sadun!)
import PlaygroundSupport
import SwiftUI
extension UIView {
var renderedImage: UIImage {
let image = UIGraphicsImageRenderer(size: self.bounds.size).image { context in
UIColor.lightGray.set(); UIRectFill(bounds)
context.cgContext.setAlpha(0.75)
self.layer.render(in: context.cgContext)
}
return image
}
}
extension View {
var renderedImage: UIImage {
let window = UIWindow(frame: CGRect(origin: .zero, size: CGSize(width: 320, height: 160)))
let hosting = UIHostingController(rootView: self)
hosting.view.frame = window.frame
window.rootViewController = hosting
window.makeKey()
return hosting.view.renderedImage
}
}

Resources