How to add UIView on top of SKView? - swift

I wanted to add a Custom NSView on top of and SKView. However, it is never showing up. Have no clue what is happening...
class GameScene: SKScene {
override func didMoveToView(view: SKView) {
//Trying to add Custom View
let smallView = NSView(frame: NSRect(origin:CGPoint(x: 100,y: 100), size: CGSize(width: 200, height: 200)))
let layer = CALayer()
layer.backgroundColor = CGColorCreateGenericRGB(1.0, 0.0, 0.0, 0.4)
smallView.layer = layer
view.superview!.addSubview(smallView)
}
}
Could anyone who could give me an insight into what is happening here? I even tried adding some NSLabels to the MainStory board. Nothing happens.
I wanted to draw some thing with Coregrapghics and Show on top of the SKScene.But, I can't move forward.
https://github.com/cocoBavan/NSViewInSpriteKit

Try to add UIView from your ViewController, instead of adding it from SKScene.
In your VC add function (for example), create UIView, and then just add it as a subview of a view, like so:
let myView = UIView(frame: CGRect(x: 0, y:0, width: 100, height: 100))
self.view.addSubview(myView)
It will add a new view above existing view, so your GameScene would be below new UIView.

Related

UIView does not change colors after setting backgroundColor programmatically

I'm creating a subview to add onto an existing view. I'm trying to assign the background color to this subview to red programmatically but displays as the defaulted color still.
let toggleView = UIView(frame: CGRect(x: 0, y: 0, width: screenWidth, height: screenHeight))
toggleView.backgroundColor = UIColor.red
As from the above code snippet it looks like that you are creating a view but not adding it as a subview to the parent view. It will be best if you can provide full function so that we can look into the actual cause.
You have created the toggleView with a red background but you have not added it to the main view, this is what you should do:
let screenWidth = view.frame.size.width
let screenHeight = view.frame.size.height
let toggleView = UIView(frame: CGRect(x: 0, y: 0, width: screenWidth, height: screenHeight))
toggleView.backgroundColor = UIColor.red
view.addSubview(toggleView)

UIView incorrect frame on #3x devices

I have a really weird bug on #3x devices where a UIView is visually incorrectly sized.
I insist on the visually word because when I print out the frame of that particular view, everything is correct.
On #2x devices, everything looks fine.
My view hierarchy is really simple. I have a view (view B) inside another one (view A).
View B is centered in its superview (view A).
Really simple right?
Frame of view B should be:
CGRect(x: 8.5, y: 15.5, width: 19.0, height: 5.0)
If we scale it with a factor of 3 (to obtain its real dimensions on #3x devices), we should have a rectangle with the following frame:
CGRect(x: 25.5, y: 46.5, width: 57.0, height: 15.0)
When testing on a #3x device, visually, the origin.x of the view is 26px (instead of 25.5), and its width is 56px (instead of 57px).
Here is the code:
class ViewController: UIViewController {
private static let centeredViewSize = CGSize(width: 36, height: 36)
private let centeredView = UIView(frame: .zero)
private let rectangleView = UIView(frame: .zero)
// MARK: - View Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
self.rectangleView.clipsToBounds = true
self.rectangleView.backgroundColor = UIColor.purple
self.centeredView.backgroundColor = UIColor.red
self.centeredView.addSubview(self.rectangleView)
self.view.addSubview(self.centeredView)
}
// MARK: - Layout
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
self.centeredView.frame.size = ViewController.centeredViewSize
self.centeredView.center = self.view.center
let rectangleViewSize = CGSize(width: 19, height: 5)
let rectangleViewHorizontalOrigin = self.centeredView.bounds.midX - (rectangleViewSize.width / 2)
let rectangleViewVerticalOrigin = self.centeredView.bounds.midY - (rectangleViewSize.height / 2)
let rectangleViewOrigin = CGPoint(x: rectangleViewHorizontalOrigin, y: rectangleViewVerticalOrigin)
self.rectangleView.frame = CGRect(origin: rectangleViewOrigin, size: rectangleViewSize)
}
}
This whole issue seems to come from the horizontal origin.
If I round it like this:
let rectangleViewHorizontalOrigin = (self.centeredView.bounds.midX - (rectangleViewSize.width / 2)).rounded()
The issue is gone. But that's not a solution. I want that view to be perfectly centered in its superview.
How can I fix this?
I created a demo project so you can try it out.
I run your code. Your frames are perfectly centred at any device.
Only two things I've changed.
1st in:
override func viewDidLoad() {
super.viewDidLoad()
// Change the order of adding subviews
self.view.addSubview(self.centeredView)
self.centeredView.addSubview(self.rectangleView)
}
2nd:
I use override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
}
instead override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
}
If something will go wrong, please edit your question with new screenshots.
Here is my console output.

How to add custom View according to UIButton location in swift?

I am trying to add custom View on button action. custom View is add successfully, but it's not show properly
#IBAction func sideButtonAction(_ sender: UIButton) {
sideSubView = SideView(frame: CGRect(x: sender.frame.origin.x ,y: sender.frame.origin.y + 40,width: 200,height: 200))
self.view.addSubview(sideSubView)
}
In UIView class
func xibSetup() {
view = loadViewFromNib()
view.frame = bounds
view.autoresizingMask = [UIViewAutoresizing.flexibleWidth, UIViewAutoresizing.flexibleHeight]
addSubview(view)
}
override init(frame: CGRect) {
super.init(frame: frame)
xibSetup()
}
In screenshot, blue View is custom view, it's not show properly, I have set height and width is 200.
Thanks
Please use this,
sideSubView = SideView(frame: CGRect(x: sender.frame.origin.x - 200 ,y: sender.frame.origin.y + 40,width: 200,height: 200))
The screenshot shows the code working as it should. Your view starts underneath the button and moves right. I'm assuming that you wanted the whole 200 width and height visible under the button. If that is the case, then you need to change this line
sideSubView = SideView(frame: CGRect(x: sender.frame.origin.x ,y: sender.frame.origin.y + 40,width: 200,height: 200))
to
sideSubView = SideView(frame: CGRect(x: sender.frame.origin.x + sender.frame.size.width - 200 , y: sender.frame.origin.y + sender.frame.size.height, width: 200, height: 200))
Its look like your button on Navigationbar and you are adding blue view on controller's view. Both view are different so point coordinate will be different for both.
You need to pass relative coordinate to your blue view's frame.

Using an UIView as a Mask in another UIView on Swift

I am developing an App on xCode with Swift. My screen has an Image of an animal (outlet "backImage"), over this image I have a view (outlet "coverView"), color black, which covers all the screen. So so far you can't see the animal image, because the "coverView" is in front of it. Then I have another view (outlet "maskView") which is smaller and it's over the big view "coverView". What I want is to use this "maskView" as mask and therefor see the "backImage" through it, like a window.
Is there anyone out there able to figure this out?
Here is my screen, I want to see the woman character behind the big gray view through the smaller white view:
You can set the alpha property from your mask view and add in front of the other view, for instance:
let maskView = UIView()
maskView.backgroundColor = UIColor(white: 0, alpha: 0.5) //you can modify this to whatever you need
maskView.frame = CGRect(x: 0, y: 0, width: imageView.frame.width, height: imageView.frame.height)
yourView.addSubview(maskView)
EDIT: Now that you edited your question with an image, now I see what you need, so here is how you can accomplish that.
func setMask(with hole: CGRect, in view: UIView){
// Create a mutable path and add a rectangle that will be h
let mutablePath = CGMutablePath()
mutablePath.addRect(view.bounds)
mutablePath.addRect(hole)
// Create a shape layer and cut out the intersection
let mask = CAShapeLayer()
mask.path = mutablePath
mask.fillRule = kCAFillRuleEvenOdd
// Add the mask to the view
view.layer.mask = mask
}
With this function, all you need is to have a view and create a shape that it's going to be a hole in that view, for instance:
// Create the view (you can also use a view created in the storyboard)
let newView = UIView(frame: CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height))
newView.backgroundColor = UIColor(white: 0, alpha: 1)
// You can play with these values and find one that fills your need
let rectangularHole = CGRect(x: view.bounds.width*0.3, y: view.bounds.height*0.3, width: view.bounds.width*0.5, height: view.bounds.height*0.5)
// Set the mask in the created view
setMask(with: rectangularHole, in: newView)
Thank you, #Alexandre Lara! You did it!
Here goes the solution:
#IBOutlet weak var windowView: UIView!
#IBOutlet weak var bigCoverView: UIView!
func setMask(with hole: CGRect, in view: UIView){
// Create a mutable path and add a rectangle that will be h
let mutablePath = CGMutablePath()
mutablePath.addRect(view.bounds)
mutablePath.addRect(hole)
// Create a shape layer and cut out the intersection
let mask = CAShapeLayer()
mask.path = mutablePath
mask.fillRule = kCAFillRuleEvenOdd
// Add the mask to the view
view.layer.mask = mask
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let rectangularHole = windowView.frame.integral
// Set the mask in the created view
setMask(with: rectangularHole, in: bigCoverView!)
}

UIView Orientation change in Swift

I'm developing an app to display a binary tree.
Each node will be displayed as a subview programatically generated from the ViewController - I run the following from viewDidLayoutSubviews().
let theView = BinaryTreeView(frame: CGRect(x: 0, y: 50, width: width, height: 100))
// let theView = BinaryTreeView(s: "I'm testing")
theView.backgroundColor = .white
theView.addGestureRecognizer(UIPinchGestureRecognizer(target:theView, action:#selector(BinaryTreeView.changeScale(recognizer:))))
self.view.addSubview(theView)
theView.eyesOpen = false
let secondView = BinaryTreeView(frame: CGRect(x: width/2, y: 150, width: width/2, height: 100))
// let theView = BinaryTreeView(s: "I'm testing")
secondView.backgroundColor = .white
secondView.addGestureRecognizer(UIPinchGestureRecognizer(target:secondView, action:#selector(BinaryTreeView.changeScale(recognizer:))))
self.view.addSubview(secondView)
let thirdView = BinaryTreeView(frame: CGRect(x: (width/2)+width/4, y: 250, width: width/4, height: 100))
// let theView = BinaryTreeView(s: "I'm testing")
thirdView.backgroundColor = .white
thirdView.addGestureRecognizer(UIPinchGestureRecognizer(target:thirdView, action:#selector(BinaryTreeView.changeScale(recognizer:))))
self.view.addSubview(thirdView)
The issue is that on orientation change the views repeat each other (above there are three nodes, on orientation change 4 might display.
I looked through Stack and Within my subclassed UIView I added:
self.contentMode = UIViewContentMode.redraw
Within the programatic Subview but the same happens.
Don't worry - I'm going to generate my nodes in a loop later (I'm trying to understand how layout works). Incidentally I found the same happened using a UICollectionView so I seem to be doing something fundamentally wrong.
Change the "target:" to the controller (to self) for all three. Your controller will respond to gestures, not the views themselves. The target will be the same in all three cases.
secondView.addGestureRecognizer(UIPinchGestureRecognizer(target:secondView, action:#selector(BinaryTreeView.changeScale)))
self.view.addSubview(secondView)
becomes
secondView.addGestureRecognizer(UIPinchGestureRecognizer(target:self, action:#selector(BinaryTreeView.changeScale)))
self.view.addSubview(secondView)