find application position relative to screen point macOS swift - swift

Trying to find applications current position in X Y coordinate. For example: An application has starting point(X,Y) + Hight, Width. How to find its starting point as CGPoint or X Y onscreen values?
Current trying with view.bounds :
class ViewController: NSViewController {
var testPoint = CGPoint.zero;
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
//testPoint = view.bounds.height //rect
//if possible following:
//testPoint = CGPoint(x: view.window?.frame.origin.x , y: view.window?.frame.origin.y)
print(testPoint)
}
}

In viewWillAppear or viewDidAppear ask the window of the view for the origin of its frame
override func viewWillAppear() {
super.viewWillAppear()
print(view.window?.frame.origin)
}

You should use NSWindow API, particularly NSWindow.frameRect.

Related

How to move the cursor to the center of an NSView?

On macOS, I have an application that should move the cursor to the center of the NSView when the window is loaded.
class ViewController: NSViewController {
override func viewDidLayout() {
super.viewDidLayout()
let view = super.view
let point = NSPoint(x: view.frame.midX, y:view.frame.midY)
let pointInWindow = view.convert(point, to: nil)
let pointOnScreen = view.window?.convertToScreen(NSRect(origin: pointInWindow, size: .zero)).origin ?? .zero
CGWarpMouseCursorPosition(NSPoint(x:pointOnScreen.x, y:pointOnScreen.y))
}
}
(The code was taken from: Mac OS X: Convert between NSView coordinates and global screen coordinates)
But it seems to be placing the cursor above the window instead of inside it— x-position looks correct but the y-position is off. Thank you for any help.
I found a usage example on GitHub by searching for CGWarpMousePosition:
https://github.com/chockenberry/Notchmeister/blob/9e9308f0803a4e0faf27790c02081689545a989d/Notchmeister/Notchmeister/PortalEffect.swift#L162-L171
This ended up working. The y-position needed to be subtracted from the bottom screen coordinate:
class ViewController: NSViewController {
override func viewDidLayout() {
super.viewDidLayout()
let view = super.view
let window = view.window
let screen = window!.screen
let viewPoint = NSPoint(x: view.frame.midX, y:view.frame.midY)
let windowPoint = view.convert(viewPoint, to: nil)
let screenPoint = window!.convertPoint(toScreen: windowPoint)
let globalPoint = CGPoint(
x: screen!.frame.origin.x + screenPoint.x,
y: screen!.frame.origin.y + screen!.frame.height - screenPoint.y
)
CGWarpMouseCursorPosition(globalPoint)
}
}

How can I get the safeAreaLayout info for my GameScene?

Am trying to develop a game and am not using storyboard at all. Am building it all via code.
I know how to get the safeAreaLayout info, thanks to this forum) for a UIViewController. My thought was I'd be able to attach my GameScene: SKScene to that and go from there. Found out the hard way that's not the case. I have searched so hard and have tried all the example I found find for the likes of
override func viewDidLayoutSubviews()
and
func viewDidAppear(_ animated: Bool)
And every method I've tried returns either sets of 0's, or the full height of the screen 812
I would like to think that there is a proper method for getting the proper safeArea info to the initial GameScene of my app. Is there?
Hei,
You get the 812 pixels height because that's the scene height. In SpriteKit the games are full screen, you don't need to worry about the safe areas.
From GameViewController present the scene you want to display, in my case MainScene.
if let view = self.view as! SKView?
{
// create a new scene of type Main Scene
let scene = MainScene()
// set the new (MainScene) settings
scene.scaleMode = .resizeFill
scene.anchorPoint = CGPoint(x: 0.5, y: 0.5)
// present the scene
view.presentScene(scene)
}
If you want to know the size of the scene in MainScene, just get the values like this.
class MainScene: SKScene
{
override func didMove(to view: SKView)
{
let screenHeight = self.scene!.size.height
let screenWidth = self.scene!.size.width
}
}

In Swift’s UIKit Dynamics, how can I define a circle boundary to contain a UIView?

I have researched a LOT, but the only examples I can find anywhere are for the purpose of defining the bounds of a UIView so that they collide/bounce off each other on the OUTSIDE of the objects.
Example: A ball hits another ball and they bounce away from each other.
But what I want to do is create a circular view to CONTAIN other UIViews, such that the containing boundary is a circle, not the default square. Is there a way to achieve this?
Yes, that's totally possible. The key to achieving collision within a circle is to
Set the boundary for the collision behaviour to be a circle path (custom UIBezierPath) and
Set the animator’s referenceView to be the circle view.
Output:
Storyboard setup:
Below is the code of the view controller for the above Storyboard. The magic happens in the simulateGravityAndCollision method:
Full Xcode project
class ViewController: UIViewController {
#IBOutlet weak var redCircle: UIView!
#IBOutlet weak var whiteSquare: UIView!
var animator:UIDynamicAnimator!
override func viewDidLoad() {
super.viewDidLoad()
self.redCircle.setCornerRadius(self.redCircle.bounds.width / 2)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.5) { [unowned self] in
self.simulateGravityAndCollision()
}
}
func simulateGravityAndCollision() {
//The dynamic animation happens only within the reference view, i.e., our red circle view
animator = UIDynamicAnimator.init(referenceView: self.redCircle)
//Only the inside white square will be affected by gravity
let gravityBehaviour = UIGravityBehavior.init(items: [self.whiteSquare])
//We also apply collision only to the white square
let collisionBehaviour = UICollisionBehavior.init(items:[self.whiteSquare])
//This is where we create the circle boundary from the redCircle view's bounds
collisionBehaviour.addBoundary(withIdentifier: "CircleBoundary" as NSCopying, for: UIBezierPath.init(ovalIn: self.redCircle.bounds))
animator.addBehavior(gravityBehaviour)
animator.addBehavior(collisionBehaviour)
}
}
extension UIView {
open override func awakeFromNib() {
super.awakeFromNib()
self.layer.allowsEdgeAntialiasing = true
}
func setCornerRadius(_ amount:CGFloat) {
self.layer.cornerRadius = amount
self.layer.masksToBounds = true
self.clipsToBounds = true
}
}

Layer transform matrix (CATransform3D, etc.) but with IBDesignable?

This class will put perspective on an upright image.
It works perfectly BUT does not work live in Storyboard with IBDesignable. Which is very sad.
Is it possible to use CATransform3D and the like for live display on Storyboard with IBDesignable??
// Twist.swift .. twist on Y, perspective from the left
import UIKit
#IBDesignable
class Twist:UIViewController
{
#IBInspectable var perspective:CGFloat = 0.5 // -1 to 1
#IBOutlet var im:UIView! // the image you want to twist on y
override func prepareForInterfaceBuilder()
{ twist(perspective) }
override func viewDidAppear(animated: Bool)
{
twist(perspective)
super.viewWillAppear(animated)
}
func twist(f:CGFloat) // -1 to 1
{
// hinge around left edge
im.layer.anchorPoint = CGPointMake(0, 0.5)
im.center = CGPointMake(0.0, self.view.bounds.size.height/2.0)
// base transform, twist on y
var t:CATransform3D = CATransform3DIdentity
t.m34 = -1/500
im.layer.transform = t
im.layer.transform = CATransform3DRotate(t, f*CGFloat(M_PI_2), 0, 1, 0);
}
}
I already had an issue with live preview transformations. It seems it just doesn't work, maybe not implemented yet.
There's a thing, only UIViews can be #IBDesignable. Here you can see that both of #UIDesignable classes can't be rendered. I created a Class TwistableView for the example.

iPhone - Get Position of UIView within entire UIWindow

The position of a UIView can obviously be determined by view.center or view.frame etc. but this only returns the position of the UIView in relation to it's immediate superview.
I need to determine the position of the UIView in the entire 320x480 co-ordinate system. For example, if the UIView is in a UITableViewCell it's position within the window could change dramatically irregardless of the superview.
Any ideas if and how this is possible?
That's an easy one:
[aView convertPoint:localPosition toView:nil];
... converts a point in local coordinate space to window coordinates. You can use this method to calculate a view's origin in window space like this:
[aView.superview convertPoint:aView.frame.origin toView:nil];
2014 Edit: Looking at the popularity of Matt__C's comment it seems reasonable to point out that the coordinates...
don't change when rotating the device.
always have their origin in the top left corner of the unrotated screen.
are window coordinates: The coordinate system ist defined by the bounds of the window. The screen's and device coordinate systems are different and should not be mixed up with window coordinates.
Swift 5+:
let globalPoint = aView.superview?.convert(aView.frame.origin, to: nil)
Swift 3, with extension:
extension UIView{
var globalPoint :CGPoint? {
return self.superview?.convert(self.frame.origin, to: nil)
}
var globalFrame :CGRect? {
return self.superview?.convert(self.frame, to: nil)
}
}
In Swift:
let globalPoint = aView.superview?.convertPoint(aView.frame.origin, toView: nil)
Here is a combination of the answer by #Mohsenasm and a comment from #Ghigo adopted to Swift
extension UIView {
var globalFrame: CGRect? {
let rootView = UIApplication.shared.keyWindow?.rootViewController?.view
return self.superview?.convert(self.frame, to: rootView)
}
}
For me this code worked best:
private func getCoordinate(_ view: UIView) -> CGPoint {
var x = view.frame.origin.x
var y = view.frame.origin.y
var oldView = view
while let superView = oldView.superview {
x += superView.frame.origin.x
y += superView.frame.origin.y
if superView.next is UIViewController {
break //superView is the rootView of a UIViewController
}
oldView = superView
}
return CGPoint(x: x, y: y)
}
Works well for me :)
extension UIView {
var globalFrame: CGRect {
return convert(bounds, to: window)
}
}
this worked for me
view.layoutIfNeeded() // this might be necessary depending on when you need to get the frame
guard let keyWindow = UIApplication.shared.windows.first(where: { $0.isKeyWindow }) else { return }
let frame = yourView.convert(yourView.bounds, to: keyWindow)
print("frame: ", frame)