SCNNode is not showing up - swift

I'm new in Swift and ARKit. For some reason the SCNNode node I'm trying to display is not showing up. I'm working with SwiftUI. I defined in the next code block the function addNode that should render the node.
import Foundation
import ARKit
import SwiftUI
// MARK: - ARViewIndicator
struct ARViewIndicator: UIViewControllerRepresentable {
typealias UIViewControllerType = ARView
func makeUIViewController(context: Context) -> ARView {
return ARView()
}
func updateUIViewController(_ uiViewController:
ARViewIndicator.UIViewControllerType, context:
UIViewControllerRepresentableContext<ARViewIndicator>) { }
}
class ARView: UIViewController, ARSCNViewDelegate {
var arView: ARSCNView {
return self.view as! ARSCNView
}
override func loadView() {
self.view = ARSCNView(frame: .zero)
}
override func viewDidLoad() {
super.viewDidLoad()
arView.delegate = self
arView.scene = SCNScene()
}
// MARK: - Functions for standard AR view handling
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let configuration = ARWorldTrackingConfiguration()
arView.debugOptions = [.showFeaturePoints,
.showWorldOrigin]
arView.session.run(configuration)
arView.delegate = self
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
arView.session.pause()
}
func addNode(){
let node = SCNNode()
node.geometry = SCNBox(width: 0.1,
height: 0.1,
length: 0.1,
chamferRadius: 0)
node.geometry?.firstMaterial?.diffuse.contents = UIColor.blue
node.position = SCNVector3(0,0,0.3)
arView.scene.rootNode.addChildNode(node)
arView.delegate = self
print(123)
}
// MARK: - ARSCNViewDelegate
func sessionWasInterrupted(_ session: ARSession) {}
func sessionInterruptionEnded(_ session: ARSession) {}
func session(_ session: ARSession, didFailWithError error: Error)
{}
func session(_ session: ARSession, cameraDidChangeTrackingState
camera: ARCamera) {}
}
... and that function is invoked when clicking the button "HOME"
import SwiftUI
import ARKit
// MARK: - NavigationIndicator
struct NavigationIndicator: UIViewControllerRepresentable {
typealias UIViewControllerType = ARView
func makeUIViewController(context: Context) -> ARView {
return ARView()
}
func updateUIViewController(_ uiViewController:
NavigationIndicator.UIViewControllerType, context:
UIViewControllerRepresentableContext<NavigationIndicator>) { }
}
struct ContentView: View {
#State var page = "Home"
var body: some View {
VStack {
ZStack {
NavigationIndicator()
VStack {
Spacer()
HStack {
Button("Home") {
let ar = ARView();
ar.addNode()
}.padding()
.background(RoundedRectangle(cornerRadius: 10)
.foregroundColor(Color.white).opacity(0.7))
Spacer()
}
}
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Do you know why it's not showing up ?
Thanks in advance !

Use this approach for SceneKitView:
import SwiftUI
import ARKit
struct SceneKitView: UIViewRepresentable {
let arView = ARSCNView(frame: .zero)
#Binding var pressed: Bool
#Binding var node: SCNNode
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
final class Coordinator: NSObject, ARSCNViewDelegate {
var control: SceneKitView
init(_ control: SceneKitView) {
self.control = control
}
func renderer(_ renderer: SCNSceneRenderer,
updateAtTime time: TimeInterval) {
if control.pressed {
self.control.node = self.addCube()
self.control.arView.scene.rootNode.addChildNode(control.node)
}
}
fileprivate func addCube() -> SCNNode {
control.node.geometry = SCNBox(width: 0.25,
height: 0.25,
length: 0.25,
chamferRadius: 0.01)
control.node.geometry?.firstMaterial?.diffuse.contents = UIColor.blue
control.node.geometry?.firstMaterial?.lightingModel = .phong
control.node.position = SCNVector3(0, 0,-2)
return control.node
}
}
func makeUIView(context: Context) -> ARSCNView {
arView.scene = SCNScene()
arView.delegate = context.coordinator
arView.autoenablesDefaultLighting = true
arView.debugOptions = .showFeaturePoints
// arView.allowsCameraControl = true
let config = ARWorldTrackingConfiguration()
arView.session.run(config)
return arView
}
func updateUIView(_ uiView: ARSCNView,
context: Context) { }
}
Then use this code for ContentView.
struct ContentView: View {
#State var pressed: Bool = false
#State var node = SCNNode()
var body: some View {
ZStack {
SceneKitView(pressed: $pressed, node: $node)
VStack {
Spacer()
HStack {
Button("Blue Cube") {
pressed.toggle()
}.padding()
.foregroundColor(.red)
Spacer()
}
}
}
}
}
P.S.
However, a strange issue occurs with ARSCNView in Simulator – after pressing a button a SCNBox appears only after tapping a screen with .allowsCameraControl = true.

Related

Take a picture (ID Card in this case) through a frame with rounded edges using SwiftUI

I have managed to take a correct picture of an ID Card, however, to help the user to frame it I need to do it through a frame with rounded edges exactly as shown in the image. I have tried many approaches without success. Could someone give me some guidance?
import UIKit
import SwiftUI
import AVFoundation
struct CameraView: UIViewControllerRepresentable {
#Binding var isShowing: Bool
#Binding var capturedImage: UIImage?
func makeUIViewController(context: UIViewControllerRepresentableContext<CameraView>) -> UIViewController {
let cameraView = UIImagePickerController()
cameraView.sourceType = .camera
cameraView.delegate = context.coordinator
return cameraView
}
func updateUIViewController(_ uiViewController: UIViewController, context: UIViewControllerRepresentableContext<CameraView>) {
}
func makeCoordinator() -> Coordinator {
return Coordinator(isShowing: $isShowing, capturedImage: $capturedImage)
}
class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
#Binding var isShowing: Bool
#Binding var capturedImage: UIImage?
init(isShowing: Binding<Bool>, capturedImage: Binding<UIImage?>) {
_isShowing = isShowing
_capturedImage = capturedImage
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
let image = info[UIImagePickerController.InfoKey.originalImage] as! UIImage
capturedImage = image
isShowing = false
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
isShowing = false
}
}
}
The way to handle this is to use the UIImagePickerController.cameraOverlayView property. You assign a UIView to this which is presented over the top of the camera.
Here's a (bad looking) example, using SwiftUI View and a UIHostingController…
struct Overlay: View {
var body: some View {
VStack(spacing: 0) {
Rectangle().fill(.black.opacity(0.5))
.frame(height: 100)
HStack(spacing: 0) {
Rectangle().fill(.black.opacity(0.5))
.frame(width: 20)
Color.clear
Rectangle().fill(.black.opacity(0.5))
.frame(width: 20)
}
.frame(maxWidth: .infinity)
.frame(height: 200)
Rectangle().fill(.black.opacity(0.5))
Color.clear
.frame(height: 200)
}
}
}
and then
func makeUIViewController(context: UIViewControllerRepresentableContext<CameraView>) -> UIViewController {
let cameraView = UIImagePickerController()
cameraView.sourceType = .camera
cameraView.delegate = context.coordinator
let overlayView = UIHostingController(rootView: Overlay()).view
overlayView?.backgroundColor = .clear
overlayView?.isUserInteractionEnabled = false
overlayView?.frame = (cameraView.cameraOverlayView?.frame)!
cameraView.cameraOverlayView = overlayView
return cameraView
}
gives…
There are more details in the Apple documentation

NSController calling function in NSView

I am trying to make NSViewControler work with NSView. I can't get myView to call any function in myView(NSView).
myView?.myFunctionName does not work and for NSView I get a nil error when I try set backgoundColor (myview?.layer?.backgroundColor = .white)
class ViewController: NSViewController {
#IBOutlet weak public var myview: NSView!
override func viewDidLoad() {
super.viewDidLoad()
myview?.wantsLayer = true
myview?.layer?.backgroundColor = .white
myview?.needsDisplay = true
}
override var representedObject: Any? {
didSet {
//Update the view, if already loaded.
}
}
}
import Cocoa
class myView: NSView {
var backgroundColor: NSColor?
override func draw(_ dirtyRect: NSRect) {
print("draw")
if let bg = backgroundColor {
bg.setFill()
dirtyRect.fill()
} else {
super.draw(dirtyRect)
print("error:\(String(describing: backgroundColor))")
self.changeBackgroundColor(color: .blue)
}
}
func changeBackgroundColor(color: NSColor) {
// print("change background\( bounds.size)")
// backgroundColor = color
var path = NSBezierPath()
path = NSBezierPath(rect: NSRect(origin:CGPoint(x: 0, y: 0), size: bounds.size))
// print("\(String(describing: path))")
path.close()
color.setFill()
path.fill()
setNeedsDisplay(self.bounds)
}
}

PryntTrimmerView in SwiftUI

I am working on a video editor app where I need a trimmer for the video. So I found this package. Now When I'm trying to show the TrimView,but it's not showing up on my SwiftUI view.
This is my View Controller Representable
final class TrimView: UIViewControllerRepresentable{
let player: AVPlayer
init(player: AVPlayer){
self.player = player
}
func makeUIViewController(context: Context) -> some UIViewController {
return TrimVC(player: player)
}
func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {
}
}
Here's my View Controller
class TrimVC: UIViewController, TrimmerViewDelegate{
func didChangePositionBar(_ playerTime: CMTime) {
//
}
func positionBarStoppedMoving(_ playerTime: CMTime) {
//
}
let player: AVPlayer
init(player: AVPlayer){
self.player = player
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
var trimmerView: TrimmerView = TrimmerView()
override func viewDidLoad() {
trimmerView.delegate = self
view.addSubview(trimmerView)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
loadTrimmer()
}
func loadTrimmer() {
let frame = view.frame.inset(by: view.safeAreaInsets)
let viewWidth = frame.size.width
trimmerView.asset = player.currentItem?.asset
// THIS IS PRINTING MY CURRENT ASSET DIRECTORY.
print("Asset: \(player.currentItem?.asset)")
}
}
And This is How I'm calling it to my SwiftUI View
TrimView(player: player)
.background(Color.red)
.frame( height: UIScreen.screenHeight * 0.05)
But the trimmerView is not showing on my view but only the red square which I put to see if the view is available.

How can I be able to controlling the blur amount in macOS?

I am able to control the blur amount in iOS with help of fractionComplete then I am trying to do same work in macOS native app, I made a multi platform project which run for iOS and native macOS, the codes are in below, the version of iOS works just fine and looking to reach same effect of controlling the amount of blur in macOS, but unable to find a property works as fractionComplete in macOS version.
import SwiftUI
struct ContentView: View {
var body: some View {
ZStack {
Text("Hello, world!")
.font(Font.system(size: 50.0))
.padding()
.background(Color.yellow)
.fixedSize()
Text("Hello, world!")
.font(Font.system(size: 25.0))
.foregroundColor(Color.blue)
.padding(20)
.background(UnicornView())
.border(Color.blue)
}
}
}
#if os(iOS)
struct UnicornView: UIViewControllerRepresentable {
class UnicornControllerModel: UIViewController {
var animator = UIViewPropertyAnimator(duration: 1, curve: .linear)
var visualEffectView = UIVisualEffectView(effect: nil)
override func viewDidLoad() {
super.viewDidLoad()
animator.addAnimations {
self.visualEffectView.effect = UIBlurEffect(style: .systemUltraThinMaterial)
}
animator.fractionComplete = 0.2
view = visualEffectView
}
}
func makeUIViewController(context: UIViewControllerRepresentableContext<UnicornView>) -> UnicornControllerModel {
return UnicornControllerModel()
}
func updateUIViewController(_ uiViewController: UnicornControllerModel, context: UIViewControllerRepresentableContext<UnicornView>) {
}
}
#endif
#if os(macOS)
struct UnicornView: NSViewControllerRepresentable {
class UnicornControllerModel: NSViewController {
var animator = NSAnimation(duration: 1, animationCurve: .linear)
var visualEffectView = NSVisualEffectView()
init() {
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
visualEffectView.material = .popover
visualEffectView.blendingMode = .withinWindow
view = visualEffectView
}
override func loadView() {
view = NSView()
}
}
func makeNSViewController(context: NSViewControllerRepresentableContext<UnicornView>) -> UnicornControllerModel {
return UnicornControllerModel()
}
func updateNSViewController(_ nsViewController: UnicornControllerModel, context: NSViewControllerRepresentableContext<UnicornView>) {
}
}
#endif

The function does not work in UIViewControllerRepresentable

I am trying to implement the unsplash-photopicker-ios component in SwiftUI through the UIViewControllerRepresentable. The view starts successfully, but the unsplashPhotoPicker function does not work, it always returns nil, can someone tell me what the problem is.
import SwiftUI
import UnsplashPhotoPicker
struct UnsplashImagePicker: UIViewControllerRepresentable {
var urlUnsplashImage = [UnsplashPhoto]()
let configuration = UnsplashPhotoPickerConfiguration(
accessKey: "f99d21d6eb682196455dd29b621688aff2d525c7c3a7f95bfcb05d497f38f5dc",
secretKey: "ccff858162e795c062ce13e9d16a2cf607076d0eb185141e35b14f589b1cd713",
allowsMultipleSelection: false)
func makeUIViewController(context: UIViewControllerRepresentableContext<UnsplashImagePicker>) -> UnsplashPhotoPicker {
let unsplashImagePicker = UnsplashPhotoPicker(configuration: configuration)
unsplashImagePicker.delegate = context.coordinator
return unsplashImagePicker
}
func makeCoordinator() -> UnsplashImagePicker.Coordinator {
Coordinator(self)
}
class Coordinator: NSObject, UnsplashPhotoPickerDelegate, UINavigationControllerDelegate {
var parent: UnsplashImagePicker
init(_ parent: UnsplashImagePicker) {
self.parent = parent
}
func unsplashPhotoPicker(_ photoPicker: UnsplashPhotoPicker, didSelectPhotos photos: [UnsplashPhoto]) {
print(photos)
}
func unsplashPhotoPickerDidCancel(_ photoPicker: UnsplashPhotoPicker) {
print("Unsplash photo picker did cancel")
}
}
func updateUIViewController(_ uiViewController: UnsplashPhotoPicker, context: UIViewControllerRepresentableContext<UnsplashImagePicker>) {
}
}
You need to present the Unsplashpicker from a different UIViewcontroller.The Unsplashpicker could not be directly used as UIViewControllerRepresentable.
import SwiftUI
import UIKit
import UnsplashPhotoPicker
struct UnsplashPresenter: UIViewControllerRepresentable {
func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
//
}
func makeUIViewController(context: Context) -> UIViewController {
return UnsplashPickerVC()
}
typealias UIViewControllerType = UIViewController
}
class UnsplashPickerVC: UIViewController, UnsplashPhotoPickerDelegate {
func unsplashPhotoPicker(_ photoPicker: UnsplashPhotoPicker, didSelectPhotos photos: [UnsplashPhoto]) {
print("=============== New Photo Selected =============== \n")
print(photos)
}
func unsplashPhotoPickerDidCancel(_ photoPicker: UnsplashPhotoPicker) {
print("did cancel")
}
var outputImage = UIImage(named: "Instructions.png")
#IBOutlet weak var imageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
let button = UIButton()
button.frame = CGRect(x: (self.view.frame.size.width / 2) - 25, y: (self.view.frame.size.height / 2) - 50, width: 100, height: 50)
button.backgroundColor = UIColor.blue
button.setTitle("Pick Images", for: .normal)
button.addTarget(self, action: #selector(pickImages), for: .touchUpInside)
self.view.addSubview(button)
}
#objc func pickImages(sender: UIBarButtonItem) {
let configuration = UnsplashPhotoPickerConfiguration(
accessKey: "<Your Access Key >",
secretKey: "<Your Secret Key >"
)
let photoPicker = UnsplashPhotoPicker(configuration: configuration)
photoPicker.photoPickerDelegate = self
present(photoPicker, animated: true, completion: nil)
}
}