这是一个允许 Aspect Fit 和 Alignment 属性的自定义类。
它已被标记@IBDesignable
,因此您可以在 Storyboard / Interface Builder 中看到它。
@IBInspectable
属性是:
像选择普通UIImageView
.
有效值为HAlign
"left" "center" "right" 或默认留空(中心)。
有效值为VAlign
"top" "center" "bottom" 或默认留空(中心)。
“方面填充”是On
或Off
(真/假)。如果为 True,图像将被缩放到Aspect Fill
而不是Aspect Fit
.
@IBDesignable
class AlignedAspectFitImageView: UIView {
enum HorizontalAlignment: String {
case left, center, right
}
enum VerticalAlignment: String {
case top, center, bottom
}
private var theImageView: UIImageView = {
let v = UIImageView()
return v
}()
@IBInspectable var image: UIImage? {
get { return theImageView.image }
set {
theImageView.image = newValue
setNeedsLayout()
}
}
@IBInspectable var hAlign: String = "center" {
willSet {
// Ensure user enters a valid alignment name while making it lowercase.
if let newAlign = HorizontalAlignment(rawValue: newValue.lowercased()) {
horizontalAlignment = newAlign
}
}
}
@IBInspectable var vAlign: String = "center" {
willSet {
// Ensure user enters a valid alignment name while making it lowercase.
if let newAlign = VerticalAlignment(rawValue: newValue.lowercased()) {
verticalAlignment = newAlign
}
}
}
@IBInspectable var aspectFill: Bool = false {
didSet {
setNeedsLayout()
}
}
var horizontalAlignment: HorizontalAlignment = .center
var verticalAlignment: VerticalAlignment = .center
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
commonInit()
}
func commonInit() -> Void {
clipsToBounds = true
addSubview(theImageView)
}
override func layoutSubviews() {
super.layoutSubviews()
guard let img = theImageView.image else {
return
}
var newRect = bounds
let viewRatio = bounds.size.width / bounds.size.height
let imgRatio = img.size.width / img.size.height
// if view ratio is equal to image ratio, we can fill the frame
if viewRatio == imgRatio {
theImageView.frame = newRect
return
}
// otherwise, calculate the desired frame
var calcMode: Int = 1
if aspectFill {
calcMode = imgRatio > 1.0 ? 1 : 2
} else {
calcMode = imgRatio < 1.0 ? 1 : 2
}
if calcMode == 1 {
// image is taller than wide
let heightFactor = bounds.size.height / img.size.height
let w = img.size.width * heightFactor
newRect.size.width = w
switch horizontalAlignment {
case .center:
newRect.origin.x = (bounds.size.width - w) * 0.5
case .right:
newRect.origin.x = bounds.size.width - w
default: break // left align - no changes needed
}
} else {
// image is wider than tall
let widthFactor = bounds.size.width / img.size.width
let h = img.size.height * widthFactor
newRect.size.height = h
switch verticalAlignment {
case .center:
newRect.origin.y = (bounds.size.height - h) * 0.5
case .bottom:
newRect.origin.y = bounds.size.height - h
default: break // top align - no changes needed
}
}
theImageView.frame = newRect
}
}
使用此图像:
以下是240 x 240 AlignedAspectFitImageView
背景颜色设置为黄色的外观(因此我们可以看到框架):
也可以通过代码设置属性。例如:
override func viewDidLoad() {
super.viewDidLoad()
let testImageView = AlignedAspectFitImageView()
testImageView.image = UIImage(named: "bkg640x360")
testImageView.verticalAlignment = .bottom
view.addSubview(testImageView)
// set frame / constraints / etc
testImageView.frame = CGRect(x: 40, y: 40, width: 240, height: 240)
}
要显示“Aspect Fill”和“Aspect Fit”之间的区别...
使用此图像:
Aspect Fill: Off
我们用and得到这个结果VAlign: bottom
:
然后用Aspect Fill: On
and得到这个结果HAlign: right
: