Last active
October 1, 2024 18:25
-
-
Save ryanlintott/2340f35977bf2d1f7b6ea40aa379bcc6 to your computer and use it in GitHub Desktop.
Alternative Text view for SwiftUI with an extendable clipping area. This is a fix for certain fonts and characters that have a clipped intrinsic size.
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 | |
import UIKit | |
struct NoClipText: UIViewRepresentable { | |
typealias UIViewType = NoClipLabel | |
let text: String | |
let font: UIFont | |
let clipExtension: EdgeSizes | |
func makeUIView(context: Context) -> UIViewType { | |
let uiView = UIViewType() | |
uiView.text = text | |
uiView.font = font | |
uiView.clipExtension = clipExtension | |
return uiView | |
} | |
func updateUIView(_ uiView: UIViewType, context: Context) { | |
uiView.text = text | |
uiView.font = font | |
uiView.clipExtension = clipExtension | |
} | |
} | |
struct NoClipText_Previews: PreviewProvider { | |
static let font: UIFont = UIFont(name: "Cochin", size: 48)! | |
static var previews: some View { | |
Group { | |
NoClipText(text: "Ǣʃ", font: font, clipExtension: .zero) | |
.fixedSize() | |
NoClipText(text: "Ǣʃ", font: font, clipExtension: .all(10)) | |
.fixedSize() | |
} | |
.previewLayout(.sizeThatFits) | |
.border(Color.blue, width: 1) | |
.padding(10) | |
} | |
} | |
class NoClipLabel: UILabel { | |
static let defaultClipExtension: EdgeSizes = .all(10) | |
var clipExtension: EdgeSizes | |
var top: CGFloat { clipExtension.top } | |
var left: CGFloat { clipExtension.left } | |
var bottom: CGFloat { clipExtension.bottom } | |
var right: CGFloat { clipExtension.right } | |
var width: CGFloat { left + right } | |
var height: CGFloat { bottom + top } | |
required init(clipExtension: EdgeSizes = defaultClipExtension) { | |
self.clipExtension = clipExtension | |
super.init(frame: CGRect.zero) | |
} | |
override init(frame: CGRect) { | |
clipExtension = Self.defaultClipExtension | |
super.init(frame: frame) | |
} | |
required init?(coder aDecoder: NSCoder) { | |
clipExtension = Self.defaultClipExtension | |
super.init(coder: aDecoder) | |
} | |
override func draw(_ rect: CGRect) { | |
super.drawText(in: rect.inset(by: UIEdgeInsets(top: top, left: left, bottom: bottom, right: right))) | |
} | |
override var alignmentRectInsets: UIEdgeInsets { | |
return .init(top: top, left: left, bottom: bottom, right: right) | |
} | |
override var intrinsicContentSize: CGSize { | |
var size = super.intrinsicContentSize | |
size.width += width | |
size.height += height | |
return size | |
} | |
override func sizeThatFits(_ size: CGSize) -> CGSize { | |
let fixedSize = CGSize(width: size.width - width, height: size.height - height) | |
let sizeWithoutExtension = super.sizeThatFits(fixedSize) | |
return CGSize(width: sizeWithoutExtension.width + width, | |
height: sizeWithoutExtension.height + height) | |
} | |
} | |
struct EdgeSizes: Equatable { | |
let top: CGFloat | |
let left: CGFloat | |
let bottom: CGFloat | |
let right: CGFloat | |
init(top: CGFloat = 0, left: CGFloat = 0, bottom: CGFloat = 0, right: CGFloat = 0) { | |
self.top = top | |
self.left = left | |
self.bottom = bottom | |
self.right = right | |
} | |
init(vertical: CGFloat = 0, horizontal: CGFloat = 0) { | |
self.top = vertical | |
self.left = horizontal | |
self.bottom = vertical | |
self.right = horizontal | |
} | |
init(_ all: CGFloat) { | |
self.top = all | |
self.left = all | |
self.bottom = all | |
self.right = all | |
} | |
static let zero = EdgeSizes(0) | |
static func all(_ size: CGFloat) -> EdgeSizes { | |
EdgeSizes(size) | |
} | |
static func vertical(_ size: CGFloat) -> EdgeSizes { | |
EdgeSizes(vertical: size) | |
} | |
static func horizontal(_ size: CGFloat) -> EdgeSizes { | |
EdgeSizes(horizontal: size) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Modified from this solution on stackoverflow.