Why will my label not change location when trying to add additional text field? - swift

So I have a button on my storyboard. When that button is pressed, I want to move a certain label down a little bit and also add a new text field to the screen. Here is the simplified code:
UIView.animateWithDuration(0.5, animations: { () -> Void in
self.addIngredientLabel.center.y += self.addIngredientLabel.bounds.height
}) { (_) -> Void in
let newIngredientTextField = UITextField(frame: CGRectMake(100, 110, 100, 100))
newIngredientTextField.center.y -= 50
newIngredientTextField.placeholder = "place text here"
newIngredientTextField.contentHorizontalAlignment = .Left
self.view.addSubview(newIngredientTextField)
}
The problem though, is that after the animation is completed, the label jumps back to its original location. It is like the animation is being pre-maturely terminated. The textField gets added and the label moves but it does not stay moved.
I have tried adding the text field at the end of the function instead of in a completion block. No kind of reordering seems to be helping.
I feel like I am not understanding something fundamental to animations. If anyone has any advice I would greatly appreciate it.

Since you're using the storyboard, you are most likely also using auto-layout. The positions of your controls are determined in your visual design (storyboard) and will adjust automatically to orientation changes and adapt to various device screen sizes. This is good but the flip size is that you cannot directly change the positions of your control using their x,y coordinates.
Instead, you can change values in the constraints you defined in the storyboard. for example, if you button has a "Top" distancs constraint with a control above it (or the edge of the view), you can change the constraint's "constant" attribute to indirectly change the position of the control.
In order to manipulate the contraints in your code, you can create IBOutlets for them just as you would do with any control.

Related

How to set first responder for NSTextView in Swift?

Edit: in a macOS project
I have a simple ViewController which I display as popover on a status item menu app.
I change the text of the view text with a NSTableView, depending of which item is clicked. The code I use is similar to this one:
mainTextField.insertText(newStr, replacementRange: theRange)
(I use insertText for the purpose to have the change recorded in undo manager)
Then I highlight the text:
// create the new NSRange
let range = NSRange(location: startRange, length: newStrLength)
// select the range in field
mainTextField.selectedRange = range
All work fine, except that the text is highlighted but with a light grey instead of the usual sky blue, indicating that the control is not the first responder. And when I click on the field the selection disappear.
Actually I would like that the NSTextView becomes first responder so I can directly copy the selected text.
Edit: if I press Tab key on the keyboard I got the textView to become first responder (and the grey selection becomes standard sky blue).
Corrected Answer
In AppKit, you need:
if mainTextField.acceptsFirstResponder {
mainTextField.window?.makeFirstResponder(mainTextField)
}
In this case, it's probably safe to not check acceptsFirstResponder, but it doesn't hurt either.
Original Answer (UIKit)
You need to call mainTextField.becomeFirstResponder().

Can I use auto layout in a storyboard to position my views, then disable the constraints?

I'd like to perform an interactive gesture-based animation with my views that requires moving a view which is centered in the screen to the top-left corner of the screen. I can't seem to interpolate between the position of two different x/y constraints (only changing the constant), so as an alternative, I thought perhaps I could lay out the views in my storyboard, then animate them by changing the frame directly. Is there a good way to do this, or is it a bad idea?
You don't need to remove them! Just deactivate them is enough.
If you have seen the docs, you should know that the constraints property of a UIView returns the constraints that it has as a [NSLayoutConstraint]. You just need to loop through this array and deactivate all the constraints!
for constraint in someView.constraints {
constraint.active = false
}
Or using forEach:
someView.constraints.forEach { $0.active = false }
The advantage of deactivating constraints instead of removing them is that you can activate them again easily when you need it.
If I were you I would choose to animate constraint instead. Even if you cannot change the constraint constant for some reason, you can still remove the previous contraint and add a new one.
To do so you'll need to :
Keep a reference to the constraint you want to change
remove it from the view
set the new constraint and add it to the view
keep the reference of that new constraint
Animate with :
UIView.animateWithDuration(0.5) {
self.view.layoutIfNeeded()
}

NSTextField label: dynamically change content and grow width to fit

If I drag a Label (of class NSTextField) into a view in Interface Builder, and then attempt to set its stringValue dynamically like so:
self.testingLabel.stringValue = "Labels are really really really long"
Then most of the label will be cut off.
How can I make the label grow to fit its content without wrapping/scrolling?
I have tried using this custom class but it doesn't work.
class AutogrowTextField: NSTextField {
override var intrinsicContentSize: NSSize {
get {
var frame = self.frame;
frame.size.width = CGFloat.max;
// Calculate new height within the frame
// with practically infinite height.
let width = self.cell!.cellSizeForBounds(frame).width
Swift.print(width)
NSBeep()
Swift.print(self.frame.width)
return NSMakeSize(width, frame.size.height)
}
}
// you need to invalidate the layout on text change, else it wouldn't grow by changing the text
override func textDidChange(notification: NSNotification) {
super.textDidChange(notification)
self.invalidateIntrinsicContentSize()
}
}
Essentially I just want the default behaviour of an HTML document like this:
<p id="dynamic">Hi</p>
<script>
document.getElementByID("dynamic").innerHtml = "Something really really really long"
</script>
This is extremely painful for me as while I am new to Mac OS X and Cocoa, I am not a 'beginner' programmer.
In case it helps here is the contents of the attributes inspector. (it should just be all default values)
Yes, auto layout is enabled
Are you sure your NIB or storyboard is configured to use auto layout? That would be a checkbox on the File inspector.
The reason I ask is that the Attributes inspector would have a "Preferred Width _ First Runtime Layout Width" checkbox, immediately below the "Uses Single Line Mode" checkbox. It doesn't, which makes me think that auto layout is not enabled.
If you're not using auto layout, then you are responsible for either setting the label's frame size or, more simply, telling it to size itself to fit its content by calling sizeToFit().
If you're using auto layout, then the standard NSTextField already computes its intrinsicContentSize based on its string content. The problem is almost certainly with whatever other constraints you may have set on the view. You need to make sure that the auto layout system is free to adjust the label's width. So, you must not set an explicit width constraint. Or, if you have, say, both a leading and trailing spacing constraint, you need to make sure the label's compression-resistance priority is high enough to push the other related views out or compress them. Etc.

UILabel with auto scroll

How I create UILabel with auto scroll from left to right?
like this http://www.youtube.com/watch?v=moI3ROPBm4Y
Thanks!
I use this code for this (From YouTube):
-(void)time:(NSTimer *)theTimer{
textLabel.center = CGPointMake(textLabel.center.x - 2.2, textLabel.center.y);
if (textLabel.center.x < -(textLabel.bounds.size.width/1.5)){
textLabel.center = CGPointMake(320 + (textLabel.bounds.size.width/1/5), textLabel.center.y);
}
how I to change the move label from left to right?
You can have a looping selector moving the viewarea of the frame slowly sideways. That should do the trick, without blocking the UI.
You would have to create a subclass of UILabel that overrides the drawRect. Then on a timer you would redraw the text with an offset, most easily with a ever increasing translation transform on the graphics context.
You also have to be careful to schedule the timer on the common modes because otherwise the scrolling of the label would stop as soon as the user starts scrolling any scroll view.

How do I adjust a UIButton relative to its current position?

I'm trying to work with a scroll view controller that needs to adjust it's contents based on user interaction -- specifically, by adding a 'done' button while the user is working with a UITextView, then removing it when they are done. The problem is making room for the button in question. What I'd like to do is...
control.layer.position.x-=50;
for every single control that is 'below' the one I'm working with. Unfortunately, that doesn't work. As far as I can tell, I'm going to have to do something more like...
control.layer.position=CGPointMake(newX, newY);
This creates a maintainability nightmare; instead of being able to rearrange buttons inside UIBuilder at will, I'm going to have to change their positions in the code as well. Unfortunately, no matter what variant of the first type of code I use, the result doesn't work; I'm informed that I need an lvalue to the left of the assign or that I'm trying to manipulate incompatible types.
It'll be more verbose than the -= solution, but why don't you just calculate newX and newY based on their old values?
e.g.
CGPoint oldPosition = control.layer.position;
control.layer.position = CGPointMake(oldPosition.x - 50, oldPosition.y);
The button comes with a center property, so:
button.center = CGPointMake(button.center.x - 50, button.center.y);
should do the trick