diff --git a/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..919434a
--- /dev/null
+++ b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/README.md b/README.md
index efb8061..419fde5 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,8 @@
+## This code is forked from @jasudev and it supports multiline texts. To customize the UI, simply go to AnimateText file and edit lines that are commented on.
+
+
+
+
# **AnimateText for SwiftUI**
This library for animating text. Developed with SwiftUI. This library supports iOS/macOS.
diff --git a/Sources/AnimateText/AnimateText.swift b/Sources/AnimateText/AnimateText.swift
index db9676d..a03468f 100644
--- a/Sources/AnimateText/AnimateText.swift
+++ b/Sources/AnimateText/AnimateText.swift
@@ -37,6 +37,9 @@ public struct AnimateText: View {
/// Custom user info for the effect.
var userInfo: Any? = nil
+ /// The height of the Text view.
+ @State private var height: CGFloat = 0
+
/// Split text into individual elements.
@State private var elements: Array = []
@@ -69,25 +72,42 @@ public struct AnimateText: View {
ZStack(alignment: .leading) {
if !isChanged {
Text(text)
- .lineLimit(1)
.takeSize($size)
+ .multilineTextAlignment(.center)
}else {
- HStack(spacing: 0) {
- ForEach(Array(elements.enumerated()), id: \.offset) { index, element in
- let data = ATElementData(element: element,
- type: self.type,
- index: index,
- count: elements.count,
- value: value,
- size: size)
- if toggle {
- Text(element).modifier(E(data, userInfo))
- }else {
- Text(element).modifier(E(data, userInfo))
+ GeometryReader { geometry in
+ VStack(alignment: .leading, spacing: 0) {
+ ForEach(splitElements(containerWidth: geometry.size.width), id: \.self) { lineElements in
+ HStack {
+ Spacer()
+ HStack(spacing: 0) {
+ ForEach(Array(lineElements.enumerated()), id: \.offset) { index, element in
+ let data = ATElementData(element: element,
+ type: self.type,
+ index: index,
+ count: elements.count,
+ value: value,
+ size: size)
+ if toggle {
+ Text(element).modifier(E(data, userInfo))
+ } else {
+ Text(element).modifier(E(data, userInfo))
+ }
+ }
+ }
+ .fixedSize(horizontal: true, vertical: false)
+ Spacer()
+ }
}
}
+ .onAppear {
+ height = CGFloat(splitElements(containerWidth: geometry.size.width).count) * 40 // here you can customize the height to align a text
+ }
+ .onChange(of: geometry.size.width) { newValue in
+ height = CGFloat(splitElements(containerWidth: geometry.size.width).count) * 40 // here you can customize the height to align a text
+ }
}
- .fixedSize(horizontal: true, vertical: false)
+ .frame(height: height)
}
}
.onChange(of: text) { _ in
@@ -117,6 +137,56 @@ public struct AnimateText: View {
self.elements = elements
}
}
+
+ func splitElements(containerWidth: CGFloat) -> [[String]] {
+ var lines: [[String]] = [[]]
+ var currentLineIndex = 0
+ var remainingWidth: CGFloat = containerWidth
+ var currentWord: String = ""
+ var words: [String] = []
+
+ // build words
+ for (index, element) in elements.enumerated() {
+ if element == " " {
+ currentWord.append(element)
+ words.append(currentWord)
+ currentWord = ""
+ } else {
+ // Add the element to the current word
+ currentWord.append(element)
+
+ // Check if this is the last element
+ if index == elements.count - 1 {
+ words.append(currentWord)
+ }
+ }
+ }
+
+ // build sentences, split words into elements
+ for (index, word) in words.enumerated() {
+ var letters: [String] = []
+ for char in word {
+ letters.append(String(char))
+ }
+
+ let wordWidth = word.width(withConstrainedHeight: 1000, font: .systemFont(ofSize: 40)) // change the size if you change a font on your contentView
+
+ if index == 0 {
+ lines[currentLineIndex].append(contentsOf: letters)
+ remainingWidth -= wordWidth
+ } else {
+ if wordWidth > remainingWidth {
+ currentLineIndex += 1
+ lines.append(letters)
+ remainingWidth = containerWidth - wordWidth
+ } else {
+ lines[currentLineIndex].append(contentsOf: letters)
+ remainingWidth -= wordWidth
+ }
+ }
+ }
+ return lines
+ }
}
struct AnimateText_Previews: PreviewProvider {
@@ -124,3 +194,11 @@ struct AnimateText_Previews: PreviewProvider {
ATAnimateTextPreview()
}
}
+
+extension String {
+ func width(withConstrainedHeight height: CGFloat, font: UIFont) -> CGFloat {
+ let constraintRect = CGSize(width: .greatestFiniteMagnitude, height: height)
+ let boundingBox = self.boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, attributes: [.font: font], context: nil)
+ return ceil(boundingBox.width)
+ }
+}
diff --git a/Sources/AnimateText/Preview/ATAnimateTextPreview.swift b/Sources/AnimateText/Preview/ATAnimateTextPreview.swift
index e4187b9..0818498 100644
--- a/Sources/AnimateText/Preview/ATAnimateTextPreview.swift
+++ b/Sources/AnimateText/Preview/ATAnimateTextPreview.swift
@@ -41,13 +41,16 @@ public struct ATAnimateTextPreview: View {
VStack(alignment: .leading) {
Spacer()
AnimateText($text, type: type)
- .font(.largeTitle)
+ .font(.largeTitle) // remember that if you change the font, you should change the size of wordWidth in struct "AnimateText"
.padding()
.background(
RoundedRectangle(cornerRadius: 10)
.fill(Color.blue.opacity(0.1))
+ .frame(height: 300) // modify this if you need
)
.padding(.leading)
+ .padding(.trailing)
+ Spacer()
Divider().padding()
HStack {
Spacer()