Skip to content

ksloginov/DrapierLayout

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

DrapierLayout

Helps make layoutSubviews more readable

Examples

A simple view with a UIImageView and two UILabels.

class CustomView: UIView {
	var imageView: UIImageView!
	var titleLabel: UILabel!
	var detailLabel: UILabel!
	
	struct ViewLayout {
		let imageFrame: CGRect
		let titleFrame: CGRect
		let detailFrame: CGRect
	}
	
	func generateLayout(bounds: CGRect) -> ViewLayout {
		// Since a size is not specified, sizeThatFits is called on imageView with a 
		// size of 10,000 x 10,000 this allows the image to be as large as it can.
		var imageFrame = imageView.layout(
			Leading(equalTo: bounds.leading(layoutMargins)),
			Top(equalTo: bounds.top(layoutMargins))
		)
		
		let maximumImageWidth = CGFloat(50.0)
		
		if imageFrame.width > maximumImageWidth {
			// This time a size is specified, this attempts to make sure that the image
			// doesn't push the UILabels off the edge of the parent view.
			imageFrame = imageView.layout(
				Leading(equalTo: bounds.leading(layoutMargins)),
				Top(equalTo: bounds.top(layoutMargins)),
				Width(equalTo: maximumImageWidth),
				Height(equalTo: round(maximumImageWidth * imageFrame.inverseAspectRatio))
			)
		}
		
		// The title fits between the image and the trailing edge of the superview.
		// A capline is the line that marks the top of a capital letter for the 
		// UILabel's current font.
		let titleFrame = titleLabel.layout(
			Leading(equalTo: imageFrame.trailing, constant: 8.0),
			Trailing(equalTo: bounds.trailing(layoutMargins)),
			Capline(equalTo: imageFrame.top)
		)
		
		let detailFrame = detailLabel.layout(
			Leading(equalTo: titleFrame.leading),
			Trailing(equalTo: titleFrame.trailing),
			Capline(equalTo: titleFrame.baseline(font: titleLabel.font), constant: 8.0)
		)
		
		return ViewLayout(
			imageFrame: imageFrame,
			titleFrame: titleFrame,
			detailFrame: detailFrame
		)
	}
	
	override func sizeThatFits(size: CGSize) -> CGSize {
		let layout = generateLayout(size.rect())
		// Find the fitting height from the layout frame that is farthest toward the bottom, then
		// add in the layoutMargin bottom if needed to find the true height.
		let maxBottom = max(layout.imageFrame.bottom, layout.detailFrame.baseline(font: detailLabel.font))
		return CGSize(width: size.width, height: maxBottom + layoutMargins.bottom)
	}
	
	override func layoutSubviews() {
		super.layoutSubviews()
		
		// In most cases the layout code can be shared between sizeThatFits and layoutSubviews.
		let layout = generateLayout(bounds)
		
		imageView.frame = layout.imageFrame
		titleLabel.frame = layout.titleFrame
		detailLabel.frame = layout.detailFrame
	}
}

Contact

Justin Kolb
@nabobnick

License

DrapierLayout is available under the MIT license. See the LICENSE file for more info.

About

Easy Autolayout without the magic

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Swift 92.0%
  • Objective-C 8.0%