I'm writing an app in Swift 2.2 targeting iOS 8 and using Eureka Forms. For rows of type TextRow, I would like to have all of the textFields be left aligned starting at a particular distance from the edge of the screen, roughly equal to the width of the longest title. For example:
Prompt1 textField
A longer prompt textField
Prompt2 textField
I have found that I can get left alignment with the following code:
TextRow.defaultCellUpdate = { cell, row in
cell.textField.textAlignment = .Left
}
For setting the left position, I found that I could use textFieldPercentage but it doesn't quite have the behavior I want since the app works in both portrait and landscape. Is there a way to set either the textField or title label width to a fixed value?
Related
I am trying to achieve something with Auto Layout and Stackview. I have a Vertical Stackview with a UIView, UITextView, and UIView in it as shown below.
I have checked out the previous answers here but couldn't find a clean solution to achieve this.
The UITextView is editable and must expand as the user types in it - for this I have disabled the scroll for the UITextView in the IB. I also have a height constraint set on the UITextView set to "Greater than or equal to" 10 and number of lines set to 0, so that the UITextView takes the intrinsic height at run time while the user types. I also want the expansion of the UITextView to continue until the UIStackView bottom edge reaches the Keypad accessory's top edge. I have been somewhat able to achieve the expanding UITextView part with my stack view pinned to the top, trailing, and leading edges of the Superview but I keep getting an error that the stackview needs Y position or height which is understandable but if I give it a fixed height or bottom constraint then the UITextView simply won't expand.
I also am not sure how to stop the expansion of the UITextView when it reaches the top edge of the Keyboard accessory view.
The code that I have so far is
let allowedHeight = self.view.frame.height - (self.keyboardHeight! + self.accessory.frame.height)
Basically find the allowed height in the view frame by subtracting the keyboardheight+Accessory view height. This calculation happens correctly. Next I do this (inside textViewDidChange) in hopes that just enabling/disabling the scroll on the UITextView would work but it clearly doens't since the whole text view then weirdly jumps up and down with every key stroke.
func textViewDidChange(_ textView: UITextView) {
if stackView.frame.height >= allowedHeight{
textView.isScrollEnabled = true
}
if stackView.frame.height < allowedHeight{
textView.isScrollEnabled = false
}
}
What is the best way to achieve what I am looking to do?
Couple notes...
I think you'll be better off setting the Max Height of your UITextView rather than of your UIStackView. The Text View will expand / contract based on its content, so you can set a <= height constraint.
Calculate the "elementsHeight" - the vertical size used by your top and bottom views, plus any spacing - and set the "max text view height" to the view height minus elementsHeight ... and subtract keyboard height when visible.
Update the text view's height constraint constant when "max text view height" changes.
Then set up an Observer for the text view's .contentSize ... and enable / disable scrolling based on .contentSize.height compared to "max text view height".
Needs a bit of hoop-jumping, to make sure you update sizes when subviews are laid-out, and to make sure you don't get in a recursion loop.
This is how I set it up:
The initial height constraint on the text view is <= 40 - but that doesn't really matter, as it will be changed via code every time the views layout differently.
I put up an example on GitHub -- it works, but is really just a starting-point. Take a look if you're interested, and pick it apart. https://github.com/DonMag/ExpandingTextView
I'm trying to create a text view which height follows number of line in it. I've worked on constraint but here I've a curious issue :
At the beginning all is centered as I want
When there is a break, text is not vertically centered anymore and goes in top left corner
When you delete characters and then come back to previous line, the text is yet vertically centered
Here is the code
func textViewDidChange(textView: UITextView) { //Handle the text changes here
if(textView.text != ""){
self.animateSendButton(true)
}else{
self.animateSendButton(false)
}//the textView parameter is the textView where text was changed
heightTextfieldConstraint.constant = self.textField.contentSize.height + 2
textField.contentInset.top = 1
}
I don't understand why there are these 3 different cases, do you have any idea to solve it ?
You can try and add an inset to the top, bot, left and right, that should keep the text centered even after a second line appears.
textView.textContainerInset = UIEdgeInsetsMake(5, 5, 5, 5)
You might be better off keeping the text view itself vertically centered while ensuring that the text view is always sized to fit the content. You can do this with Auto Layout.
Set the text view to be vertically centered in its container and also add a height constraint to the text view with a low constant value (about the height of 1 line of text). Then set the text view's Content Compression Resistant Priority to a value that is higher than the text view's height constraint (see screenshots).
I've done it in "Main.storyboard" of this demo project of mine if you want to see a working example:
https://github.com/patricklynch/Walkthrough
Perhaps you could call view.layoutIfNeeded() after text has been entered.
I have a program with an NSSplitView (containing two panes) filling the window. The left pane is an NSStackView and it contains three NSBoxes. The top two each contain an NSTextField for displaying a string of weather information that can change length every time it is updated by code in the background. I have added the relevant constraints to the top two NSBoxes (and their child NSTextFields) to make them expand or shrink to fit the size of the text fields inside them as the text changes length. The third NSBox fills up the remaining space in the stack view.
The problem is that when the window loads, the NSBoxes (as expected) display the correct size as designed in interface builder to fit the default string in the text fields. However, when the update code kicks in and changes the text of the text fields to the downloaded data, which is longer than the default string, the NSBoxes do not adjust their height to fit the larger text. They only change their height when the splitter of the split view is moved. This is annoying because I have to move the splitter every time the number of lines in the text fields changes. Why is this happening and how can I make the boxes update their height to fit the text when it is longer or shorter than before?
It is much like this question (the only source of information I found on my problem): NSScrollView with auto layout not resizing until first manual window resize, however the solution did not work for me.
Below is an image of the interface (again, the top two boxes should resize to fit their text but this only happens when the splitter is moved). It shows longer text than the boxes can display and they haven't resized:
One option is to create a subclass of NSBox and override the intrinsicContentSize property. In your implementation you'd measure the height of the text contained in the box's text field, take account of any vertical padding that exists between the vertical edges of the text field and the corresponding edges of the box, and return the result of your calculation as the height part of the NSSize return value. Then, any time you want the boxes to resize, you can call invalidateIntrinsicContentSize.
I created a sample app to see if I could get this to work which I've posted here. There are a couple of tricky parts which you should be aware of:
Calculating Text Height
The most involved bit of coding in this approach is calculating the height of the text. Fortunately, Apple has documentation that tells you exactly how to do it; here's how that looks in Swift:
// Properties of your NSBox subclass
var layoutManager: NSLayoutManager {
return textStorage.layoutManagers.first! as! NSLayoutManager
}
var textContainer: NSTextContainer {
return layoutManager.textContainers.first! as! NSTextContainer
}
var typesetter: NSTypesetter {
return layoutManager.typesetter
}
// The textStorage object lies at the heart of the text stack. Create this
// object first, the rest follows.
lazy var textStorage: NSTextStorage! = {
var initialString: String = ""
var ts = NSTextStorage(attributedString: self.textField.attributedStringValue)
var lm = NSLayoutManager()
lm.typesetterBehavior = NSTypesetterBehavior.Behavior_10_2_WithCompatibility
var tc = NSTextContainer()
lm.addTextContainer(tc)
ts.addLayoutManager(lm)
return ts
}()
Setting the hugging-resisting priorities for your NSBox subclass
To get the demo working correctly I found that I needed to set the vertical hugging priority and vertical compression resistance values of the NSBox objects to 900.
I develop test app with swift ,
I need way to arrange first row in first screen to first row in second screen
to make all button across application look similar
my tries :
match X,Y value , width , height
Do you use Auto Layout ?
You can achieve that by
set vertical space between the top edge and your title
set horizontal alignment of title to be center of the view
set vertical space between title and the first item in the row
set leading margin of the first item in the first row
set horizontal alignment of all following items to be center of the first item
I have a UILabel with right-aligned text that may vary from between three to seven characters in length. I am trying to anchor a button to the left of this text so that when the length of the text increases, the button will stay the same distance from the left of the label.
Is there an anchor setting in Interface Builder, or does it require a code-level solution (e.g. setting the button's x position according to the width of the label)?
You need to do this in code. Interface builder is not build for runtime calculations.
To calculate the width of your text you can use NSString's sizeWithFont: method.