Skip to content

Commit 53792a1

Browse files
committed
Made HairSpaceJustifiedText public and added example to example app.
1 parent 0513afa commit 53792a1

4 files changed

Lines changed: 65 additions & 10 deletions

File tree

Example/FrameUpExample.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
CF19BC182AA7BC730096876A /* View+IfAvailable.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF19BC172AA7BC730096876A /* View+IfAvailable.swift */; };
3030
CF19BC192AA7BC780096876A /* View+IfAvailable.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF19BC172AA7BC730096876A /* View+IfAvailable.swift */; };
3131
CF1AB2B22CB5BF530049E553 /* FrameUp in Frameworks */ = {isa = PBXBuildFile; productRef = CF1AB2B12CB5BF530049E553 /* FrameUp */; };
32+
CF1C336B2CC6C1170003069B /* HairSpaceJustifiedTextExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF1C336A2CC6C1170003069B /* HairSpaceJustifiedTextExample.swift */; };
3233
CF1EEF30274D4C4C00987595 /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CF1EEF2F274D4C4C00987595 /* WidgetKit.framework */; };
3334
CF1EEF32274D4C4C00987595 /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CF1EEF31274D4C4C00987595 /* SwiftUI.framework */; };
3435
CF1EEF35274D4C4C00987595 /* WidgetFrameWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF1EEF34274D4C4C00987595 /* WidgetFrameWidget.swift */; };
@@ -173,6 +174,7 @@
173174
CF19BC082AA67CA70096876A /* SharedAssets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = SharedAssets.xcassets; sourceTree = "<group>"; };
174175
CF19BC0B2AA67F6E0096876A /* InlineImageExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InlineImageExample.swift; sourceTree = "<group>"; };
175176
CF19BC172AA7BC730096876A /* View+IfAvailable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "View+IfAvailable.swift"; sourceTree = "<group>"; };
177+
CF1C336A2CC6C1170003069B /* HairSpaceJustifiedTextExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HairSpaceJustifiedTextExample.swift; sourceTree = "<group>"; };
176178
CF1EEF2D274D4C4C00987595 /* WidgetFrameWidgetExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = WidgetFrameWidgetExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
177179
CF1EEF2F274D4C4C00987595 /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = System/Library/Frameworks/WidgetKit.framework; sourceTree = SDKROOT; };
178180
CF1EEF31274D4C4C00987595 /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; };
@@ -509,6 +511,7 @@
509511
children = (
510512
CFE981F72C9DF0F90094A1A8 /* TextExamples.swift */,
511513
CFE981F42C9DF06B0094A1A8 /* UnclippedTextExample.swift */,
514+
CF1C336A2CC6C1170003069B /* HairSpaceJustifiedTextExample.swift */,
512515
);
513516
path = TextExamples;
514517
sourceTree = "<group>";
@@ -741,6 +744,7 @@
741744
CF2D066C292201BD007D1142 /* DoubleScrollTabView.swift in Sources */,
742745
CFC476572A0C9FC2003B51CF /* HMasonryAspectRatioExample.swift in Sources */,
743746
CFAC14A02885BC99003D4539 /* HFlowExample.swift in Sources */,
747+
CF1C336B2CC6C1170003069B /* HairSpaceJustifiedTextExample.swift in Sources */,
744748
CF48CC9F26F131C200406F4E /* FrameUpExampleApp.swift in Sources */,
745749
CFF9E74F2A0F304900451A65 /* HFlowLayoutExample.swift in Sources */,
746750
CF25F6532901D91C0041FBAF /* HFlowSmartScrollViewExample.swift in Sources */,
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
//
2+
// HairSpaceJustifiedTextExample.swift
3+
// FrameUpExample
4+
//
5+
// Created by Ryan Lintott on 2024-10-21.
6+
//
7+
8+
import FrameUp
9+
import SwiftUI
10+
11+
struct HairSpaceJustifiedTextExample: View {
12+
var body: some View {
13+
VStack {
14+
/// Example of Text with mixed LTR and RTL text.
15+
Text("This ثم كلا ارتكبها إستيلاء البولندي, احداث نتيجة بالرّدأسر بـ.ثموصل جديدة aslkasjdf والكساد. ان مكثّفة العالم الهادي أضف, مما مع انذار")
16+
.font(.system(size: 16).bold())
17+
18+
/// Example of HairSpaceJustified with the same mixed LTR and RTL text.
19+
HairSpaceJustifiedText(
20+
// Arabic for "Hello, World"
21+
"This ثم كلا ارتكبها إستيلاء البولندي, احداث نتيجة بالرّدأسر بـ.ثموصل جديدة aslkasjdf والكساد. ان مكثّفة العالم الهادي أضف, مما مع انذار",
22+
font: .boldSystemFont(ofSize: 16),
23+
justifyLastLine: false
24+
)
25+
26+
HairSpaceJustifiedText(
27+
"""
28+
This is a bunch of text justified by hair spaces. SwiftUI doesn't have a way of justifying text so this view swaps out all spaces with varying numbers of hair spaces to adjust each line and make it appear justified.
29+
The last line of a paragraph is not justified by default but it can be by parameter.
30+
Line breaks continue to work as expected.
31+
32+
Multiple line breaks remain but multiple spaces are condensed into a single space or line break.
33+
34+
If you have a veryLongWordThatWillNotFitOnASingleLineItWillBeBrokenAtTheLastCharacterThatFits
35+
36+
Words are not hyphenated.
37+
38+
UIFont must be used as that is how the text width is calculated.
39+
""",
40+
font: .boldSystemFont(ofSize: 16),
41+
justifyLastLine: false
42+
)
43+
}
44+
.padding()
45+
}
46+
}
47+
48+
#Preview {
49+
HairSpaceJustifiedTextExample()
50+
}

Example/FrameUpExample/TextExamples/TextExamples.swift

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,18 @@ import SwiftUI
1010
struct TextExamples: View {
1111
var body: some View {
1212
Section {
13+
NavigationLink(destination: HairSpaceJustifiedTextExample()) {
14+
Label("HairSpaceJustifiedText", systemImage: "character.textbox")
15+
}
16+
17+
/// This check ensures this code only builds in Xcode 16+
18+
#if compiler(>=6)
1319
if #available(iOS 18, macOS 15, watchOS 11, tvOS 18, visionOS 2, *) {
14-
/// This check ensures this code only builds in Xcode 16+
15-
#if compiler(>=6)
1620
NavigationLink(destination: UnclippedTextExample()) {
1721
Label("Unclipped Text", systemImage: "character.textbox")
1822
}
19-
#else
20-
UnavailableView(availableInLaterVersion: true)
21-
#endif
22-
} else {
23-
UnavailableView(availableInLaterVersion: true)
2423
}
24+
#endif
2525
} header: {
2626
Text("Text")
2727
}

Sources/FrameUp/_Experimental/HairSpaceJustifiedText.swift renamed to Sources/FrameUp/Text/HairSpaceJustifiedText.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
//
55
// Created by Ryan Lintott on 2022-11-15.
66
//
7+
78
import SwiftUI
89

910
#if os(iOS)
@@ -136,18 +137,18 @@ extension StringProtocol {
136137
}
137138

138139
/// A SwiftUI-only method for efficiently presenting justifying text. This is particularly useful in a widget or other SwiftUI-only setting.
139-
struct HairSpaceJustifiedText: View {
140+
public struct HairSpaceJustifiedText: View {
140141
let text: String
141142
let font: UIFont
142143
let justifyLastLine: Bool
143144

144-
init(_ text: String, font: UIFont, justifyLastLine: Bool = false) {
145+
public init(_ text: String, font: UIFont, justifyLastLine: Bool = false) {
145146
self.font = font
146147
self.text = text
147148
self.justifyLastLine = justifyLastLine
148149
}
149150

150-
var body: some View {
151+
public var body: some View {
151152
WidthReader { width in
152153
Text(text.justifiedByHairSpaces(font: font, maxWidth: width, justifyLastLine: justifyLastLine))
153154
.font(Font(font))

0 commit comments

Comments
 (0)