Skip to content

Commit

Permalink
Merge pull request #84 from mirego/aspect_ratio
Browse files Browse the repository at this point in the history
Implementation of aspectRatio methods
  • Loading branch information
Luc Dion committed Sep 29, 2017
2 parents 2c55b0a + 5a3fe9a commit 1b2c341
Show file tree
Hide file tree
Showing 15 changed files with 536 additions and 53 deletions.
27 changes: 27 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,33 @@

# Change Log

## [1.3.2](https://github.com/mirego/PinLayout/releases/tag/1.3.2)
#### Change
* Add **aspectRatio** methods:
* **`aspectRatio(_ ratio: CGFloat)`**:
Set the view aspect ratio. If a single dimension is set (either width or height), the aspect ratio will be used to compute the other dimension.
* AspectRatio is defined as the ratio between the width and the height (width / height).
* An aspect ratio of 2 means the width is twice the size of the height.
* AspectRatio respects the min (minWidth/minHeight) and the max (maxWidth/maxHeight) dimensions of an item.
Set all margins using an UIEdgeInsets.
This method is particularly useful to set all margins using iOS 11 UIView.safeAreaInsets
* **`aspectRatio(of view: UIView)`**:
Set the view aspect ratio using another UIView's aspect ratio.

AspectRatio is applied only if a single dimension (either width or height) can be determined,
in that case the aspect ratio will be used to compute the other dimension.

* AspectRatio is defined as the ratio between the width and the height (width / height).
* AspectRatio respects the min (minWidth/minHeight) and the max (maxWidth/maxHeight)
dimensions of an item.

* **`aspectRatio()`**:
If the layouted view is an UIImageView, this method will set the aspectRatio using
the UIImageView's image dimension.
For other types of views, this method as no impact.
* Added by [Luc Dion](https://github.com/lucdion) in Pull Request [#84](https://github.com/mirego/PinLayout/pull/84)
*
## [1.3.1](https://github.com/mirego/PinLayout/releases/tag/1.3.1)
#### Change
* Add new margin method `margin(_ insets: UIEdgeInsets)`
Expand Down
2 changes: 1 addition & 1 deletion PinLayout.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Pod::Spec.new do |s|
#

s.name = "PinLayout"
s.version = "1.3.1"
s.version = "1.3.2"
s.summary = "Fast Swift UIViews layouting without auto layout. No magic, pure code, full control and blazing fast. Concise syntax, intuitive, readable & chainable."

# This description is used to generate tags and improve search results.
Expand Down
10 changes: 9 additions & 1 deletion PinLayout.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
2469C5041E75DB7600073BEE /* RectNimbleMatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2469C5031E75DB7600073BEE /* RectNimbleMatcher.swift */; };
246D36481E6C46F50050F202 /* PinPointCoordinatesSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 246D36471E6C46F50050F202 /* PinPointCoordinatesSpec.swift */; };
2482908C1E78CFFC00667D08 /* RelativePositionSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2482908B1E78CFFC00667D08 /* RelativePositionSpec.swift */; };
248E4C741F7A883800C0E7F7 /* AspectRatioTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 248E4C721F7A83FA00C0E7F7 /* AspectRatioTests.swift */; };
248E4C771F7A88D200C0E7F7 /* UIImage+Color.swift in Sources */ = {isa = PBXBuildFile; fileRef = 248E4C751F7A88CF00C0E7F7 /* UIImage+Color.swift */; };
24949A281EF550E2003643D3 /* PinLayoutImpl+Relative.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24949A271EF550E2003643D3 /* PinLayoutImpl+Relative.swift */; };
24949A2A1EF551D6003643D3 /* PinLayoutImpl+Coordinates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24949A291EF551D6003643D3 /* PinLayoutImpl+Coordinates.swift */; };
24949A2C1EF55216003643D3 /* PinLayoutImpl+Warning.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24949A2B1EF55216003643D3 /* PinLayoutImpl+Warning.swift */; };
Expand Down Expand Up @@ -92,6 +94,8 @@
2469C5031E75DB7600073BEE /* RectNimbleMatcher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RectNimbleMatcher.swift; sourceTree = "<group>"; };
246D36471E6C46F50050F202 /* PinPointCoordinatesSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PinPointCoordinatesSpec.swift; sourceTree = "<group>"; };
2482908B1E78CFFC00667D08 /* RelativePositionSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RelativePositionSpec.swift; sourceTree = "<group>"; };
248E4C721F7A83FA00C0E7F7 /* AspectRatioTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AspectRatioTests.swift; sourceTree = "<group>"; };
248E4C751F7A88CF00C0E7F7 /* UIImage+Color.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIImage+Color.swift"; sourceTree = "<group>"; };
24949A271EF550E2003643D3 /* PinLayoutImpl+Relative.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "PinLayoutImpl+Relative.swift"; sourceTree = "<group>"; };
24949A291EF551D6003643D3 /* PinLayoutImpl+Coordinates.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "PinLayoutImpl+Coordinates.swift"; sourceTree = "<group>"; };
24949A2B1EF55216003643D3 /* PinLayoutImpl+Warning.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "PinLayoutImpl+Warning.swift"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -179,7 +183,6 @@
DFC97CA61E8A8F2C001545D5 /* PinLayout.swift */,
24949A2D1EF69474003643D3 /* PinLayout+Filters.swift */,
24D18D231F3E37DD008129EF /* PinLayoutGlobals.swift */,
24BBE6361F50FADE0091D5E9 /* Percent.swift */,
DFA06B031E8B38B300B6D5E7 /* Impl */,
DF11A3741E834181008B33E5 /* Supporting Files */,
);
Expand All @@ -193,6 +196,7 @@
2469C5011E75D88500073BEE /* BasicView.swift */,
245302061ED05FD000E13F29 /* AccurencyTests.swift */,
2469C4FF1E75D74000073BEE /* AdjustSizeSpec.swift */,
248E4C721F7A83FA00C0E7F7 /* AspectRatioTests.swift */,
240F88BC1F0C042500280FC8 /* JustifyAlignSpec.swift */,
244C6E141E776A0C0074FC74 /* MarginsSpec.swift */,
242723711F008B85006A5C3A /* MinMaxWidthHeightSpec.swift */,
Expand All @@ -205,6 +209,7 @@
2482908B1E78CFFC00667D08 /* RelativePositionSpec.swift */,
242E8DC11EED5982005935FB /* RelativePositionMultipleViewsSpec.swift */,
240F88BF1F0C1ED900280FC8 /* WarningSpec.swift */,
248E4C751F7A88CF00C0E7F7 /* UIImage+Color.swift */,
);
path = Tests;
sourceTree = "<group>";
Expand All @@ -224,6 +229,7 @@
DFA06B031E8B38B300B6D5E7 /* Impl */ = {
isa = PBXGroup;
children = (
24BBE6361F50FADE0091D5E9 /* Percent.swift */,
24A9782D1EE845BB002BD0F1 /* Coordinates.swift */,
DFC97CA41E8A8EB3001545D5 /* PinLayoutImpl.swift */,
24949A291EF551D6003643D3 /* PinLayoutImpl+Coordinates.swift */,
Expand Down Expand Up @@ -500,6 +506,7 @@
240F88BE1F0C066800280FC8 /* JustifyAlignSpec.swift in Sources */,
2469C5001E75D74000073BEE /* AdjustSizeSpec.swift in Sources */,
2482908C1E78CFFC00667D08 /* RelativePositionSpec.swift in Sources */,
248E4C741F7A883800C0E7F7 /* AspectRatioTests.swift in Sources */,
240F88C11F0C1F5000280FC8 /* WarningSpec.swift in Sources */,
242E8DC31EED5AB2005935FB /* RelativePositionMultipleViewsSpec.swift in Sources */,
2469C5041E75DB7600073BEE /* RectNimbleMatcher.swift in Sources */,
Expand All @@ -512,6 +519,7 @@
DF7A36BD1E918301000F9856 /* PinEdgesSpec.swift in Sources */,
244C6E151E776A0C0074FC74 /* MarginsSpec.swift in Sources */,
249EFE891E64FB4C00165E39 /* PinLayoutTests.swift in Sources */,
248E4C771F7A88D200C0E7F7 /* UIImage+Color.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
53 changes: 49 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ Extremely Fast views layouting without auto layout. No magic, pure code, full co
* [Relative positioning](#relative_positioning)
* [Width, height and size](#width_height_size)
* [minWidth, maxWidth, minHeight, maxHeight](#minmax_width_height_size)
* [Aspect Ratio](#aspect_ratio)
* [justify, align](#justify_align)
* [Margins](#margins)
* [Warnings](#warnings)
Expand Down Expand Up @@ -789,6 +790,9 @@ The following example layout the UILabel on the right side of the UIImageView wi

PinLayout has methods to set the view’s minimum and maximum width, and minimum and maximum height.

:pushpin: minWidth/maxWidth & minHeight/maxHeight have the highest priority. Higher than sizes (width/height/size, fitSize, aspectRatio) and edges positioning (top/left/bottom/right). Their values are always fullfilled.


**Methods:**

* **`minWidth(_ width: CGFloat)`**
Expand Down Expand Up @@ -816,9 +820,6 @@ The value specifies the view's maximum height of the view in pixels or in percen
view.pin.top().height(50%).maxHeight(200)
```

:pushpin: minWidth/maxWidth & minHeight/maxHeight have the highest priority. Higher than sizes (width/height/size) and edges positioning (top/left/bottom/right). Their values are always fullfilled.


###### Example:
This example layout a view 20 pixels from the top, and horizontally from left to right with a maximum width of 200 pixels. If the superview is smaller than 200 pixels, the view will take the full horizontal space, but for a larger superview, the view will be centered.

Expand All @@ -837,6 +838,46 @@ This is an equivalent solutions using the `justify()` method. This method is exp

<br/>


## Aspect Ratio <a name="aspect_ratio"></a>
Set the view aspect ratio.
AspectRatio solves the problem of knowing one dimension of an element and an aspect ratio, this is particularly useful for images.

AspectRatio is applied only if a single dimension (either width or height) can be determined, in that case the aspect ratio will be used to compute the other dimension.

* AspectRatio is defined as the ratio between the width and the height (width / height).
* An aspect ratio of 2 means the width is twice the size of the height.
* AspectRatio respects the min (minWidth/minHeight) and the max (maxWidth/maxHeight)
dimensions of an item.

**Methods:**

* **`aspectRatio(_ ratio: CGFloat)`**:
Set the view aspect ratio using a CGFloat. AspectRatio is defined as the ratio between the width and the height (width / height).
* **`aspectRatio(of view: UIView)`**:
Set the view aspect ratio using another UIView's aspect ratio.
* **`aspectRatio()`**:
If the layouted view is an UIImageView, this method will set the aspectRatio using the UIImageView's image dimension. For other types of views, this method as no impact.

###### Usage examples:
```swift
aView.pin.left().width(100%).aspectRatio(2)
imageView.pin.left().width(200).aspectRatio()
```

###### Example:
This example layout an UIImageView at the top and center it horizontally, it also adjust its width to 50%. The view’s height will be adjusted automatically using the image aspect ratio.

![](docs/pinlayout_example_aspectratio.png)

```swift
imageView.pin.top().hCenter().width(50%).aspectRatio()
```


</br>


## justify() / align() <a name="justify_align"></a>

**Methods:**
Expand Down Expand Up @@ -1258,10 +1299,14 @@ This app is available in the `Example` folder. Note that you must do a `pod inst
let percentageValue: CGFloat = 50
view.pin.width(percentageValue%)
```
* For other questions, you can checks already [answered questions here.](https://github.com/mirego/PinLayout/issues?q=is%3Aissue+is%3Aclosed+label%3Aquestion)

<br>


### Contributing, comments, ideas, suggestions, issues, .... <a name="comments"></a>
### Questions, comments, ideas, suggestions, issues, .... <a name="comments"></a>
If you have questions, you can checks already [answered questions here.](https://github.com/mirego/PinLayout/issues?q=is%3Aissue+is%3Aclosed+label%3Aquestion)

For any **comments**, **ideas**, **suggestions**, **issues**, simply open an [issue](https://github.com/mirego/PinLayout/issues).

If you find PinLayout interesting, thanks to **Star** it. You'll be able to retrieve it easily later.
Expand Down
31 changes: 31 additions & 0 deletions Sources/PinLayout.swift
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,37 @@ public protocol PinLayout {
@discardableResult func size(_ percent: Percent) -> PinLayout
@discardableResult func size(of view: UIView) -> PinLayout

/**
Set the view aspect ratio.
AspectRatio is applied only if a single dimension (either width or height) can be determined,
in that case the aspect ratio will be used to compute the other dimension.
* AspectRatio is defined as the ratio between the width and the height (width / height).
* An aspect ratio of 2 means the width is twice the size of the height.
* AspectRatio respects the min (minWidth/minHeight) and the max (maxWidth/maxHeight)
dimensions of an item.
*/
@discardableResult func aspectRatio(_ ratio: CGFloat) -> PinLayout
/**
Set the view aspect ratio using another UIView's aspect ratio.
AspectRatio is applied only if a single dimension (either width or height) can be determined,
in that case the aspect ratio will be used to compute the other dimension.
* AspectRatio is defined as the ratio between the width and the height (width / height).
* AspectRatio respects the min (minWidth/minHeight) and the max (maxWidth/maxHeight)
dimensions of an item.
*/
@discardableResult func aspectRatio(of view: UIView) -> PinLayout
/**
If the layouted view is an UIImageView, this method will set the aspectRatio using
the UIImageView's image dimension.
For other types of views, this method as no impact.
*/
@discardableResult func aspectRatio() -> PinLayout

@available(*, deprecated, message: "You should now use fitSize() instead.")
@discardableResult func sizeToFit() -> PinLayout
@discardableResult func fitSize() -> PinLayout
Expand Down
6 changes: 3 additions & 3 deletions Sources/PinLayoutImpl+Coordinates.swift
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ extension PinLayoutImpl {

internal func validateWidth(_ width: CGFloat, context: Context) -> Bool {
if width < 0 {
warn("the width (\(width)) must be greater than or equal to zero.", context);
warnWontBeApplied("the width (\(width)) must be greater than or equal to zero.", context);
return false
} else {
return true
Expand All @@ -297,7 +297,7 @@ extension PinLayoutImpl {

internal func validateHeight(_ height: CGFloat, context: Context) -> Bool {
if height < 0 {
warn("the height (\(height)) must be greater than or equal to zero.", context);
warnWontBeApplied("the height (\(height)) must be greater than or equal to zero.", context);
return false
} else {
return true
Expand Down Expand Up @@ -338,7 +338,7 @@ extension PinLayoutImpl {
})

guard results.count > 0 else {
warn("no valid references", context)
warnWontBeApplied("no valid references", context)
return nil
}

Expand Down
2 changes: 1 addition & 1 deletion Sources/PinLayoutImpl+Relative.swift
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ extension PinLayoutImpl {
fileprivate func validateRelativeViews(_ relativeViews: [UIView], context: Context) -> [UIView]? {
guard let _ = layoutSuperview(context) else { return nil }
guard relativeViews.count > 0 else {
warn("At least one view must be visible (i.e. UIView.isHidden != true) ", context)
warnWontBeApplied("At least one view must be visible (i.e. UIView.isHidden != true) ", context)
return nil
}

Expand Down
14 changes: 7 additions & 7 deletions Sources/PinLayoutImpl+Warning.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@ extension PinLayoutImpl {
return "\(method)(to: .\(anchor.type.rawValue), of: \(viewDescription(anchor.view)))"
}

internal func warn(_ text: String, _ context: Context) {
internal func warnWontBeApplied(_ text: String, _ context: Context) {
guard Pin.logWarnings else { return }
warn("\(context()) won't be applied, \(text)")
}

internal func warn(_ text: String) {
guard Pin.logWarnings else { return }
displayWarning("PinLayout Warning: \(text)")
Expand All @@ -48,7 +48,7 @@ extension PinLayoutImpl {
displayWarning("PinLayout Conflict: \(context()) won't be applied since it value has already been set to CGSize(width: \(propertyValue.width), height: \(propertyValue.height)).")
}

internal func warnConflict(_ context: Context, _ properties: [String: CGFloat]) {
internal func warnConflict(_ context: Context, _ properties: [String: Any]) {
guard Pin.logWarnings else { return }
var warning = "PinLayout Conflict: \(context()) won't be applied since it conflicts with the following already set properties:"
properties.forEach { (property) in
Expand All @@ -62,22 +62,22 @@ extension PinLayoutImpl {
if let justify = justify {
func context() -> String { return "justify(.\(justify))" }
if !((_left != nil && _right != nil) || (shouldPinEdges && width != nil && (_left != nil || _right != nil || _hCenter != nil))) {
warn("the left and right coordinates must be set to justify the view horizontally.", context)
warnWontBeApplied("the left and right coordinates must be set to justify the view horizontally.", context)
}

if _hCenter != nil {
warn("justification is not applied when hCenter has been set. By default the view will be centered around the hCenter.", context)
warnWontBeApplied("justification is not applied when hCenter has been set. By default the view will be centered around the hCenter.", context)
}
}

if let align = align {
func context() -> String { return "align(.\(align))" }
if !((_top != nil && _bottom != nil) || (shouldPinEdges && height != nil && (_top != nil || _bottom != nil || _vCenter != nil))) {
warn("the top and bottom coordinates must be set to align the view vertically.", context)
warnWontBeApplied("the top and bottom coordinates must be set to align the view vertically.", context)
}

if _vCenter != nil {
warn("alignment is not applied when vCenter has been set. By default the view will be centered around the specified vCenter.", context)
warnWontBeApplied("alignment is not applied when vCenter has been set. By default the view will be centered around the specified vCenter.", context)
}
}
}
Expand Down

0 comments on commit 1b2c341

Please sign in to comment.