From 23c4993a730217c8e811d8c570de4dff0ee92f99 Mon Sep 17 00:00:00 2001 From: Krzysztof Czura Date: Sun, 11 Feb 2024 23:33:08 +0100 Subject: [PATCH 1/5] Add a multiline feature. --- .../contents.xcworkspacedata | 7 ++ Sources/AnimateText/AnimateText.swift | 107 +++++++++++++++--- .../Preview/ATAnimateTextPreview.swift | 1 + 3 files changed, 101 insertions(+), 14 deletions(-) create mode 100644 .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata 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/Sources/AnimateText/AnimateText.swift b/Sources/AnimateText/AnimateText.swift index db9676d..f900883 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,43 @@ 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) * 15 + } + .onChange(of: geometry.size.width) { newValue in + height = CGFloat(splitElements(containerWidth: geometry.size.width).count) * 15 + } } - .fixedSize(horizontal: true, vertical: false) + .padding(.bottom, 40) + .frame(height: height) } } .onChange(of: text) { _ in @@ -117,6 +138,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: 18)) // Assuming font size 18 + + 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 +195,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..788a058 100644 --- a/Sources/AnimateText/Preview/ATAnimateTextPreview.swift +++ b/Sources/AnimateText/Preview/ATAnimateTextPreview.swift @@ -48,6 +48,7 @@ public struct ATAnimateTextPreview: View { .fill(Color.blue.opacity(0.1)) ) .padding(.leading) + .padding(.trailing) Divider().padding() HStack { Spacer() From a9f80bfe93f8c5c28137d458e86a72cbc9c223f8 Mon Sep 17 00:00:00 2001 From: Krzysztof Czura Date: Sun, 11 Feb 2024 23:39:40 +0100 Subject: [PATCH 2/5] Fix alignment. --- Sources/AnimateText/AnimateText.swift | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Sources/AnimateText/AnimateText.swift b/Sources/AnimateText/AnimateText.swift index f900883..a4a1221 100644 --- a/Sources/AnimateText/AnimateText.swift +++ b/Sources/AnimateText/AnimateText.swift @@ -101,13 +101,12 @@ public struct AnimateText: View { } } .onAppear { - height = CGFloat(splitElements(containerWidth: geometry.size.width).count) * 15 + height = CGFloat(splitElements(containerWidth: geometry.size.width).count) * 20 } .onChange(of: geometry.size.width) { newValue in - height = CGFloat(splitElements(containerWidth: geometry.size.width).count) * 15 + height = CGFloat(splitElements(containerWidth: geometry.size.width).count) * 20 } } - .padding(.bottom, 40) .frame(height: height) } } From c5dc7f1c5be9862d5005b52b703a0b5c6ca72bd6 Mon Sep 17 00:00:00 2001 From: Krzysztof Czura Date: Mon, 12 Feb 2024 01:13:08 +0100 Subject: [PATCH 3/5] Finish the project. Customize the hight of a text field. --- Sources/AnimateText/AnimateText.swift | 6 +++--- Sources/AnimateText/Preview/ATAnimateTextPreview.swift | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Sources/AnimateText/AnimateText.swift b/Sources/AnimateText/AnimateText.swift index a4a1221..a03468f 100644 --- a/Sources/AnimateText/AnimateText.swift +++ b/Sources/AnimateText/AnimateText.swift @@ -101,10 +101,10 @@ public struct AnimateText: View { } } .onAppear { - height = CGFloat(splitElements(containerWidth: geometry.size.width).count) * 20 + 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) * 20 + height = CGFloat(splitElements(containerWidth: geometry.size.width).count) * 40 // here you can customize the height to align a text } } .frame(height: height) @@ -169,7 +169,7 @@ public struct AnimateText: View { letters.append(String(char)) } - let wordWidth = word.width(withConstrainedHeight: 1000, font: .systemFont(ofSize: 18)) // Assuming font size 18 + 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) diff --git a/Sources/AnimateText/Preview/ATAnimateTextPreview.swift b/Sources/AnimateText/Preview/ATAnimateTextPreview.swift index 788a058..0818498 100644 --- a/Sources/AnimateText/Preview/ATAnimateTextPreview.swift +++ b/Sources/AnimateText/Preview/ATAnimateTextPreview.swift @@ -41,14 +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() From 1514d8381f4a2894d25b5a7e578af65d33b39e7d Mon Sep 17 00:00:00 2001 From: krzysiekk22d <81439980+krzysiekk22d@users.noreply.github.com> Date: Tue, 13 Feb 2024 21:43:51 +0100 Subject: [PATCH 4/5] Update README.md --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index efb8061..afa8761 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,9 @@ +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. From ebb489f384e0b2fb22c7965f521fec9a85ed90da Mon Sep 17 00:00:00 2001 From: krzysiekk22d <81439980+krzysiekk22d@users.noreply.github.com> Date: Tue, 13 Feb 2024 21:51:22 +0100 Subject: [PATCH 5/5] Update 2 README.md --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index afa8761..419fde5 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ -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. - +## 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.