I need, on button click, to replace a NSWindow.contentViewController with new ViewController. To do this I wrote following code:
let g = GameViewController()
if self.window!.styleMask & NSFullScreenWindowMask != NSFullScreenWindowMask {
let ws = NSScreen.mainScreen()?.frame.size
let width : CGFloat = g.view.frame.width
let height : CGFloat = g.view.frame.height
let frame = NSRect(origin: NSMakePoint(((ws?.width)!-width)/2, ((ws?.height)!-height)/2), size: CGSize(width:width, height:height))
self.window?.setFrame(frame, display: true, animate: true)
}
self.window?.contentViewController = g
When NSWindow is not in FullScreen mode, this code works good. While, when NSWindow is in FullScreen mode, the GameViewController is set with his default size and not change is size until occurs a resize event.
How can I instantiate NSViewController in order to occupy all window space?
If you are using storyboard:
let storyboard = NSStoryboard(name: "Main", bundle: nil)
if let homeViewController = (storyboard.instantiateControllerWithIdentifier("HomeViewController") as? NSViewController){
let windowController = NSWindowController(window: Constants.appDelegate!.window)
windowController.contentViewController = homeViewController
windowController.showWindow(Constants.appDelegate!.window)
}
Hope this will help you. Happy Codding
Related
I've got this extension for my collection view that makes horizontal scroll but I want to change it on vertical scroll??
extension viewRe : UIScrollViewDelegate
{
func scrollViewWillEndDragging(scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>)
{
let layout = self.recipesCollView?.collectionViewLayout as! UICollectionViewFlowLayout
let cellWidthIncludingSpacing = layout.itemSize.width + layout.minimumLineSpacing
var offset = targetContentOffset.memory
let index = (offset.x + scrollView.contentInset.left) / cellWidthIncludingSpacing
let roundedIndex = round(index)
offset = CGPoint(x: roundedIndex * cellWidthIncludingSpacing - scrollView.contentInset.left, y: -scrollView.contentInset.top)
targetContentOffset.memory = offset
}
}
With this extension I'm trying to make the cells to stick to the TOP of the view even when he scrolls because the paging is enabled. So whenever the user scrolls i would like the cell to stick to the top and so on when the user scrolls.
#donnyWals is right. If you are using a UICollectionView just change its UICollectionViewFlowLayout
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = . Horizontal
let collectionView = UICollectionView(frame: frame, collectionViewLayout: layout)
or if you have an existent UICollectionView
if let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
layout.scrollDirection = .Horizontal
}
Follow the official API:
UICollectionView
UICollectionViewFlowLayout
I have set up my UIImageView using the below setup. I am trying to draw on the view but can not get anything to appear. I am new to Xcode and want my view to automatically change depending on what the screen size is. When I have used the storyboard I could not figure out how to get the view to change with the screen size and/or rotation. As a result I figured it would be easier to make that happen in the ViewController.swift file. When the program wasn't working I tried to see if the view was appearing on the screen. When I made one of the views red, I still could not see anything on the screen. I am very confused. I am open to any feedback. I appreciate you taking time to read this and am looking forward to assistance.
Thanks,
T
import UIKit
import CoreGraphics
class ViewController: UIViewController {
var ResultImageView = UIImageView ( frame: UIScreen.mainScreen().bounds)
var DrawingImageView = UIImageView ( frame: UIScreen.mainScreen().bounds)
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
ResultImageView.userInteractionEnabled = true
ResultImageView.backgroundColor = UIColor.redColor()
DrawingImageView.userInteractionEnabled = true
}
I think the problem is you have to create the imageview in viewDidAppear if you're setting the screen size, because the screen size hasn't been set and orientated where you're setting it. Try the below and hope this issue gets resolved soon :)
var ResultImageView = UIImageView()
var DrawingImageView = UIImageView()
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(true)
ResultImageView = UIImageView (frame: self.view.frame)
DrawingImageView = UIImageView (frame: self.view.frame)
ResultImageView.userInteractionEnabled = true
self.view.addSubview(ResultImageView)
self.view.addSubview(DrawingImageView)
ResultImageView.backgroundColor = UIColor.redColor()
DrawingImageView.userInteractionEnabled = true
}
I am making a MenuBar app for which I am using NSPopOver. The problem is that NSPopover uses NSViewController as a contentViewController, whose size gets fixed. My requirement is to make the size of NSViewController flexible i.e just like NSWindowController(set the minimum size and maximum depends upon the total screen size). In simple words how to change the size of NSViewController(NSPopOver) when user drags it. I am new to OS X programming.
I finally got it working by using Mouse Events. Just need to monitor the
override func mouseDown(theEvent: NSEvent) {}
override func mouseDragged(theEvent: NSEvent) {}
events, and reset the content size of the popOver.
Hope this would be helpful to someone one day.
EDIT
override func mouseDragged(theEvent: NSEvent) {
var currentLocation = NSEvent.mouseLocation()
println("Dragged at : \(currentLocation)")
var newOrigin = currentLocation
let screenFrame = NSScreen.mainScreen()?.frame
var windowFrame = self.view.window?.frame
newOrigin.x = screenFrame!.size.width - currentLocation.x
newOrigin.y = screenFrame!.size.height - currentLocation.y
println("the New Origin Points : \(newOrigin)")
// Don't let window get dragged up under the menu bar
if newOrigin.x < 450 {
newOrigin.x = 450
}
if newOrigin.y < 650 {
newOrigin.y = 650
}
println("the New Origin Points : \(newOrigin)")
let appDelegate : AppDelegate = NSApplication.sharedApplication().delegate as! AppDelegate
appDelegate.popover.contentSize = NSSize(width: newOrigin.x, height: newOrigin.y)
}
This is how i tracked the mouse event. On Mouse drag just calculated the current position and the new position(To the point where user has dragged), then checked if the point is smaller then my default size for the Popover i.e. (450, 650) in this case. Once the point has been calculated, just set the size of the popover.
This is just a proposed way. There must be something better then this, but for time being this is what I did.
I had the same need, and thanks to the helpful comments above, I created PopoverResize. This allows a user to resize a menubar NSPopover. It includes cursors for the edges as well.
https://github.com/dboydor/PopoverResize
Here is an answer that handles only vertical, but not horizontal resizing of an NSPopover.
override func mouseDragged(with theEvent: NSEvent) {
let currentLocation = NSEvent.mouseLocation()
let screenFrame = NSScreen.main()?.frame
var newY = screenFrame!.size.height - currentLocation.y
if newY < MIN_HEIGHT {
newY = MIN_HEIGHT
}
if newY > MAX_HEIGHT {
newY = MAX_HEIGHT
}
let appDelegate : AppDelegate = NSApplication.shared().delegate as! AppDelegate
appDelegate.popover.contentSize = NSSize(width: FIXED_WIDTH, height: newY)
}
I am working on Xcode 6.1.1 on OSX 10.10. I am trying out storyboards for Mac apps. I have a NSTabViewController using the new NSTabViewControllerTabStyleToolbar tabStyle and it is set as the default view controller for the window controller. How do I make my window resize according to the current selected view controller?
Is it possible to do entirely in Interface Builder?
Here is what my storyboard looks like:
The auto layout answer is half of it. You need to set the preferredContentSize in your ViewController for each tab to the fitting size (if you wanted the tab to size to the smallest size satisfying all constraints).
override func viewWillAppear() {
super.viewWillAppear()
preferredContentSize = view.fittingSize
}
If your constraints are causing an issue below try first with a fixed size, the example below sets this in the tab item's view controller's viewWillAppear function (Swift used here, but the Objective-C version works just as well).
override func viewWillAppear() {
super.viewWillAppear()
preferredContentSize = NSSize(width: 400, height: 280)
}
If that works, fiddle with your constraints to figure out what's going on
This solution for 'toolbar style' tab view controllers does animate and supports the nice crossfade effect. In the storyboard designer, add 'TabViewController' in the custom class name field of the NSTabViewController. Don't forget to assign a title to each viewController, this is used as a key value.
import Cocoa
class TabViewController: NSTabViewController {
private lazy var tabViewSizes: [String : NSSize] = [:]
override func viewDidLoad() {
// Add size of first tab to tabViewSizes
if let viewController = self.tabViewItems.first?.viewController, let title = viewController.title {
tabViewSizes[title] = viewController.view.frame.size
}
super.viewDidLoad()
}
override func transition(from fromViewController: NSViewController, to toViewController: NSViewController, options: NSViewController.TransitionOptions, completionHandler completion: (() -> Void)?) {
NSAnimationContext.runAnimationGroup({ context in
context.duration = 0.5
self.updateWindowFrameAnimated(viewController: toViewController)
super.transition(from: fromViewController, to: toViewController, options: [.crossfade, .allowUserInteraction], completionHandler: completion)
}, completionHandler: nil)
}
func updateWindowFrameAnimated(viewController: NSViewController) {
guard let title = viewController.title, let window = view.window else {
return
}
let contentSize: NSSize
if tabViewSizes.keys.contains(title) {
contentSize = tabViewSizes[title]!
}
else {
contentSize = viewController.view.frame.size
tabViewSizes[title] = contentSize
}
let newWindowSize = window.frameRect(forContentRect: NSRect(origin: NSPoint.zero, size: contentSize)).size
var frame = window.frame
frame.origin.y += frame.height
frame.origin.y -= newWindowSize.height
frame.size = newWindowSize
window.animator().setFrame(frame, display: false)
}
}
The window containing a toolbar style tab view controller does resize without any code if you have auto layout constraints in your storyboard tab views (macOS 11.1, Xcode 12.3). I haven't tried other style tab view controllers.
If you want to resize with animation as in Finder, it is sufficient to add one override in your tab view controller. It will resize the window with system-calculated resize animation time and will hide the tab view during resize animation:
class PreferencesTabViewController: NSTabViewController {
override func transition(from fromViewController: NSViewController, to toViewController: NSViewController, options: NSViewController.TransitionOptions = [], completionHandler completion: (() -> Void)? = nil) {
guard let window = view.window else {
super.transition(from: fromViewController, to: toViewController, options: options, completionHandler: completion)
return
}
let fromSize = window.frame.size
let toSize = window.frameRect(forContentRect: toViewController.view.frame).size
let widthDelta = toSize.width - fromSize.width
let heightDelta = toSize.height - fromSize.height
var toOrigin = window.frame.origin
toOrigin.x += widthDelta / 2
toOrigin.y -= heightDelta
let toFrame = NSRect(origin: toOrigin, size: toSize)
NSAnimationContext.runAnimationGroup { context in
context.duration = window.animationResizeTime(toFrame)
view.isHidden = true
window.animator().setFrame(toFrame, display: false)
super.transition(from: fromViewController, to: toViewController, options: options, completionHandler: completion)
} completionHandler: { [weak self] in
self?.view.isHidden = false
}
}
}
Please adjust closure syntax if you are using Swift versions older than 5.3.
Use autolayout. Set explicit size constraints on you views. Or once you have entered the UI into each tab view item's view set up the internal constraints such that they force view to be the size you want.
I have an NSTextView inside an NSView (which is being used by a NSPopover, don't know if that is relevant) that I'm trying to resize automatically and programmatically (cf caption).
I have been struggling with a lot of stuff, namely :
Looking at NSLayoutManager and usedRectForTextContainer that give me aberrant size values
(usedRectForTextContainer : {{0, 0}, {0.001, 28}})
Modifying NSScrollView frame, [NSScrollView contentView], [NSScrollView documentView]
Getting rid of AutoLayout
I reached the point where I can resize my scollview and my Popover, but I can't get the actual height of the text inside the NSTextView.
Any kind of help would be appreciated.
-(void)resize
{
//Get clipView and scrollView
NSClipView* clip = [popoverTextView superview];
NSScrollView* scroll = [clip superview];
//First, have an extra long contentSize and ScrollView to test everything else
[popover setContentSize:NSMakeSize([popover contentSize].width, 200)];
[scroll setFrame:(NSRect){
[scroll frame].origin.x,[scroll frame].origin.y,
[scroll frame].size.width,155
}];
NSLayoutManager* layout = [popoverTextView layoutManager];
NSTextContainer* container = [popoverTextView textContainer];
NSRect myRect = [layout usedRectForTextContainer:container]; //Broken
//Now what ?
}
I still have no idea why I can't use [layout usedRectForTextContainer:container], but I managed to get the NSTextView's height by using :
-(void)resize
{
//Get glyph range for boundingRectForGlyphRange:
NSRange range = [[myTextView layoutManager] glyphRangeForTextContainer:container];
//Finally get the height
float textViewHeight = [[myTextView layoutManager] boundingRectForGlyphRange:range
inTextContainer:container].size.height;
}
Here is some functional code that I have tested myself for swift. usedRectForTextContainer is not broken it just is set lazily. To set it i call glyphrangefortextcontainer
I found the answer here: http://stpeterandpaul.ca/tiger/documentation/Cocoa/Conceptual/TextLayout/Tasks/StringHeight.html
let textStorage = NSTextStorage(string: newValue as! String)
let textContainer = NSTextContainer(size: NSSize(width: view!.Text.frame.width, height:CGFloat.max))
let layoutManager = NSLayoutManager()
layoutManager.addTextContainer(textContainer)
textStorage.addLayoutManager(layoutManager)
textContainer.lineFragmentPadding = 0.0
textContainer.lineBreakMode = NSLineBreakMode.ByWordWrapping
textStorage.font = NSFont(name: "Times-Roman", size: 12)
layoutManager.glyphRangeForTextContainer(textContainer)
let rect = layoutManager.usedRectForTextContainer(textContainer)
Swift.print(rect)
The documentation also suggest that is the the case: