If sizeToFit is not called, the label is invisible. Why is this?
class RootViewController: UIViewController {
override func loadView() {
let v = UIView()
v.backgroundColor = .green
self.view = v
let label = UILabel()
v.addSubview(label)
label.text = "Hello, World!"
label.autoresizingMask = [
.flexibleTopMargin,
.flexibleLeftMargin,
.flexibleBottomMargin,
.flexibleRightMargin]
label.sizeToFit()
label.center = CGPoint(v.bounds.midX, v.bounds.midY)
label.frame = label.frame.integral
}
}
UIView() is the same thing as UIView(frame: CGRect.zero). So the default size of your label is zero. You're using manual layout, which means that the system won't automatically resize your label. So whatever size you assign to it is the size it will have. Your code isn't assigning a size anywhere except for the call to sizeToFit(). So if you don't call sizeToFit(), your label will retain the zero size that you created it with. sizeToFit() changes its size to fit its contents, so you can actually see it.
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'm building an app which takes Strings from the user and saves them using NSUserDefaults. Then I recover them and paste them on top of an image (a form or questionnaire) I'm currently saving the image with .write to file but when I check the image I've saved, I discovered that it doesn't save the full image and as a consequence the positions for the fields aren't right. I need to be able to send this image and later on print on a sheet of A4 paper.
The simulator :
http://postimg.org/image/5szujdgw3/
The saved image:
http://postimg.org/image/uq6mea6vb/
Why isn't it saving the full image?
Here's my code :
import UIKit
class StartMorgagesSave: UIViewController {
let rectangle = UIBezierPath(rect: CGRectMake(80, 166, 80, 05)) //x , y , width , height 240, 165
let shapeLayer = CAShapeLayer()
//let label = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
shapeLayer.path = rectangle.CGPath
shapeLayer.strokeColor = UIColor.blueColor().CGColor
shapeLayer.fillColor = UIColor.whiteColor().CGColor
view.layer.addSublayer(shapeLayer)
view.pdfData.writeToURL(NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).first!.URLByAppendingPathComponent("test53.pdf"), atomically: true) // what it is saved as
view.pdfData.writeToFile("fdfdlo", atomically: false)
print(NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).first!.path!)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
extension UIView {
var pdfData: NSData {
let result = NSMutableData()
UIGraphicsBeginPDFContextToData(result, frame, nil)
guard let context = UIGraphicsGetCurrentContext() else { return result }
UIGraphicsBeginPDFPage()
layer.renderInContext(context)
UIGraphicsEndPDFContext()
return result
}
}
Niall
In GameViewController.swift, I find this line
if let scene = GameScene(fileNamed:"GameScene") {
and I always thought that if I wanted to load something other than GameScene.swift, I could just change "GameScene" to "LandingPage" and everything would work just dandy. However, as I recently figured out, "GameScene" here actually refers to GameScene.sks and not the swift file.
I'm looking to make a game with a number of levels, each written in its own swift file. Where do I go to/ how do I move from, say, level1.swift to level2.swift?
if you are in one scene for example level selection scene, lets say LevelSelectionScene.swift, you can go to another scene via SKView's -presentScene:transition: method.
class LevelSelectionScene: SKScene {
override func didMoveToView(view: SKView) { /* ... */}
func selectLevel(level: Int) {
let fadeTransition = SKTransition.fadeWithDuration(0.3)
if let selectedLevel = createLevelSceneWithLevel(level) {
self.view?.presentScene(selectedLevel, transition: fadeTransition)
}
}
// Not a good idea if you progressively adding new levels,
// it's totally depend on how you gonna organize your levels.
// Since its level input is not arbitrary, the output of this
// rarely nil, if it does, it must be the developer mistake.
func createLevelSceneWithLevel(level: Int) -> SKScene? {
let levelScene: SKScene?
switch level {
case 1: levelScene = Level1()
case 2: levelScene = Level2()
default: levelScene = nil
}
return levelScene
}
}
As somebody above has said the line "fileNamed: "GameScene" "
if let scene = GameScene(fileNamed:"GameScene") {
references the GameScene.sks file, which is the equivalent of storyboard for games.
If you create a new SKScene class and try to load it this way, either from another SKScene or the gameViewController it will not work because it cannot find the corresponding sks file.
I am not 100% sure how to create a new sks file because I dont use it in my games.
If you just want to load a new scene you created you would use this code in your gameViewController
let skView = self.view as! SKView
let scene = NewScene(size: skView.bounds.size)
skView.ignoresSiblingOrder = true
skView.multipleTouchEnabled = true
scene.scaleMode = .AspectFill
skView.presentScene(scene)
If you want to load another scene from a SKScene class its basically the same code
let newScene = NewScene(size: self.size) //size of current scene
let transition = SKTransition.doorsCloseHorizontalWithDuration(0.5) // use transition between 2 SKScenes
let skView = self.view as! SKView
skView.ignoresSiblingOrder = true
skView.multipleTouchEnabled = true
newScene.scaleMode = .AspectFill
skView.presentScene(newScene, transition: transition)
or a slightly cleaner version
let newScene = NewScene(size: self.size)
let transition = SKTransition.doorsCloseHorizontalWithDuration(0.5)
newScene.scaleMode = SKSceneScaleMode.AspectFill
self.view?.presentScene(newScene, transition: transition)
You can specify a custom class name for each scene file in the Custom Class Inspector. That's the right most tab in the Utilities pane.
The custom class (must be a subclass of SKScene) is loaded when the sks file is loaded.
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)
}
Is the Swift compiler smart enough to optimize away multiple repeated method calls that return the same object? Or, should I first assign the return value to a constant and use that instead?
For Example:
The Table View Programming Guide for iOS says that when adding subviews to a UITableViewCell's contentView, avoid making them transparent. "Transparent subviews affect scrolling performance because of the increased compositing cost."
So, I often do the following:
class EmployeeCell: UITableViewCell {
var nameLabel: UILabel
var titleLabel: UILabel
// ...
init(style: UITableViewCellStyle, reuseIdentifier: String) {
nameLabel = UILabel(frame: CGRectZero)
nameLabel.backgroundColor = UIColor.whiteColor()
titleLabel = UILabel(frame: CGRectZero)
titleLabel.backgroundColor = UIColor.whiteColor()
// ...
super.init(style: style, reuseIdentifier: reuseIdentifier)
}
}
Would it be better, however, to first (inside init) do let whiteColor = UIColor.whiteColor() and then replace each call to UIColor.whiteColor() with whiteColor?
Or, perhaps in this example, I should define a function (inside init) that creates a UILabel with a frame of CGRectZero and a backgroundColor of UIColor.whiteColor() and just call that to initialize each label property. If I do that, will Swift know to optimize (perhaps inline) that function?
use swiftc -help There is a lot of options, use -emit-xxxx to see the resulting job in details