I have a textView which should always have the same text : "Link öffnen". This is what I got so far:
let linkLabel: UITextView = {
let v = UITextView()
v.backgroundColor = .clear
v.textAlignment = .left
v.isSelectable = false
v.isScrollEnabled = false
let padding = v.textContainer.lineFragmentPadding
v.textContainerInset = UIEdgeInsets(top: 0, left: -padding, bottom: 0, right: -padding)
v.attributedText = NSAttributedString(string: "Link öffnen", attributes:
[.underlineStyle: NSUnderlineStyle.single.rawValue,
NSAttributedString.Key.font: UIFont(name: "AvenirNext-Medium", size: 15)!,
NSAttributedString.Key.foregroundColor: UIColor.darkCustom])
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
It displays the textView exactly how I want it to. What is missing now is the clickable function. This textView is inside a tableViewCell and it should be clickable and each should open a certain url which is saved inside the cell. I know I can use SFSafariViewController for example for that. The problem is to make the textView clickable. What is the easiest/best practice way to do this here?
When you are using NSAttributedString then you can use link attribute. Also in Interface Builder you need to turn on selectable property on your TextView.
For a really clean way to solve this try out ActiveLabel Great for links hashtags and mentions within your textView. Also very easy to customise.
Related
I am trying to use the MDCTextField with MDCTextInputControllerOutlined of MaterialComponents in my swift project but I facing a major challenge with design adjustments in it. It's not allowing me to change even the height of the textfield as well to centre the text input part. Not even the fonts of placeholder is changing.
Tried following all possible options provided in sdk.
tptf.placeholder = "Name"
tptf.placeholderLabel.textColor = UIColor.green
tptf.placeholderLabel.font = UIFont(name: "TimesNewRoman", size: 14)
tptf.textColor = UIColor.green
tptf.font = UIFont(name: "TimesNewRoman", size: 14)
tptf.clearButtonMode = .unlessEditing
tptf.delegate = self
self.textController = MDCTextInputControllerOutlined(textInput: tptf)
self.textController.textInsets(UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10))
self.textController.activeColor = UIColor.green
self.textController.floatingPlaceholderActiveColor = UIColor.green
PFA image
I am doing localization of Arabic in which i have to do text from right to left.
No i dont wont to use POD or Bundle.I am doing at runtime using CountryPicker for selecting Country.
for label i did using below code which is working
self.userNameLbl.textAlignment = .right
and i have used
UITextField.appearance().semanticContentAttribute = .forceRightToLeft
still no use
i am a little confused with your question you want to change the Alignment of textfield or label but for text field i used this and its working you have to create an outlet for your textfild first or define it in a variable
NameTextField.textAlignment = .right
go to storyboard -> select your textfield -> attributes inspector -> view -> semantic set to forceRightToLeft.
You can do:
label.textAlignment = NSTextAlignment.center;
Or, for shorthand:
label.textAlignment = .center;
Swift 3
label.textAlignment = .center
or
You can set the placeholder text using an attributed string. Pass the color you want with the attributes:
var myTextField = UITextField(frame: CGRect(x: 0, y: 0, width: 200, height: 30))
myTextField.backgroundColor = .blue
myTextField.attributedPlaceholder = NSAttributedString(string: "placeholder text",
attributes: [NSForegroundColorAttributeName: UIColor.yellow])
For Swift 3+ use following:
myTextField.attributedPlaceholder = NSAttributedString(string: "placeholder text",
attributes: [NSAttributedStringKey.foregroundColor: UIColor.white])
For Swift 4.2 use following:
myTextField.attributedPlaceholder = NSAttributedString(string: "placeholder text",
attributes: [NSAttributedString.Key.foregroundColor: UIColor.white])
I have a label that uses a NSMutableAttributedString to write out the text as:
What I want to do is lower the asterisk's top padding so that it's midY is even with the word Cuisine like below:
How can I add padding using a NSMutableAttributedString?
I know I can create a separate label with the asterisk alone and use anchors w/ a constant to center it but I want to see how this is possible using a NSMutableAttributedString
let cuisineLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
let attributedText = NSMutableAttributedString(string: "Cuisine ", attributes: [NSAttributedStringKey.font: UIFont.systemFont(ofSize: 17), NSAttributedStringKey.foregroundColor: UIColor.lightGray])
attributedText.append(NSAttributedString(string: "*", attributes: [NSAttributedStringKey.font: UIFont.systemFont(ofSize: 24), NSAttributedStringKey.foregroundColor: UIColor.red]))
label.attributedText = attributedText
return label
}()
The baselineOffset attribute key is used for this purpose.
let cuisine = NSMutableAttributedString(string: "Cuisine")
let asterisk = NSAttributedString(string: "*", attributes: [.baselineOffset: -3])
cuisine.append(asterisk)
Obviously, you will have to calculate the offset using the font size of the rest of the text. This is why I believe that using a full width asterisk (*) is easier.
Result with full width asterisk (you might want its font size to be a proportion of the font size of the rest of the string):
As Code Different points out, you can do this with baselineOffset attribute. A value of -8 should work for your case:
import UIKit
import PlaygroundSupport
class MyViewController : UIViewController {
override func loadView() {
let view = UIView()
view.backgroundColor = .white
self.view = view
let cuisineLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.frame = CGRect(x: 150, y: 200, width: 200, height: 20)
let attributedText = NSMutableAttributedString(string: "Cuisine ", attributes: [
NSAttributedStringKey.font: UIFont.systemFont(ofSize: 17),
NSAttributedStringKey.foregroundColor: UIColor.lightGray])
attributedText.append(NSAttributedString(string: "*", attributes: [
NSAttributedStringKey.font: UIFont.systemFont(ofSize: 24),
NSAttributedStringKey.baselineOffset: -8,
NSAttributedStringKey.foregroundColor: UIColor.red]))
label.attributedText = attributedText
return label
}()
view.addSubview(cuisineLabel)
}
}
// Present the view controller in the Live View window
PlaygroundPage.current.liveView = MyViewController()
If you're struggling with line height offsets being messed up because of the new baseline and you're using a multi-line label, try playing with lineHeightMultiple:
let lineStyle = NSParagraphStyle()
lineStyle.lineHeightMultiple = 0.8
...
NSAttributedStringKey.paragraphStyle = style
If not (and you're using multiple labels stacked on top of one another) then you probably just need to adjust the frame of each label in the series to compensate.
I'm trying to create an attributed string but the underline covers my text instead of appearing behind it:
Is there a way to fix this? I'm using the following code:
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = 10.0
let attributes = [NSForegroundColorAttributeName: UIColor.white,
NSUnderlineStyleAttributeName: NSUnderlineStyle.styleThick.rawValue,
NSUnderlineColorAttributeName: UIColor.red,
NSParagraphStyleAttributeName: paragraphStyle]
let attributedString = NSAttributedString(string: "Story", attributes: attributes)
Thanks!
EDIT:
To give more context:
I'm displaying the attributed string on a UILabel placed in a .xib file:
view.textLabel.attributedText = attributedString
The label has the following font:
System Bold 32.0
I'm running the code on iPhone 6 - iOS 10.3 simulator.
EDIT 2:
I should have mentioned that the label may, at some point, contain more than one line of text. That's why the numberOfLines is set to 0.
EDIT 3:
If anybody encounters this problem -- it seems that there is a lot of difference in how underline is drawn on iOS 9 vs 10 as well as UILabel vs UITextView. I've ended up having to draw the underline myself by subclassing NSLayoutManager.
Yes, there is such problem as you have described. It shows up when you use multiline UILabel, so not only setting numberOfLines to 0, but type more than 1 line in it.
Example
let selectedStringAttributes: [String: Any]
= [NSFontAttributeName: UIFont.boldSystemFont(ofSize: 28),
NSForegroundColorAttributeName: UIColor.green,
NSUnderlineStyleAttributeName: NSUnderlineStyle.styleSingle.rawValue,
NSUnderlineColorAttributeName: UIColor.green]
let label = UILabel(frame: CGRect(x: 100, y: 100, width: 500, height: 100))
label.numberOfLines = 0
label.attributedText = NSAttributedString(string: "String to test underline", attributes: selectedStringAttributes)
And everything will look pretty good.
But if you want to use such text:
label.attributedText = NSAttributedString(string: "String to\ntest underline", attributes: selectedStringAttributes)
or label's width is too short, than:
So the reason for such behaviour is of course bug in NSAttributedString. As it mentioned in radar there is a workaround
You should add this attribute to your NSAttributedString
NSBaselineOffsetAttributeName: 0
And magic will happen.
Instead of using NSAttributedString you can draw border below the label with x space using this.
let space:CGFloat = 10
let border = CALayer()
border.backgroundColor = UIColor.red.cgColor
border.frame = CGRect(x: 0, y: (label?.frame.size.height)! + space, width: (label?.frame.size.width)!, height: 1)
label?.layer.addSublayer(border)
On my machine, showing your attributed string in a black-backgrounded UILabel, it makes a quite nice-looking display:
The red thick underline is nicely separated from the text, and is interrupted to allow the descender of the "y" to pass through it.
NOTE You cannot combine the font of the UILabel (set in Interface Builder) with its attributedText. You must set the entire label's text formatting in the attributedText. So, my code looks like this:
let attributes : [String:Any] = [NSForegroundColorAttributeName: UIColor.white,
NSUnderlineStyleAttributeName: NSUnderlineStyle.styleThick.rawValue,
NSUnderlineColorAttributeName: UIColor.red,
NSFontAttributeName: UIFont.boldSystemFont(ofSize: 32)]
let attributedString = NSAttributedString(string: "Story", attributes: attributes)
lab.backgroundColor = .black
lab.attributedText = attributedString
(You will notice that I removed your stipulation of the paragraph line spacing; there is only one line, so this stipulation adds nothing. However, I get the same result even if I restore it.)
So this is my solution to this issue.
I think it is "cleaner" and easier.
Post me if you dont understand :)
class BottomLineTextField: UITextField {
var bottomBorder = UIView()
override func awakeFromNib() {
super.awakeFromNib()
setBottomBorder()
}
func setBottomBorder() {
self.translatesAutoresizingMaskIntoConstraints = false
bottomBorder = UIView.init(frame: CGRect(x: 0, y: 0, width: 0, height: 0))
hasError = false
bottomBorder.translatesAutoresizingMaskIntoConstraints = false
addSubview(bottomBorder)
bottomBorder.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
bottomBorder.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
bottomBorder.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
bottomBorder.heightAnchor.constraint(equalToConstant: 1).isActive = true // Set underline height
}
}
Here's a gif of the behavior:
I want the text to stay in place, without going up and down as demonstrated.
Here's the actual UITextView:
let chatTextField: UITextView = {
let chatText = UITextView()
chatText.font = UIFont(name: "Helvetica", size: 16)
chatText.backgroundColor = UIColor(r: 248, g: 248, b: 248)
chatText.translatesAutoresizingMaskIntoConstraints = false
return chatText
}()
My text view is inside a container so here is how I constrained it:
self.chatTextField.heightAnchor.constraintEqualToAnchor(container.heightAnchor).active = true
self.chatTextField.widthAnchor.constraintEqualToConstant(212).active = true
self.chatTextField.centerYAnchor.constraintEqualToAnchor(container.centerYAnchor).active = true
self.chatTextField.centerXAnchor.constraintEqualToAnchor(container.centerXAnchor).active = true
I'm not sure whether this is a bug or a constraint problem, but I have an idea that it could be the text leading, or other font attributes.