Skip to content

Commit

Permalink
Merge pull request #101 from square/entin/distribution-rtl
Browse files Browse the repository at this point in the history
Fix horizontal distribution in RTL layout
  • Loading branch information
NickEntin committed May 25, 2023
2 parents 31f5c79 + 2de2b82 commit e17929b
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,21 @@ final class ViewDistributionSnapshotTests: SnapshotTestCase {
assertSnapshot(matching: containerView, as: .image, named: nameForSnapshot(with: []))
}

func testHorizontalDistributionFollowsLayoutDirection() {
let view = HorizontalDistributionView(frame: CGRect(x: 0, y: 0, width: 160, height: 60))

assertSnapshot(
matching: view,
as: .image,
named: nameForSnapshot(with: ["LTR"])
)
assertSnapshot(
matching: view,
as: .image(traits: .init(layoutDirection: .rightToLeft)),
named: nameForSnapshot(with: ["RTL"])
)
}

}

// MARK: -
Expand Down Expand Up @@ -137,3 +152,63 @@ extension UIUserInterfaceLayoutDirection {
}

}

// MARK: -

final class HorizontalDistributionView: UIView {

// MARK: - Life Cycle

override init(frame: CGRect) {
super.init(frame: frame)

firstView.bounds.size = .init(width: 40, height: 40)
firstView.backgroundColor = .red
addSubview(firstView)

secondView.bounds.size = .init(width: 40, height: 40)
secondView.backgroundColor = .green
addSubview(secondView)

thirdView.bounds.size = .init(width: 40, height: 40)
thirdView.backgroundColor = .blue
addSubview(thirdView)

// Set arbitrary semantic content attributes to ensure the layout relies on the _receiver's_ effective layout
// direction, not that of the distributed views.
firstView.semanticContentAttribute = .forceLeftToRight
secondView.semanticContentAttribute = .forceRightToLeft

backgroundColor = .white
}

@available(*, unavailable)
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

// MARK: - Private Properties

private let firstView: UIView = .init()

private let secondView: UIView = .init()

private let thirdView: UIView = .init()

// MARK: - UIView

override func layoutSubviews() {
applyHorizontalSubviewDistribution(
[
1.flexible,
firstView,
1.flexible,
secondView,
1.flexible,
thirdView,
1.flexible,
]
)
}

}
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.
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.
20 changes: 12 additions & 8 deletions Paralayout/UIView+Distribution.swift
Original file line number Diff line number Diff line change
Expand Up @@ -254,17 +254,21 @@ extension UIView {
let receiverLayoutDirection = effectiveUserInterfaceLayoutDirection

// Okay, ready to go!
var viewOrigin = axis.leadingEdge(of: layoutBounds, layoutDirection: receiverLayoutDirection)
var leadingEdgePosition = axis.leadingEdge(of: layoutBounds, layoutDirection: receiverLayoutDirection)
for item in items {
switch item {
case .view(let subview, let insets):
var frame = subview.untransformedFrame

switch axis {
case .horizontal:
frame.origin.x = (viewOrigin - insets.left).roundedToPixel(in: self)
case .vertical:
frame.origin.y = (viewOrigin - insets.top).roundedToPixel(in: self)
switch (axis, receiverLayoutDirection) {
case (.horizontal, .leftToRight):
frame.origin.x = (leadingEdgePosition - insets.left).roundedToPixel(in: self)
case (.horizontal, .rightToLeft):
frame.origin.x = (leadingEdgePosition + insets.right - frame.width).roundedToPixel(in: self)
case (.vertical, _):
frame.origin.y = (leadingEdgePosition - insets.top).roundedToPixel(in: self)
@unknown default:
fatalError("Unknown user interface layout direction")
}

applyOrthogonalAlignment(&frame, layoutBounds)
Expand All @@ -287,9 +291,9 @@ extension UIView {

switch (axis, receiverLayoutDirection) {
case (.horizontal, .leftToRight), (.vertical, _):
viewOrigin += distanceToMoveOrigin
leadingEdgePosition += distanceToMoveOrigin
case (.horizontal, .rightToLeft):
viewOrigin -= distanceToMoveOrigin
leadingEdgePosition -= distanceToMoveOrigin
@unknown default:
fatalError("Unknown user interface layout direction")
}
Expand Down

0 comments on commit e17929b

Please sign in to comment.