I'm have an application like a webchat, and i'm trying to format a text to a html text. For example:
Text:
"<b>Lorem ipsum dolor sit amet elit.\n\n Quisque maximus venenatis.</b>"
So to convert it to an html text, I'm using the ruby simple_format from ActionView::Helpers::TextHelper, but it's not keeping the bold formatation like following:
"<p><b>Lorem ipsum dolor sit amet elit.</p>\n\n <p>Quisque maximus venenatis.</b></p>"
when actually it should be shown as follows
"<p><b>Lorem ipsum dolor sit amet elit.</b></p>\n\n <p><b>Quisque maximus venenatis.</b></p>"
Any suggestions?
If you apply this code:
- html = "<b>Lorem ipsum dolor sit amet elit.\n\n Quisque maximus venenatis.</b>"
= simple_format(simple)
it will produce such HTML:
<p><b>Lorem ipsum dolor sit amet elit.</p>
<p> Quisque maximus venenatis.</b></p>
And it keeps bold format for both lines in modern browsers even though it is invalid HTML code. However, it may not work correctly in some browsers
Another option -- use CSS
.wrap-lines {
white-space: pre-line;
}
And then apply this rule to some container
- html = "<b>Lorem ipsum dolor sit amet elit.\n\n Quisque maximus venenatis.</b>"
.wrap-lines
== html
white-space: pre-line; breaks lines at newline characters, at <br> (white space are collapsed)
I have a goal to implement local search inside Core Data entities. Technical part of finding occurrences is pretty clear. But I'm not sure how to display it correctly. Case: we have string in our entity
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
and user want to find entries with word adipiscing. We have UILabel with width i.e. 320dp and numberOfLines = 1. If we will display whole string without correct trimming it would be
Lorem ipsum dolor sit amet, consec...
which just useless for user. I want label to look like
...consectetur adipiscing elit, se...
So in other words I want search occurrence to be "focused" somewhere about middle of UILabel. How can I trim the string where occurrence has happened depending on label font and width?
It's not complete, but should bring you on track:
let wholeString = "This is a very long Hello world in a simple String"
let someSearch = wholeString.range(of: "Hello")!
// Make sure to call dropLast() twice to remove the space before 'Hello'
var stringBeforeSomeSearch = wholeString[wholeString.startIndex...someSearch.lowerBound].dropLast().dropLast()
// This is everything before the searched string
let prefixRange = stringBeforeSomeSearch.range(of: " ", options: .backwards)!.upperBound...someSearch.lowerBound
print(wholeString[prefixRange]) // prints "long H"
print(wholeString[prefixRange.lowerBound...someSearch.upperBound]) // prints "long Hello "
If you need more explanation, I'll be back later on.
Here's a solution that uses UITextView instead of UILabel, to achieve the desired search visualisation.
The concept is to use a UITextView with userInteraction and vertical scroll disabled and horizontal scroll enabled.
Use the textView method of scroll to range to show the desired word.
let textView = UITextView()
textView.isUserInteractionEnabled = false
textView.contentSize = CGSize(width: textWidth, height: textView.frame.size.width)
scrollTo(text: "swift")
func scrollTo(text: String) {
if let string = textView.text,
let range = string.localizedStandardRange(of: text) {
let viewRange = NSRange(range, in: string)
textView.scrollRangeToVisible(viewRange)
}
}
textWidth is the width of your total text. Follow this link for help.
Even After setting the .lineLimit(nil) the text doesn't get wrapped.
var body: some View {
VStack(alignment: .center) {
Text("SwiftUI is a modern way to declare user interfaces for any Apple platform. ")
.font(.title)
.color(.red)
.lineLimit(nil)
Text("Create beautiful, dynamic apps faster than ever before.")
.font(.system(size: 20))
.lineLimit(nil)
}.padding(EdgeInsets(top: 0, leading: 10, bottom: 0, trailing: 10))
}
After spending a lot of time with an error like this, I can't be 100% certain that this is a lineLimit issue. As of writing this post, the solution I found with more complex views is the following snippet of code to prevent wrapping:
.fixedSize(horizontal: false, vertical: true)
This should prevent the interpreter from collapsing text vertically.
The full solution as of Xcode 11.3 / Swift 5.1 is found across multiple answers here.
The explanation for why this is happening is found in Matteo Pacini's answer: using the predefined .font(.title), .font(.headline), etc. seems to bring the behavior that these Text views will size themselves to always ellipsize rather than wrap. However, simply switching to .body doesn't seem like the best work around.
The best workaround is found in Sharpienero's answer: add .fixedSize(horizontal: false, vertical: true) to your Text view. This tells the Text view to NOT do its custom re-sizing horizontal logic of NOT ellipsizing which causes it to follow the standard rules that we're all use to.
Thanks to both of them!
Try changing the second Text's lineLimit to a number instead of nil:
VStack(alignment: .leading) {
Text("SwiftUI is a modern way to declare user interfaces for any Apple platform. ")
.font(.title)
.color(.red)
.lineLimit(nil)
Text("Create beautiful, dynamic apps faster than ever before.")
.font(.system(size: 20))
.lineLimit(2)
}.padding(EdgeInsets(top: 0, leading: 10, bottom: 0, trailing: 10))
Result:
It looks like the font holds line wrapping attributes.
If you change it to body, then it wraps correctly!
For my problem, I had a setup like this:
public var body: some View {
Form {
Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit.")
.font(.title)
Spacer()
.fixedSize()
Text("""
Integer ut orci odio. Proin cursus ut elit eget rutrum. Nunc ante sem, euismod sed purus sed, tempus elementum elit. Phasellus lobortis at arcu quis porta. Cras accumsan leo eu tempus molestie. Suspendisse vulputate diam ipsum, et tristique lorem porta et. Pellentesque sodales est id arcu luctus venenatis.
Vestibulum non magna lorem. In tincidunt aliquet nunc, sit amet pharetra neque hendrerit id.
Cras sed!
""")
NativeButton("OK", keyEquivalent: .return) { self.screen = .game }
}
.frame(maxWidth: 480)
.fixedSize()
.padding()
}
For some reason, all I had to do was add minWidth: 480, idealWidth: 480 to the frame and everything rendered correctly. I didn't expect this because I already applied .fixedSize(), so I figured one of these three should've been enough.
public var body: some View {
Form {
Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit.")
.font(.title)
Spacer()
.fixedSize()
Text("""
Integer ut orci odio. Proin cursus ut elit eget rutrum. Nunc ante sem, euismod sed purus sed, tempus elementum elit. Phasellus lobortis at arcu quis porta. Cras accumsan leo eu tempus molestie. Suspendisse vulputate diam ipsum, et tristique lorem porta et. Pellentesque sodales est id arcu luctus venenatis.
Vestibulum non magna lorem. In tincidunt aliquet nunc, sit amet pharetra neque hendrerit id.
Cras sed!
""")
NativeButton("OK", keyEquivalent: .return) { self.screen = .game }
}
.frame(minWidth: 480, idealWidth: 480, maxWidth: 480)
.fixedSize()
.padding()
}
SwiftUI
.lineLimit(nil) VS .lineLimit(any number)
VStack(alignment: .leading, spacing: 16.0) {
// Sets the maximum number of lines that text can occupy in the view.
Text("SwiftUI is a user interface toolkit that lets us design apps in a declarative way. ")
.font(.title)
.lineLimit(3)
// But if you don't know about the the text size then Sets nil in the lineLimit.
Text("SwiftUI is a user interface toolkit that lets us design apps in a declarative way. That's a fancy way of saying that we tell SwiftUI how we want our UI to look and work, and it figures out how to make that happen as the user interacts with it.... ")
.font(.body)
.lineLimit(nil)
}.padding(EdgeInsets(top: 0, leading: 8, bottom: 0, trailing: 8))
I had a situation involving a UIViewRepresentable wrapped UITextField which was presented as:
VStack {
Text("Long enough to wrap....")
Spacer().frame(height: 40)
CustomTextField()
}
The Text stopped wrapping when I added the CustomTextField. Nothing I did to the Text helped. If I removed the Spacer() it wrapped just fine!!
I wound up removing the Spacer and adding a bottom padding to the Text. As far as I can tell, my CustomTextField is just fine and I cannot see why it would affect the SwiftUI layout algorithms.
The only answer that kinda worked for me was applying .fixedSize(horizontal: false, vertical: true) on the Text.
I say "kinda" because, by using .fixedSize, SwiftUI will completely ignore the size given by the parent and overflow it. If the parent has a background, the layout is ruined. If the parent has a sibling node, the text is rendered on top of it.
I really believe Apple should give us the option to have the ideal size of a Text be its multiline version instead of the one-line counterpart.
While this doesn't happen, I'm using the following monstrosity, but it works:
struct AdaptiveText: View {
#State private var height: CGFloat?
var text: String
private func updateHeight(height: CGFloat) -> some View {
DispatchQueue.main.async {
self.height = height
}
return Color.clear
}
var body: some View {
ZStack {
Text(text)
.fixedSize(horizontal: false, vertical: true)
.background() {
GeometryReader { geo in
updateHeight(height: geo.size.height)
}
}
.opacity(0)
Text(text)
}.frame(width: nil, height: height)
}
}
I just added
.padding()
to my Text instance and it worked
I'm trying to align a UILabel inside a UICollectionViewCell like Whatsapp, Telegram, etc... Last line aligned to the left of the hour label, the others that ends on top of it.
I've tried adding at the end of the text some transparent characters and it worked until I tried some emojis; extra characters changed emoji code.
This is a sample of the code I'm using with TTTAttributedLabel for links detection.
let text = "Lorem ipsum dolor sit amet, enim apeirian his cu. Saperet interesset ex cum, ut per altera quodsi causae."
let endTransparentText = "aaaaa"
let showingText = text + endTransparentText
cell.lblMessage.setText(showingText) { (attributedString) -> NSMutableAttributedString? in
attributedString?.addAttribute(kCTForegroundColorAttributeName as String, value: UIColor.clear, range: NSMakeRange((showingText.characters.count-endTransparentText.characters.count), endTransparentText.characters.count))
return attributedString
}
Someone had to deal with this problem?
I am facing a strange problem with boundingRectWithSize and a multiline UILabel using the Swift language. I am currently working in a Xcode playground so I can see the result and updates of UI in real-time.
What I am trying to do is to calculate a given UILabel height dynamically based on it's content, I know this has been discusses over an over in other StackOverflow questions but this seems too strange to me.
The multi line label has this text in NSAttributedString form. Text is a simple Lorem ipsum placeholder:
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris. Maecenas congue ligula ac quam viverra nec consectetur ante hendrerit. Donec et mollis dolor.
Here's the code for the UILabel:
let valueString = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris. Maecenas congue ligula ac quam viverra nec consectetur ante hendrerit. Donec et mollis dolor."
var dataValue = UILabel()
dataValue.numberOfLines = 0
dataValue.lineBreakMode = .ByWordWrapping
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = .Justified
paragraphStyle.lineBreakMode = .ByWordWrapping
paragraphStyle.firstLineHeadIndent = 0.1
let attributedText = NSAttributedString.init(
string:valueString,
attributes:[NSParagraphStyleAttributeName:paragraphStyle, NSFontAttributeName:dataValue.font])
let textString = dataValue.text! as NSString
dataValue.attributedText = attributedText
dataValue.frame = CGRect(
x:CGFloat(kMargin),
y:dataType.frame.origin.y + CGFloat(kLabelHeight),
width:CGFloat((maxLabelWidth) - kMargin * 2),
height:textString.boundingRectWithSize(
CGSizeMake(CGFloat(kMaxWidth), CGFloat.max),
options:[.UsesLineFragmentOrigin, .UsesFontLeading],
attributes:[NSParagraphStyleAttributeName:paragraphStyle, NSFontAttributeName:dataValue.font],
context:nil).size.height)
The problem is that the UILabel only shows 3 lines of text, stopping at the mauris word of the text and truncating the last ones as you can see from the Playground preview feature:
One obvious problem is that valueString and textString are two different strings. So there is no reason to believe that string you're putting into the label is the same as the string you're measuring.
You use valueString here:
let attributedText = NSAttributedString.init(
string:valueString, // ...
But you use dataString here:
height:textString.boundingRectWithSize(
Also, do not try to combine label attributes with attributed text. This can cause all kinds of problems. The dataValue label should have no font. You should not be fetching this font value. Do everything using the attributed string. You should not be constructing two different style dictionaries; you should be assigning and measuring the exact same attributed string.
To put it another way, do not measure valueString or textString at all, with or without attributes. Measure attributedString.
Finally, make sure that the label has the same width as you are using during measurement. You are saying
CGSizeMake(CGFloat(kMaxWidth) // ...
but there is no evidence that the label itself is going to have this width.