Hello,
I'm thinking about how to improve my main tvOS app flow, naively I want to do something like this:
import Combine
import SwiftUI
enum AppState {
case login, onboarding, main
}
class AppStateManager {
let appStatePublisher = PassthroughSubject<AppState, Never>()
func updateState(_ appState: AppState)
}
struct tvOSApp: App {
private var appState: AppState = .login
private let appStateManager = AppStateManager()
var body: some Scene {
WindowGroup {
ZStack {
switch appState {
case .login:
LoginView()
case .onboarding:
OnboardingView()
case .main:
MainView()
}
}
.onReceive(appStateManager.appStatePublisher) {
self.appState = $0
}
}
}
}
So basically, MainView, OnboardingView and LoginView would be the main navigation views of my app, and the appStateManager would be a dependency passed to each of these views and allowing me to update the currently displayed view in the app. (of course I could use an Environment object instead for a 100% SwiftUI solution).
I was wondering, however, if there is a better way to do this, instead of switching in a ZStack, maybe with WindowGroup/Window/Scenes?
Thank you for your help!
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Created
Hi,
I'm an experienced developer on Apple platforms (having worked on iOS/tvOS projects for more than 10 years now). However, I've only worked on applications, or simple games which didn't require more than using UIKit or SwiftUI.
Now, I'd like to start a new project, recreating an old game on tvOS with 3D graphics. This is not a project I plan to release, only a simple personal challenge.
I'm torn with starting this project with either SceneKit, or Unity.
On one hand, I love Apple frameworks and tools, so I guess I could easily progress with SceneKit. Also, I don't know Unity very well, but even if it's a simple project, I've seen that there are several restrictions for free plans (no custom splash screen, etc).
On the other hand, I've read several threads (i.e. this one) making it look like that SceneKit isn't going anywhere, and clearly recommending Unity due to the fact that its documentation is way better, and the game more easily portable to other platforms.
Also, if I'm going to learn something new, maybe I could learn more with Unity (using a completely different platform, software and language) than I would with SceneKit and Swift stuff.
What's your opinion about this?
Thanks!
I have a UIViewController that presents a UIDocumentPicker to pick PDF files, and contains a UICollectionView that displays them (each cell contains a PDFView to do so).
Here is the code:
import MobileCoreServices; import PDFKit; import UIKit
class ViewController: UIViewController {
var urls: [URL] = []
@IBOutlet weak var collectionView: UICollectionView!
@IBAction func pickFile() {
DispatchQueue.main.async {
let documentPicker = UIDocumentPickerViewController(documentTypes: [kUTTypePDF as String], in: .import)
documentPicker.delegate = self
documentPicker.modalPresentationStyle = .formSheet
self.present(documentPicker, animated: true, completion: nil)
}
}
override func viewDidLoad() {
collectionView.register(UINib(nibName: PDFCollectionViewCell.identifier, bundle: .main),
forCellWithReuseIdentifier: PDFCollectionViewCell.identifier)
}
init() { super.init(nibName: "ViewController", bundle: .main) }
required init?(coder: NSCoder) { fatalError() }
}
extension ViewController: UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: PDFCollectionViewCell.identifier, for: indexPath) as! PDFCollectionViewCell
cell.pdfView.document = PDFDocument(url: urls[indexPath.row])
return cell
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return urls.count
}
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
CGSize(width: 150, height: 150)
}
}
extension ViewController: UIDocumentPickerDelegate {
// MARK: PDF Picker Delegate
func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) {
controller.dismiss(animated: true, completion: nil)
}
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
controller.dismiss(animated: true, completion: {
DispatchQueue.main.async {
self.urls.append(contentsOf: urls)
self.collectionView.reloadData()
}
})
}
}
class PDFCollectionViewCell: UICollectionViewCell {
static let identifier = "PDFCollectionViewCell"
@IBOutlet weak var pdfView: PDFView! { didSet { setPdfViewUI() } }
func setPdfViewUI() {
pdfView.displayMode = .singlePage
pdfView.autoScales = true
pdfView.displayDirection = .vertical
pdfView.isUserInteractionEnabled = false
}
}
Now, for some reason, the collectionView.reloadData()
actually only works one time in two. It works the first time, then the second time nothing happens, then the third time the collection view is updated again with the three expected elements...
I realized that even if I'm calling reloadData(), the dataSource and delegate methods (numberOfItems/cellForItem) are not getting called when this happens.
Any idea of what is happening? Am I doing something wrong?
Thank you for your help!