I was really comfortable using PencilKit in SwiftUI, however I revisited a project and apparently there is a bug in Xcodes new version where strokes disappear after drawing them in the simulator.
I am running Version 14.1 of Xcode.
I set up a minimal code example to show my problem:
import SwiftUI
import PencilKit
struct ContentView: View {
var body: some View {
PKCanvasRepresentation()
}
}
struct PKCanvasRepresentation : UIViewRepresentable {
func makeUIView(context: Context) -> PKCanvasView {
var canvas = PKCanvasView()
canvas.drawingPolicy = .anyInput
return canvas
}
func updateUIView(_ uiView: PKCanvasView, context: Context) {
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
This does not draw correctly in the preview or simulator but it works if I run it on a non-virtual testing device. Does anyone found a solution to this, as it makes debugging really uncomfortable.
this is an Xcode 14 bug that specifically happens with an iOS 16 simulator.
At first I suspected the hardware, but this was not confirmed. With the same project, hardware, Xcode and simulator, it is simply random whether it works.
Related
I have a SwiftUI app that shows a GKGameCenterViewController. I am hitting a problem which is specific to iPads running iPadOS 16.1 and above in light mode only. Under these circumstances, the child views of GKGameCenterViewController appear as black text on a dark background, which is very difficult to read - see screenshot for the leaderboard "Test" below.
The app runs with versions of iOS/iPadOS 14.0 and above. The problem is very specific to iPads running iPadOS 16.1 and above in light mode. The top-level parent view of GKGameCenterViewController (showing the title "Game Center" and a navigation menu) works fine, only the child views are affected. The problem is not seen on iPhones, nor on iPads running versions of iPadOS 14 or 15. The problem is also not seen on iPads running iPadOS 16.1 and above if dark mode is in operation when GKGameCenterViewController is first shown.
The GKGameCenterViewController is being presented using a UIViewControllerRepresentable as a layer in a ZStack. From the examples I could find, using UIViewControllerRepresentable seems to be the standard way to do it, as also described in How to display Game Center leaderboard with SwiftUI.
It is interesting to note that the problem is not seen when the Game Center dashboard is shown by tapping the Game Center access point. I assume that the access point shows the GKGameCenterViewController in a different way.
The following stripped-down code illustrates how the GKGameCenterViewController is being shown. This is a standalone app that can be used to reproduce the problem. However, for Game Center authentication to work and for the overview of leaderboards to show, the following needs to be done too:
in Xcode, Game Center needs to be added as a capability to the app target
the app needs to be added to App Store Connect
Game Center needs to be enabled for the app version in App Store Connect
a leaderboard needs to be added.
import SwiftUI
import GameKit
#main
struct GameCenterBlackoutApp: App {
var body: some Scene {
WindowGroup {
MyContentView()
}
}
}
struct MyContentView: View {
#State private var showingGameCenter = false
var body: some View {
ZStack {
Button("Show Game Center leaderboards") {
showingGameCenter = true
}
if showingGameCenter {
MyGameCenterView(showingGameCenter: $showingGameCenter)
.ignoresSafeArea()
}
}
.onAppear {
// Authenticate the local player
GKLocalPlayer.local.authenticateHandler = handleAuthenticationOutcome
}
}
private func handleAuthenticationOutcome(vc: UIViewController?, error: Error?) {
if let error {
#if DEBUG
print("Failed to authenticate player: \(error)")
#endif
}
// Prepare and show the GameCenter access point.
// If authentication failed then the access point takes
// the form of a button to sign in
GKAccessPoint.shared.location = .topTrailing
GKAccessPoint.shared.showHighlights = false
GKAccessPoint.shared.isActive = true
}
}
/// A Bridge between the Game Center view controller and its wrapper
final class MyCoordinator : NSObject, GKGameCenterControllerDelegate {
#Binding private var showingGameCenter: Bool
init(showingGameCenter: Binding<Bool>) {
self._showingGameCenter = showingGameCenter
}
func gameCenterViewControllerDidFinish(
_ gameCenterViewController: GKGameCenterViewController
) {
gameCenterViewController.dismiss(animated:false)
showingGameCenter = false
}
}
/// A wrapper for GKGameCenterViewController
struct MyGameCenterView: UIViewControllerRepresentable {
typealias Coordinator = MyCoordinator
/// Binding to the state variable that controls the visibility of the Game Center layer
#Binding private var showingGameCenter: Bool
init(showingGameCenter: Binding<Bool>) {
self._showingGameCenter = showingGameCenter
}
/// Factory function for the Bridge between the GKGameCenterViewController and this wrapper view
func makeCoordinator() -> Coordinator {
MyCoordinator(showingGameCenter: $showingGameCenter)
}
/// Creates the GKGameCenterViewController
func makeUIViewController(
context: UIViewControllerRepresentableContext<MyGameCenterView>
) -> GKGameCenterViewController {
let result = GKGameCenterViewController(state: .leaderboards)
result.gameCenterDelegate = context.coordinator
return result
}
/// Stub implementation of protocol method
func updateUIViewController(
_ gameCenterViewController: GKGameCenterViewController,
context: UIViewControllerRepresentableContext<MyGameCenterView>
) {
// NOP
}
}
I would be really grateful for any workaround that will resolve the black text issue as described and allow the child views of GKGameCenterViewController to be shown in a normal, readable foreground color. I have tried all of the following, none of which made any difference:
setting .dark or .light as .overrideUserInterfaceStyle on the view controller
applying .environment(\.colorScheme, .dark) to the UIViewControllerRepresentable or to a higher-level parent
applying .dark or .white as .preferredColorScheme on the UIViewControllerRepresentable
using modifier .toolbarColorScheme(all combinations of parameters) on the UIViewControllerRepresentable
applying Color.white as .foregroundColor on the UIViewControllerRepresentable
using black or white background behind the UIViewControllerRepresentable
showing the UIViewControllerRepresentable as an overlay instead of as a ZStack layer
not enabling the Game Center access point
using other GKGameCenterViewControllerState values in the init call
using other init functions for GKGameCenterViewController
using deprecated init functions and setters on GKGameCenterViewController.
BTW, I also reported the issue to Apple, but they have not been able to help.
i'm trying to add hardware keyboard support for an iOS 14.0 app written in SwiftUI 2.0.
I saw some examples working with UIHostingController, so i'd like to try this way on iOS14/SWiftui 2.0 using WindowGroup.
I'm gettin gerror when compiling in XCODe 12.3
"Generic struct 'WindowGroup' requires that 'KeyTestController' conform to 'View'"
ContentView() conforms to View and everything is working fine when not using the "KeyTestController" class.
Any way to solve this ?
Thank you very much.
import SwiftUI
import StoreKit
import UIKit
#main
struct myApp: App
{
var body: some Scene
{
WindowGroup
{
KeyTestController(rootView:ContentView())
}
}
}
class KeyTestController<Content>: UIHostingController<Content> where Content: View
{
/* CODE …… */
}
I've had my app inside a NavigationView using the StackNavigationViewStyle style for some time with no problems. Recently I wanted to add a sidebar to it though, so I thought I should try using the DoubleColumnNavigationViewStyle style for this. At the moment I can kind of make it work but it has some quirks:
If I am in a subview, and I try to slide back into its parent view, sliding back always brings the side bar into view instead of taking me back into the parent view which is what I would expect. Now matter how deep into my view hierarchy I am. (If you use the default Notes app and select View as a Gallery, that is exactly the way I expect my app to work like).
Much less important but annoying nonetheless is that if I press the back button, the nice animations of the sliding < back buttons into/out of view I got when I used StackNavigationViewStyle no longer happen. The buttons work fine but the animations are much worse now.
Here is a sample minimum app and a video to show what I mean:
import SwiftUI
struct ContentView: View {
var body: some View {
NavigationView {
Text("Sidebar")
MainView()
}
}
}
struct MainView: View {
var body: some View {
Text("Main View")
NavigationLink(destination: Text("Sub View")) {
Text("Go to Sub View")
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Thanks!
I have problem with making sidebar look transparent. All advices about implementing it (even official Apple Documentation) is on AppDelegate/SceneDelegate. But since last update projects have only this file:
'''
import SwiftUI
import UIKit
#main
struct SpenTApp: App {
var body: some Scene {
WindowGroup {
NavigationView {
SideBarView()
.background(Color.clear)
DetailView()
}
.navigationViewStyle(DoubleColumnNavigationViewStyle())
}
}
}
Catalyst apps have some weird limitations, so to do what you want: SideBarView must be a List with listStyle(SidebarListStyle()).
Starting from the simple iOS App template, I make my "ContentView.swift":
import SwiftUI
struct ContentView: View {
var body: some View {
Button(action: {
print("hello console!")
}, label: {
Text("Button")
})
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
I start up a preview in Debug Preview, I activate the console so it shows up below, I see my button that says "Button". I click the button on the text that says "Button", but still see nothing. What am I missing??
You need to enable Debug Preview.
From SwiftUI tips and tricks:
If you press play in the SwiftUI preview to
try out your designs, you’ll find that any calls to print() are
ignored. If you’re using print() for testing purposes – e.g. as simple
button tap actions – then this can be a real headache.
Fortunately, there’s a simple fix: right-click on the play button in
the preview canvas and choose “Debug Preview”. With that small change
made you’ll find your print() calls work as normal.