Skip to content

Commit

Permalink
Fixes LCLabel not being able to behave properly when .bottomAnchor co…
Browse files Browse the repository at this point in the history
…nstraint is used with (#35)

Addresses Pr comments by adding the test case in question and fixes the sizing method
  • Loading branch information
mustiikhalil authored Jan 16, 2023
1 parent 54167f0 commit d6fc608
Show file tree
Hide file tree
Showing 10 changed files with 204 additions and 6 deletions.
12 changes: 8 additions & 4 deletions DemoApp/DemoApp.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@
3B21D4822785F3EF0009DE6A /* LCLabelHitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B21D4812785F3EF0009DE6A /* LCLabelHitTests.swift */; };
3B29F028276E99AB00CE3D2D /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B29F027276E99AB00CE3D2D /* AppDelegate.swift */; };
3B29F02A276E99AB00CE3D2D /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B29F029276E99AB00CE3D2D /* SceneDelegate.swift */; };
3B29F02C276E99AB00CE3D2D /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B29F02B276E99AB00CE3D2D /* ViewController.swift */; };
3B29F02C276E99AB00CE3D2D /* FrameViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B29F02B276E99AB00CE3D2D /* FrameViewController.swift */; };
3B29F031276E99AD00CE3D2D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3B29F030276E99AD00CE3D2D /* Assets.xcassets */; };
3B29F034276E99AD00CE3D2D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3B29F032276E99AD00CE3D2D /* LaunchScreen.storyboard */; };
3B47B672279045750021013E /* LCLabelScrollTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B47B671279045750021013E /* LCLabelScrollTests.swift */; };
3B7F146F278CC0ED00AFDD43 /* CollectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B7F146E278CC0ED00AFDD43 /* CollectionViewController.swift */; };
3BC1D7222778FC310071AB35 /* LCLabel in Frameworks */ = {isa = PBXBuildFile; productRef = 3BC1D7212778FC310071AB35 /* LCLabel */; };
3BF48FB1295C90010005626C /* AutoLayoutLCLabelViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BF48FB0295C90010005626C /* AutoLayoutLCLabelViewController.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand All @@ -34,14 +35,15 @@
3B29F024276E99AB00CE3D2D /* DemoApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DemoApp.app; sourceTree = BUILT_PRODUCTS_DIR; };
3B29F027276E99AB00CE3D2D /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
3B29F029276E99AB00CE3D2D /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
3B29F02B276E99AB00CE3D2D /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
3B29F02B276E99AB00CE3D2D /* FrameViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FrameViewController.swift; sourceTree = "<group>"; };
3B29F030276E99AD00CE3D2D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
3B29F033276E99AD00CE3D2D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
3B29F035276E99AD00CE3D2D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
3B47B671279045750021013E /* LCLabelScrollTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LCLabelScrollTests.swift; sourceTree = "<group>"; };
3B47B67327905CA90021013E /* UI Full Tests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; name = "UI Full Tests.xctestplan"; path = "DemoApp.xcodeproj/UI Full Tests.xctestplan"; sourceTree = "<group>"; };
3B7F146E278CC0ED00AFDD43 /* CollectionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectionViewController.swift; sourceTree = "<group>"; };
3BC1D71F2778F8EB0071AB35 /* LCLabel */ = {isa = PBXFileReference; lastKnownFileType = folder; name = LCLabel; path = ..; sourceTree = "<group>"; };
3BF48FB0295C90010005626C /* AutoLayoutLCLabelViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutoLayoutLCLabelViewController.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -98,11 +100,12 @@
children = (
3B29F027276E99AB00CE3D2D /* AppDelegate.swift */,
3B29F029276E99AB00CE3D2D /* SceneDelegate.swift */,
3B29F02B276E99AB00CE3D2D /* ViewController.swift */,
3B29F02B276E99AB00CE3D2D /* FrameViewController.swift */,
3B29F030276E99AD00CE3D2D /* Assets.xcassets */,
3B29F032276E99AD00CE3D2D /* LaunchScreen.storyboard */,
3B29F035276E99AD00CE3D2D /* Info.plist */,
3B7F146E278CC0ED00AFDD43 /* CollectionViewController.swift */,
3BF48FB0295C90010005626C /* AutoLayoutLCLabelViewController.swift */,
);
path = DemoApp;
sourceTree = "<group>";
Expand Down Expand Up @@ -237,7 +240,8 @@
buildActionMask = 2147483647;
files = (
3B7F146F278CC0ED00AFDD43 /* CollectionViewController.swift in Sources */,
3B29F02C276E99AB00CE3D2D /* ViewController.swift in Sources */,
3BF48FB1295C90010005626C /* AutoLayoutLCLabelViewController.swift in Sources */,
3B29F02C276E99AB00CE3D2D /* FrameViewController.swift in Sources */,
3B29F028276E99AB00CE3D2D /* AppDelegate.swift in Sources */,
3B29F02A276E99AB00CE3D2D /* SceneDelegate.swift in Sources */,
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@
</BuildableReference>
</BuildableProductRunnable>
<CommandLineArguments>
<CommandLineArgument
argument = "-autolayout"
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "-scrollview -cellnumbers"
isEnabled = "NO">
Expand Down
85 changes: 85 additions & 0 deletions DemoApp/DemoApp/AutoLayoutLCLabelViewController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// Copyright (c) Mustafa Khalil. and contributors.
//
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree.

import LCLabel
import UIKit

final class AutoLayoutLCLabelViewController: UIViewController {

var stackView: UIStackView!

var currentPressedURL: URL?

override func viewDidLoad() {
super.viewDidLoad()

view.accessibilityIdentifier = "main"
view.backgroundColor = .white

let text = NSMutableAttributedString(
string: "welcome to this new adventure with a very very long text, this should break to a new line, this should have a very very very long text!",
attributes: [
NSAttributedString.Key.foregroundColor: UIColor.white,
NSAttributedString.Key.font: UIFont.systemFont(ofSize: 16),
])
let range = (text.string as NSString).range(of: "welcome")
text.addAttribute(
.lclabelLink,
value: URL(string: "tel://909001")!,
range: range)

// MARK: - Label
let label = labelFactory(
frame: .zero,
text: text)
label.delegate = self

stackView = UIStackView(arrangedSubviews: [label])
stackView.axis = .vertical
stackView.translatesAutoresizingMaskIntoConstraints = false

view.addSubview(stackView)

NSLayoutConstraint.activate([
stackView.topAnchor.constraint(
equalTo: view.topAnchor,
constant: 50),
stackView.leadingAnchor.constraint(
equalTo: view.leadingAnchor),
stackView.trailingAnchor.constraint(
equalTo: view.trailingAnchor),
stackView.bottomAnchor.constraint(
lessThanOrEqualTo: view.bottomAnchor,
constant: -50),
])
}

func labelFactory(
frame: CGRect,
text: NSAttributedString) -> LCLabel
{
let label = LCLabel(frame: .zero)
label.frame = frame
label.backgroundColor = .black
view.addSubview(label)
label.linkAttributes = [
.foregroundColor: UIColor.white,
]
label.centeringTextAlignment = .top
label.isUserInteractionEnabled = true
label.numberOfLines = 0
label.attributedText = text
return label
}

}

extension AutoLayoutLCLabelViewController: LCLabelDelegate {

func didPress(url: URL, at point: CGPoint) {
currentPressedURL = url
}

}
File renamed without changes.
2 changes: 2 additions & 0 deletions DemoApp/DemoApp/SceneDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ final class SceneDelegate: UIResponder, UIWindowSceneDelegate {
window?.makeKeyAndVisible()
if CommandLine.arguments.contains("-scrollview") {
window?.rootViewController = CollectionViewController()
} else if CommandLine.arguments.contains("-autolayout") {
window?.rootViewController = AutoLayoutLCLabelViewController()
} else {
window?.rootViewController = LCLabelViewController()
}
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ open package.swift
3. UI Full Tests // UITests that includes hitches tests

- `DemoApp` explains how to use LCLabel
- `DemoApp` can be ran in three modes, `-scrollview`, `-autolayout` and `default`. You will need to pass the arguments as `Arguments Passed On Launch`
- `UI Full Tests` shows that LCLabel doesnt have any hitches
*The following was compared on an iPhone xs with a baseline of UILabel*

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 17 additions & 1 deletion Sources/LCLabel/LCLabel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -225,9 +225,24 @@ final public class LCLabel: UILabel {
}
/// Returns intrinsicContentSize of the current label
public override var intrinsicContentSize: CGSize {
textContainer.size = bounds.size
let size: CGSize
// Getting the width of the current window, or the width
// of the super view since `window?.windowScene` will be nil
// if superview is set.
let width = window?.windowScene?.screen.bounds.width ??
superview?.bounds.width
if let width = width {
size = CGSize(
width: width,
height: .infinity)
} else {
size = bounds.size
}
textContainer.maximumNumberOfLines = numberOfLines
textContainer.size = size
layoutManager.ensureLayout(for: textContainer)
let rect = layoutManager.usedRect(for: textContainer)
preferredMaxLayoutWidth = rect.width
return rect.size
}
/// Text to be displayed
Expand Down Expand Up @@ -294,6 +309,7 @@ final public class LCLabel: UILabel {
assert(
!newBounds.isNegative,
"The new bounds are negative with isnt allowed, check the frame or the textInsets")
textContainer.maximumNumberOfLines = numberOfLines
textContainer.size = newBounds.size
layoutManager.ensureLayout(for: textContainer)
let drawableFrame = layoutManager.usedRect(for: textContainer)
Expand Down
88 changes: 87 additions & 1 deletion Tests/LCLabelTests/LCLabelTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import LCLabel
import SnapshotTesting
import XCTest

// Screenshots taken on an iPhone 13
// Screenshots taken on an iPhone 13 iOS 15.0
final class LCLabelTests: XCTestCase {

// MARK: Internal
Expand Down Expand Up @@ -542,6 +542,92 @@ final class LCLabelTests: XCTestCase {
XCTFail(message)
}

func testWithinStackViewWithBottomAnchor() {
let attStr = NSMutableAttributedString(
string: "LCLabel",
attributes: [
.foregroundColor: UIColor.white,
.font: UIFont.systemFont(ofSize: 14),
])
attStr.append(NSAttributedString(
string: "\n@LCLabel",
attributes: [
.foregroundColor: UIColor.white,
.font: UIFont.systemFont(ofSize: 10),
.link: "lclabel://welcome",
]))
let label = LCLabel()
label.centeringTextAlignment = .center
label.numberOfLines = 0
label.backgroundColor = .black
label.attributedText = attStr
let stackView = UIStackView(arrangedSubviews: [
label,
])
stackView.axis = .vertical
stackView.translatesAutoresizingMaskIntoConstraints = false
let view = UIView(
frame: CGRect(
x: 0,
y: 0,
width: 390,
height: 300))
view.addSubview(stackView)
view.backgroundColor = .red
NSLayoutConstraint.activate([
stackView.topAnchor.constraint(equalTo: view.topAnchor),
stackView.bottomAnchor.constraint(
lessThanOrEqualTo: view.bottomAnchor,
constant: -20),
stackView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
stackView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
])
let failure = verifySnapshot(
matching: view,
as: .image,
snapshotDirectory: path)
guard let message = failure else { return }
XCTFail(message)
}

func testLongTextAutolayout() {
let text = """
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Aliquet bibendum enim facilisis gravida neque. Orci a scelerisque purus semper eget duis at. Viverra justo nec ultrices dui sapien eget mi proin. Etiam non quam lacus suspendisse faucibus. Vel fringilla est ullamcorper eget nulla facilisi etiam. Donec enim diam vulputate ut pharetra sit amet aliquam id. Ipsum faucibus vitae aliquet nec ullamcorper sit amet risus. Ultrices gravida dictum fusce ut. Nulla aliquet porttitor lacus luctus accumsan tortor posuere ac.
"""
let attr: [NSAttributedString.Key: Any] = [
.foregroundColor: UIColor.white,
.font: UIFont.systemFont(ofSize: 14),
]
let attStr = NSMutableAttributedString(
string: text,
attributes: attr)

let label = createLabel(
text: attStr,
frame: .zero)
label.numberOfLines = 0
label.translatesAutoresizingMaskIntoConstraints = false
let superview = UIView(frame: CGRect(x: 0, y: 0, width: 300, height: 300))
superview.backgroundColor = .purple
superview.addSubview(label)
NSLayoutConstraint.activate([
label.topAnchor.constraint(equalTo: superview.topAnchor),
label.leadingAnchor.constraint(equalTo: superview.leadingAnchor),
label.trailingAnchor.constraint(equalTo: superview.trailingAnchor),
label.bottomAnchor.constraint(lessThanOrEqualTo: superview.bottomAnchor),
])
label.setContentCompressionResistancePriority(.required, for: .vertical)

superview.setNeedsLayout()
superview.layoutIfNeeded()
let failure = verifySnapshot(
matching: superview,
as: .image,
snapshotDirectory: path)
guard let message = failure else { return }
XCTFail(message)
}

func testWithinVerticalStackView() {
let text = """
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Aliquet bibendum enim facilisis gravida neque. Orci a scelerisque purus semper eget duis at. Viverra justo nec ultrices dui sapien eget mi proin. Etiam non quam lacus suspendisse faucibus. Vel fringilla est ullamcorper eget nulla facilisi etiam. Donec enim diam vulputate ut pharetra sit amet aliquam id. Ipsum faucibus vitae aliquet nec ullamcorper sit amet risus. Ultrices gravida dictum fusce ut. Nulla aliquet porttitor lacus luctus accumsan tortor posuere ac. Turpis egestas sed tempus urna et pharetra. Pellentesque nec nam aliquam sem et tortor consequat. Risus sed vulputate odio ut enim blandit volutpat maecenas. Ullamcorper velit sed ullamcorper morbi tincidunt ornare massa. Blandit massa enim nec dui nunc mattis enim ut. Tristique sollicitudin nibh sit amet.
Expand Down

0 comments on commit d6fc608

Please sign in to comment.