Skip to content
This repository was archived by the owner on Sep 30, 2024. It is now read-only.

Commit f34f5d9

Browse files
committed
Merge branch 'deploy/1.6.0' into productive
2 parents 8054e96 + 06491f7 commit f34f5d9

File tree

6 files changed

+149
-8
lines changed

6 files changed

+149
-8
lines changed

HandyUIKit.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Pod::Spec.new do |s|
22

33
s.name = "HandyUIKit"
4-
s.version = "1.5.0"
4+
s.version = "1.6.0"
55
s.summary = "Handy UI features that should have been part of UIKit in the first place."
66

77
s.description = <<-DESC

README.md

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ alt="Build Status">
1313
alt="codebeat badge">
1414
</a>
1515
<a href="https://github.com/Flinesoft/HandyUIKit/releases">
16-
<img src="https://img.shields.io/badge/Version-1.5.0-blue.svg"
17-
alt="Version: 1.5.0">
16+
<img src="https://img.shields.io/badge/Version-1.6.0-blue.svg"
17+
alt="Version: 1.6.0">
1818
</a>
1919
<img src="https://img.shields.io/badge/Swift-4.0-FFAC45.svg"
2020
alt="Swift: 4.0">
@@ -55,7 +55,7 @@ You can of course also just include this framework manually into your project by
5555
Place the following line to your Cartfile:
5656

5757
``` Swift
58-
github "Flinesoft/HandyUIKit" ~> 1.5
58+
github "Flinesoft/HandyUIKit" ~> 1.6
5959
```
6060

6161
Now run `carthage update`. Then drag & drop the HandyUIKit.framework in the Carthage/build folder to your project. Now you can `import HandyUIKit` in each class you want to use its features. Refer to the [Carthage README](https://github.com/Carthage/Carthage#adding-frameworks-to-an-application) for detailed / updated instructions.
@@ -70,7 +70,7 @@ platform :ios, '8.0'
7070
use_frameworks!
7171

7272
target 'MyAppTarget' do
73-
pod 'HandyUIKit', '~> 1.5'
73+
pod 'HandyUIKit', '~> 1.6'
7474
end
7575
```
7676

@@ -260,6 +260,25 @@ A hyphenated NSAttributedString with justified alignment and word wrapping line
260260
loremIpsum.hyphenated() // => a justified & hyphenated NSAttributedString object
261261
```
262262

263+
#### .superscripted(font:) / .subscripted(font:) / .superAndSubscripted(font:)
264+
Superscript and/or subscript part of your strings with the structures `^{superscripted text}` and `_{subscripted text}`.
265+
266+
``` Swift
267+
"x^{2}".superscripted(font: UIFont.systemFont(ofSize: 20, weight: .medium))
268+
```
269+
Result: x<sup>2</sup>
270+
271+
``` Swift
272+
"CO_{2}".subscripted(font: UIFont.systemFont(ofSize: 20, weight: .medium))
273+
```
274+
Result: CO<sub>2</sub>
275+
276+
``` Swift
277+
"_{20}Ca^{1,0}".superAndSubscripted(font: UIFont.systemFont(ofSize: 20, weight: .regular))
278+
```
279+
Result: <sub>20</sub>Ca<sup>1,0</sup>
280+
281+
263282

264283
## Contributing
265284

Sources/Code/Extensions/NSAttributedStringExtension.swift

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
import UIKit
1010

11+
private let scriptedTextSizeRatio: CGFloat = 0.618
12+
1113
extension NSAttributedString {
1214
/// Calculates and returns the height needed to fit the text into a width-constrained rect.
1315
///
@@ -37,4 +39,85 @@ extension NSAttributedString {
3739

3840
return copy.boundingRect(with: constraintSize, options: .usesLineFragmentOrigin, context: nil)
3941
}
42+
43+
/// Superscripts substrings of structure ^{substring} and subscripts substrings of structure _{substring}.
44+
///
45+
/// - Parameters:
46+
/// - font: The base font size for the resulting attributed string.
47+
/// - applyFont: Specify if the font shall be applied to the resulting attributed string. Defaults to `true`.
48+
///
49+
/// - Returns: The resulting attributed string with superscripted and subscripted substrings.
50+
public func superAndSubscripted(font: UIFont, applyFont: Bool = true) -> NSAttributedString {
51+
return subscripted(font: font).superscripted(font: font, applyFont: false)
52+
}
53+
54+
/// Superscripts substrings of structure ^{substring}.
55+
///
56+
/// - Parameters:
57+
/// - font: The base font size for the resulting attributed string.
58+
/// - applyFont: Specify if the font shall be applied to the resulting attributed string. Defaults to `true`.
59+
///
60+
/// - Returns: The resulting attributed string with superscripted substrings.
61+
public func superscripted(font: UIFont, applyFont: Bool = true) -> NSAttributedString {
62+
return scripted(
63+
font: font,
64+
regex: try! NSRegularExpression(pattern: "\\^\\{([^\\}]*)\\}"), // swiftlint:disable:this force_try
65+
captureBaselineOffset: font.pointSize * (1.0 - scriptedTextSizeRatio),
66+
applyFont: applyFont
67+
)
68+
}
69+
70+
/// Subscripts substrings of structure _{substring}.
71+
///
72+
/// - Parameters:
73+
/// - font: The base font size for the resulting attributed string.
74+
/// - applyFont: Specify if the font shall be applied to the resulting attributed string. Defaults to `true`.
75+
///
76+
/// - Returns: The resulting attributed string with subscripted substrings.
77+
public func subscripted(font: UIFont, applyFont: Bool = true) -> NSAttributedString {
78+
return scripted(
79+
font: font,
80+
regex: try! NSRegularExpression(pattern: "\\_\\{([^\\}]*)\\}"), // swiftlint:disable:this force_try
81+
captureBaselineOffset: font.pointSize * -(scriptedTextSizeRatio / 5),
82+
applyFont: applyFont
83+
)
84+
}
85+
86+
// swiftlint:disable force_cast
87+
private func scripted(font: UIFont, regex: NSRegularExpression, captureBaselineOffset: CGFloat, applyFont: Bool = true) -> NSAttributedString {
88+
// apply font to entire string
89+
let unprocessedString = self.mutableCopy() as! NSMutableAttributedString
90+
91+
if applyFont {
92+
unprocessedString.addAttribute(.font, value: font, range: NSRange(location: 0, length: unprocessedString.length))
93+
}
94+
95+
// start reading in the string part by part
96+
let attributedString = NSMutableAttributedString()
97+
98+
while let match = regex.firstMatch(
99+
in: unprocessedString.string,
100+
options: .reportCompletion,
101+
range: NSRange(location: 0, length: unprocessedString.length)
102+
) {
103+
// add substring before match
104+
let substringBeforeMatch = unprocessedString.attributedSubstring(from: NSRange(location: 0, length: match.range.location))
105+
attributedString.append(substringBeforeMatch)
106+
107+
// add match with subscripted style
108+
let capturedSubstring = unprocessedString.attributedSubstring(from: match.range(at: 1)).mutableCopy() as! NSMutableAttributedString
109+
let captureFullRange = NSRange(location: 0, length: capturedSubstring.length)
110+
capturedSubstring.addAttribute(.font, value: font.withSize(font.pointSize * scriptedTextSizeRatio), range: captureFullRange)
111+
capturedSubstring.addAttribute(.baselineOffset, value: captureBaselineOffset, range: captureFullRange)
112+
attributedString.append(capturedSubstring)
113+
114+
// strip off the processed part
115+
unprocessedString.deleteCharacters(in: NSRange(location: 0, length: match.range.location + match.range.length))
116+
}
117+
118+
// add substring after last match
119+
attributedString.append(unprocessedString)
120+
121+
return attributedString.copy() as! NSAttributedString
122+
} // swiftlint:enable force_cast
40123
}

Sources/Code/Extensions/StringExtension.swift

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,4 +45,34 @@ extension String {
4545

4646
return NSAttributedString(string: self, attributes: [NSAttributedStringKey.paragraphStyle: paragraphStyle])
4747
}
48+
49+
/// Superscripts substrings of structure ^{substring} and subscripts substrings of structure _{substring}.
50+
///
51+
/// - Parameters:
52+
/// - font: The base font size for the resulting attributed string.
53+
///
54+
/// - Returns: The resulting attributed string with superscripted and subscripted substrings.
55+
public func superAndSubscripted(font: UIFont) -> NSAttributedString {
56+
return NSAttributedString(string: self).superAndSubscripted(font: font)
57+
}
58+
59+
/// Superscripts substrings of structure ^{substring}.
60+
///
61+
/// - Parameters:
62+
/// - font: The base font size for the resulting attributed string.
63+
///
64+
/// - Returns: The resulting attributed string with superscripted substrings.
65+
public func superscripted(font: UIFont) -> NSAttributedString {
66+
return NSAttributedString(string: self).superscripted(font: font)
67+
}
68+
69+
/// Subscripts substrings of structure _{substring}.
70+
///
71+
/// - Parameters:
72+
/// - font: The base font size for the resulting attributed string.
73+
///
74+
/// - Returns: The resulting attributed string with subscripted substrings.
75+
public func subscripted(font: UIFont) -> NSAttributedString {
76+
return NSAttributedString(string: self).subscripted(font: font)
77+
}
4878
}

Sources/Supporting Files/Info.plist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
<key>CFBundlePackageType</key>
1616
<string>FMWK</string>
1717
<key>CFBundleShortVersionString</key>
18-
<string>1.5.0</string>
18+
<string>1.6.0</string>
1919
<key>CFBundleVersion</key>
2020
<string>$(CURRENT_PROJECT_VERSION)</string>
2121
<key>NSPrincipalClass</key>

UsageExamples.playground/Contents.swift

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,14 +115,23 @@ let originZeroRect2 = CGRect(width: 100, height: 50)
115115

116116
let loremIpsum = "Lorem ipsum dolor sit amet, consectetur adipisici elit, sed eiusmod tempor incidunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquid ex ea commodi consequat. Quis aute iure reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint obcaecat cupiditat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
117117

118-
loremIpsum.height(forFixedWidth: 300, font: UIFont.systemFont(ofSize: 14, weight: UIFontWeightBold))
118+
loremIpsum.height(forFixedWidth: 300, font: UIFont.systemFont(ofSize: 14, weight: .bold))
119119

120120
//: ### .height(for fixedWidth:font:)
121121
//: Calculates and returns the width needed to fit the text into a height-constrained rect.
122122

123-
loremIpsum.width(forFixedHeight: 21, font: UIFont.systemFont(ofSize: 12, weight: UIFontWeightUltraLight))
123+
loremIpsum.width(forFixedHeight: 21, font: UIFont.systemFont(ofSize: 12, weight: .ultraLight))
124124

125125
//: ### .hyphenated()
126126
//: A hyphenated NSAttributedString with justified alignment and word wrapping line break mode.
127127

128128
loremIpsum.hyphenated()
129+
130+
//: ### .superscripted(font:) / .subscripted(font:) / .superAndSubscripted(font:)
131+
//: Superscript and/or subscript part of your strings with the structures `^{superscripted text}` and `_{subscripted text}`.
132+
133+
"x^{2}".superscripted(font: UIFont.systemFont(ofSize: 20, weight: .medium))
134+
135+
"CO_{2}".subscripted(font: UIFont.systemFont(ofSize: 20, weight: .medium))
136+
137+
"_{20}Ca^{1,0}".superAndSubscripted(font: UIFont.systemFont(ofSize: 20, weight: .regular))

0 commit comments

Comments
 (0)