Skip to content
Open
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 56 additions & 87 deletions UIImageViewAligned.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import UIKit
public struct UIImageViewAlignmentMask: OptionSet {
public let rawValue: Int
public init(rawValue: Int) { self.rawValue = rawValue }

/// The option to align the content to the center.
public static let center = UIImageViewAlignmentMask(rawValue: 0)
/// The option to align the content to the left.
Expand All @@ -32,11 +32,11 @@ public struct UIImageViewAlignmentMask: OptionSet {
}

@IBDesignable
open class UIImageViewAligned: UIImageView {
open class UIImageViewAligned: UIView {

/**
The technique to use for aligning the image.

Changes to this property can be animated.
*/
open var alignment: UIImageViewAlignmentMask = .center {
Expand All @@ -45,30 +45,30 @@ open class UIImageViewAligned: UIImageView {
updateLayout()
}
}
open override var image: UIImage? {

open var image: UIImage? {
set {
realImageView?.image = newValue
imageView?.image = newValue
setNeedsLayout()
}
get {
return realImageView?.image
return imageView?.image
}
}
open override var highlightedImage: UIImage? {

open var highlightedImage: UIImage? {
set {
realImageView?.highlightedImage = newValue
imageView?.highlightedImage = newValue
setNeedsLayout()
}
get {
return realImageView?.highlightedImage
return imageView?.highlightedImage
}
}

/**
The option to align the content to the top.

It is available in Interface Builder and should not be set programmatically. Use `alignment` property if you want to set alignment outside Interface Builder.
*/
@IBInspectable open var alignTop: Bool {
Expand All @@ -79,10 +79,10 @@ open class UIImageViewAligned: UIImageView {
return getInspectableProperty(.top)
}
}

/**
The option to align the content to the left.

It is available in Interface Builder and should not be set programmatically. Use `alignment` property if you want to set alignment outside Interface Builder.
*/
@IBInspectable open var alignLeft: Bool {
Expand All @@ -93,10 +93,10 @@ open class UIImageViewAligned: UIImageView {
return getInspectableProperty(.left)
}
}

/**
The option to align the content to the right.

It is available in Interface Builder and should not be set programmatically. Use `alignment` property if you want to set alignment outside Interface Builder.
*/
@IBInspectable open var alignRight: Bool {
Expand All @@ -107,10 +107,10 @@ open class UIImageViewAligned: UIImageView {
return getInspectableProperty(.right)
}
}

/**
The option to align the content to the bottom.

It is available in Interface Builder and should not be set programmatically. Use `alignment` property if you want to set alignment outside Interface Builder.
*/
@IBInspectable open var alignBottom: Bool {
Expand All @@ -121,136 +121,105 @@ open class UIImageViewAligned: UIImageView {
return getInspectableProperty(.bottom)
}
}

open override var isHighlighted: Bool {
set {
super.isHighlighted = newValue
layer.contents = nil
}
get {
return super.isHighlighted
}
}


open var isHighlighted: Bool = false

/**
The inner image view.

It should be used only when necessary.
Accessible to keep compatibility with the original `UIImageViewAligned`.
*/
public private(set) var realImageView: UIImageView?
public private(set) var imageView: UIImageView?

private var realContentSize: CGSize {
var size = bounds.size

guard let image = image else { return size }

let scaleX = size.width / image.size.width
let scaleY = size.height / image.size.height

switch contentMode {
case .scaleAspectFill:
let scale = max(scaleX, scaleY)
size = CGSize(width: image.size.width * scale, height: image.size.height * scale)

case .scaleAspectFit:
let scale = min(scaleX, scaleY)
size = CGSize(width: image.size.width * scale, height: image.size.height * scale)

case .scaleToFill:
size = CGSize(width: image.size.width * scaleX, height: image.size.height * scaleY)

default:
size = image.size
}

return size
}

public override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
public override init(image: UIImage?) {
super.init(image: image)

public init(image: UIImage?) {
super.init(frame: .zero)
setup(image: image)
}
public override init(image: UIImage?, highlightedImage: UIImage?) {
super.init(image: image, highlightedImage: highlightedImage)

public init(image: UIImage?, highlightedImage: UIImage?) {
super.init(frame: .zero)
setup(image: image, highlightedImage: highlightedImage)
}

public required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}

open override func layoutSubviews() {
super.layoutSubviews()
layoutIfNeeded()
updateLayout()
}

open override func didMoveToSuperview() {
super.didMoveToSuperview()
layer.contents = nil
}

open override func didMoveToWindow() {
super.didMoveToWindow()
layer.contents = nil
if #available(iOS 11, *) {
let currentImage = realImageView?.image
image = nil
realImageView?.image = currentImage
}
}


private func setup(image: UIImage? = nil, highlightedImage: UIImage? = nil) {
realImageView = UIImageView(image: image ?? super.image, highlightedImage: highlightedImage ?? super.highlightedImage)
realImageView?.frame = bounds
realImageView?.autoresizingMask = [.flexibleWidth, .flexibleHeight]
realImageView?.contentMode = contentMode
addSubview(realImageView!)
imageView = UIImageView(image: image , highlightedImage: highlightedImage)
imageView?.frame = bounds
imageView?.autoresizingMask = [.flexibleWidth, .flexibleHeight]
imageView?.contentMode = contentMode
addSubview(imageView!)
Comment thread
thermech marked this conversation as resolved.
Outdated
}

private func updateLayout() {
let realSize = realContentSize
var realFrame = CGRect(origin: CGPoint(x: (bounds.size.width - realSize.width) / 2.0,
y: (bounds.size.height - realSize.height) / 2.0),
size: realSize)

var realFrame = CGRect(origin: CGPoint(x: (bounds.size.width - realSize.width) / 2.0, y: (bounds.size.height - realSize.height) / 2.0), size: realSize)

if alignment.contains(.left) {
realFrame.origin.x = 0.0
} else if alignment.contains(.right) {
realFrame.origin.x = bounds.maxX - realFrame.size.width
}

if alignment.contains(.top) {
realFrame.origin.y = 0.0
} else if alignment.contains(.bottom) {
realFrame.origin.y = bounds.maxY - realFrame.size.height
}

realImageView?.frame = realFrame.integral

// Make sure we clear the contents of this container layer, since it refreshes from the image property once in a while.
layer.contents = nil
if #available(iOS 11, *) {
super.image = nil
}

imageView?.frame = realFrame.integral
}

private func setInspectableProperty(_ newValue: Bool, alignment: UIImageViewAlignmentMask) {
if newValue {
self.alignment.insert(alignment)
} else {
self.alignment.remove(alignment)
}
}

private func getInspectableProperty(_ alignment: UIImageViewAlignmentMask) -> Bool {
return self.alignment.contains(alignment)
}
Expand Down