I'm using in my app the TextFields component of Google's Material Components library.
As you can see in the following screenshot, the text input is way too close of the leadingView. How can I add some margin between them?
Here's the code I'm using to create this text field:
emailTextField.translatesAutoresizingMaskIntoConstraints = false
emailTextField.delegate = self
emailTextField.leadingView = UIImageView(image: UIImage(named: "MailIcon"))
emailTextField.leadingViewMode = .always
emailTextFieldController = MDCTextInputControllerUnderline(textInput: emailTextField)
emailTextFieldController?.placeholderText = "Email"
The underline style text field is not a recommended design anymore. And the original design didn't specify a padding constant for the leading view. Consider changing to the filled controller which has been shown to perform much better in user research studies.
If you have to stick with underline, getting your desired layout is pretty easy.
Make sure you're on the latest version of MaterialComponents. This could mean you need to run pod update MaterialComponents if you're using CocoaPods.
Subclass MDCTextInputControllerUnderline.
Override the property leadingViewTrailingPaddingConstant and return whatever padding you'd like. In Objective-C, this would look like:
- (CGFloat)leadingViewTrailingPaddingConstant {
return 16.f;
}
Set your text fields to use the new class you've made.
Incidentally, we just pushed the ability to change the clear button's color easily. You can set it to match the underline and text by setting the property textInputClearButtonTintColor.
Related
What I want to implement
I am looking for a way to display a title label and a detail text label in a NSMenuItem.
Preferably it would look something like this:
The Title Label is left aligned with all the other NSMenuItem's
titles
The Detail Text Label is right-aligned
The Detail Text Label has a different text color than the title
Selection/Submenus etc. work as expected
What have I tried already
By reading the documentation I found the following possible implementations:
Create a custom NSView and set NSMenuItem.view
Use a default NSMenuItem and use a NSAttributedString
First I tried to use a custom NSView. However I could not get the NSMenuItem to size correctly in order to display all the available text. I guess some autoresizing masks do not work correctly but I am not sure. Also this way I would need to re-implement selection/arrow for the submenu, ...
Then I started to experiment with NSAttributedString. I calculate the title with the most characters and then pad the string with title += string.padding(toLength: maxTitleLength, withPad: " ", startingAt: 0). The NSAttributedString colors the title and the detail label differently. However this does not seem to work since the detail labels are not correctly aligned although the title is padded to the same length. I guess this makes sense since characters have different widths?
TL;DR - Question
So is there any other way to implement the desired design which I did not find? Do you have any advice for me on how to implement this?
Nevermind I found the answer myself. Actually it works for me now by using the view property of the NSMenuItem to set a custom view. This answer lead me to the right direction: Highlighting a NSMenuItem with a custom view?.
I'm trying to create an expandable label that looks like the one in the picture:
I have two problems:
How do I make the label truncate the tail such that it leaves enough place for the More button/clickable text?
How do I place the More text?
Maybe, I am going about it the wrong way? Instead of playing with the number of lines, should I maybe try to calculate how much text goes into one and a half line and present it only, and then when clicking More I present the whole text?
Would appreciate any advice, thanks!
You can use this library to achieve your expected output.
https://github.com/apploft/ExpandableLabel
Specify the number of lines you want to display default.
expandableLabel.numberOfLines = 2
Set true if the label should be collapsed or false for expanded.
expandableLabel.collapsed = true
collapsedAttributedLink
Set the link name that is shown when collapsed.
expandableLabel.collapsedAttributedLink = NSAttributedString(string: "More")
expandedAttributedLink
Set the link name that is shown when expanded. It is optional and can be nil.
expandableLabel.expandedAttributedLink = NSAttributedString(string: "Less")
I've got a UIButton, it's a simple segue to another page.
I've set Title to attributed and then selected word wrap. This works fine, the second word wraps down to the next line.
However, it is all left justified. When I select "Align Centre" (using the buttons just under the "Title", the word wrap no longer works and simply runs .... so you can't see it all. (e.g. "next pa" instead of "next page")
Am I missing something here? It seems like such a trivial thing to do! There's an old answer here can't get word wrap to work on UIButton but it's both old and uses code - surely you don't need code to centre the button text if you want to word wrap it to 2 lines!?
I've set Title to attributed and then selected word wrap. This works fine, the second word wraps down to the next line. However, it is all left justified.
Once you've decided to use an attributed string, you must do everything with the attributed string. So give your attributed string a paragraph style that centers the text.
let para = NSMutableParagraphStyle()
para.alignment = .center
para.lineBreakMode = .byWordWrapping
let s = NSAttributedString(
string: "Hello World", attributes: [.paragraphStyle : para])
self.button.setAttributedTitle(s, for: .normal)
You will also need to set the button's title label to allow multiple lines.
self.button.titleLabel?.numberOfLines = 0
Result:
surely you don't need code to centre the button text if you want to word wrap it to 2 lines!?
Not to center it, no; you can set the centering in the storyboard. So you could eliminate the first batch of code and configure it in the storyboard. But you must use code to turn the title label into a multiline label:
self.button.titleLabel?.numberOfLines = 0
There is no way to do that in the storyboard, because you have no access to the title label there.
I've just been playing round with this and I've found it works if you set it to 'character wrap' rather than 'word wrap' once you've selected centre alignment.
If anyone has a better solution please add it, as I guess this might have issues if you slightly change the width etc when using auto layout for different screen sizes etc if you want it to adapt its width so this might not be the best solution but it does work
I have a UILabel and whenever I set its outlet the padding I created in Storyboards for it under attributed text disappears like it was never there. The text the stays stuck on the left side. How can I fix this issue?
#IBOutlet weak var mycoollabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
mycoollabel.text = "Wow"
}
Note: OP clarified in a comment that they are setting their padding using attributed text in Interface Builder.
The problem here is a confusion between text and attributed text, or, because these are code, it's text and attributedText.
On iOS, lots of things have a text property, and it's just a simple string of text that gets displayed somewhere without any sort of formatting. Usually the formatting is attached to the object that is showing the text, e.g. a label has a text colour and alignment properties that make its text look however you want.
On iOS, most (all?) of those things also have an attributedText property, which is a very different beast. Attributed text contains a string but also specific formatting instructions required to display that string – text attributes, hence the name.
So, OP is creating an attributed text configuration in their storyboard, then, in code, modifying the text property. This will overwrite their formatted string with a plain string, losing its layout configuration.
If you're looking to create an attributed string with a first line indent, you should try this:
let ps = NSMutableParagraphStyle();
ps.firstLineHeadIndent = 50
let attrs = [NSParagraphStyleAttributeName: ps]
let attributedString = NSAttributedString(string: "Hello, world!", attributes: attrs)
label.attributedText = attributedString
Note that there are a few different options available to you here, so you might need to find the right type of indent for your precise needs. If you right-click on NSMutableParagraphStyle and choose Jump To Definition you'll see all the options.
That's because a UILabel can have either plain text or attributed text. You set attributed text in the storyboard, and add some formatting (padding, etc.). Then, in code, you override that text (and all its formatting) with plain text.
If you want to keep the formatting, you need to set the label's attributedText property. And add all the necessary formatting to the NSAttributedString object you create for that.
I may have found a bug in iOS and I'm not sure how to overcome it. I am losing my textView style as soon as the database populates it with content.
That is what happens:
In my storyboard I have the following textView
As soon as I populate the textView manually or from my object as per below it loses its style.
if let object = currentObject.objectForKey("postText") as? String {
postTextView.text = "the text field has some text added"
}
On simulator, showing the style is lost.
Also, other situation:
I may lose the style as well if I uncheck the editable box as per the image bellow.
Here's an older answer which hopefully answers your question and solves your problem. Is seems indeed to be a bug. https://stackoverflow.com/a/19115950/543224
Did you set the attributes on the text view itself (i.e. the text view text is "plain", and not "attributed")? Or did you use attributed text?
If the latter, it's quite normal that if you replace the attributed text with plain text with no attributes, it reverts to the attributes of the text view itself.
Make sure the type is set to "plain", and that you set the attributes on the text view itself, not on the text inside it. Or use the attributedText and not the text property of your text view, with appropriate attributes.
I guess that you update UI on from background. If you want update UI you have to update in main queue. If you don't do it, some strange issue will come. So you can change your code to:
dispatch_async(dispatch_get_main_queue()) { () -> Void in
if let object = currentObject.objectForKey("postText") as? String {
postTextView.text = "the text field has some text added"
}
}