Created
February 27, 2021 07:54
-
-
Save prafullakumar/80a33e8c512d3eac5e6b1b72d2f5d330 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import SwiftUI | |
struct ExpandableText: View { | |
@State private var expanded: Bool = false | |
@State private var truncated: Bool = false | |
@State private var shrinkText: String | |
private var text: String | |
let font: UIFont | |
let lineLimit: Int | |
private var moreLessText: String { | |
if !truncated { | |
return "" | |
} else { | |
return self.expanded ? " read less" : " ... read more" | |
} | |
} | |
init(_ text: String, lineLimit: Int, font: UIFont = UIFont.preferredFont(forTextStyle: UIFont.TextStyle.body)) { | |
self.text = text | |
self.lineLimit = lineLimit | |
_shrinkText = State(wrappedValue: text) | |
self.font = font | |
} | |
var body: some View { | |
ZStack(alignment: .bottomLeading) { | |
Group { | |
Text(self.expanded ? text : shrinkText) | |
+ Text(moreLessText) | |
.bold() | |
.foregroundColor(.blue) | |
}.animation(.easeInOut) | |
.lineLimit(expanded ? nil : lineLimit) | |
.background( | |
// Render the limited text and measure its size | |
Text(text).lineLimit(lineLimit) | |
.background(GeometryReader { visibleTextGeometry in | |
Color.clear.onAppear() { | |
let size = CGSize(width: visibleTextGeometry.size.width, height: .greatestFiniteMagnitude) | |
let attributes:[NSAttributedString.Key:Any] = [NSAttributedString.Key.font: font] | |
///Binary search until mid == low && mid == high | |
var low = 0 | |
var heigh = shrinkText.count | |
var mid = heigh ///start from top so that if text contain we does not need to loop | |
while ((heigh - low) > 1) { | |
let attributedText = NSAttributedString(string: shrinkText + moreLessText, attributes: attributes) | |
let boundingRect = attributedText.boundingRect(with: size, options: NSStringDrawingOptions.usesLineFragmentOrigin, context: nil) | |
if boundingRect.size.height > visibleTextGeometry.size.height { | |
truncated = true | |
heigh = mid | |
mid = (heigh + low)/2 | |
} else { | |
if mid == text.count { | |
break | |
} else { | |
low = mid | |
mid = (low + heigh)/2 | |
} | |
} | |
shrinkText = String(text.prefix(mid)) | |
} | |
if truncated { | |
shrinkText = String(shrinkText.prefix(shrinkText.count - 2)) //-2 extra as highlighted text is bold | |
} | |
} | |
}) | |
.hidden() // Hide the background | |
) | |
.font(Font(font)) ///set default font | |
if truncated { | |
Button(action: { | |
expanded.toggle() | |
}, label: { | |
HStack { //taking tap on only last line, As it is not possible to get 'see more' location | |
Spacer() | |
Text("") | |
}.opacity(0) | |
}) | |
} | |
} | |
} | |
} | |
struct ContentView_Previews: PreviewProvider { | |
static var previews: some View { | |
VStack(alignment: .leading, spacing: 10) { | |
ExpandableText("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Sed ut laborum", lineLimit: 6) | |
ExpandableText("Small text", lineLimit: 3) | |
ExpandableText("Render the limited text and measure its size, R", lineLimit: 1) | |
ExpandableText("Create a ZStack with unbounded height to allow the inner Text as much, Render the limited text and measure its size, Hide the background Indicates whether the text has been truncated in its display.", lineLimit: 3) | |
}.padding() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hello, the code not working for smaller devices, as iPhone SE. The read more text is not visible on these devices