aspect fit
は、デフォルトで画像をフレームの下部に揃えます。 オーバーライドaspect fit
そのままですか?
**編集**
この質問は自動レイアウトよりも前です。実際、この質問が行われたのと同じ週にWWDC 2012で自動レイアウトが明らかにされていました
つまり、UIImageView
を使用してこれを行うことはできません。
1つの解決策は、UIView
を含むUIImageView
をサブクラス化し、画像サイズに応じてフレームを変更することです。たとえば、1つのバージョンを見つけることができます here 。
これを行う方法は、UIImageViewレイヤーのcontentsRectを変更することです。私のプロジェクト(UIImageViewのサブクラス)の次のコードは、scaleToFillを想定し、デフォルトの中央揃えの代わりに上下左右に揃えるように画像をオフセットします。 aspectFitは同様のソリューションです。
typedef NS_OPTIONS(NSUInteger, AHTImageAlignmentMode) {
AHTImageAlignmentModeCenter = 0,
AHTImageAlignmentModeLeft = 1 << 0,
AHTImageAlignmentModeRight = 1 << 1,
AHTImageAlignmentModeTop = 1 << 2,
AHTImageAlignmentModeBottom = 1 << 3,
AHTImageAlignmentModeDefault = AHTImageAlignmentModeCenter,
};
- (void)updateImageViewContentsRect {
CGRect imageViewContentsRect = CGRectMake(0, 0, 1, 1);
if (self.image.size.height > 0 && self.bounds.size.height > 0) {
CGRect imageViewBounds = self.bounds;
CGSize imageSize = self.image.size;
CGFloat imageViewFactor = imageViewBounds.size.width / imageViewBounds.size.height;
CGFloat imageFactor = imageSize.width / imageSize.height;
if (imageFactor > imageViewFactor) {
//Image is wider than the view, so height will match
CGFloat scaledImageWidth = imageViewBounds.size.height * imageFactor;
CGFloat xOffset = 0.0;
if (BM_CONTAINS_BIT(self.alignmentMode, AHTImageAlignmentModeLeft)) {
xOffset = -(scaledImageWidth - imageViewBounds.size.width) / 2;
} else if (BM_CONTAINS_BIT(self.alignmentMode, AHTImageAlignmentModeRight)) {
xOffset = (scaledImageWidth - imageViewBounds.size.width) / 2;
}
imageViewContentsRect.Origin.x = (xOffset / scaledImageWidth);
} else if (imageFactor < imageViewFactor) {
CGFloat scaledImageHeight = imageViewBounds.size.width / imageFactor;
CGFloat yOffset = 0.0;
if (BM_CONTAINS_BIT(self.alignmentMode, AHTImageAlignmentModeTop)) {
yOffset = -(scaledImageHeight - imageViewBounds.size.height) / 2;
} else if (BM_CONTAINS_BIT(self.alignmentMode, AHTImageAlignmentModeBottom)) {
yOffset = (scaledImageHeight - imageViewBounds.size.height) / 2;
}
imageViewContentsRect.Origin.y = (yOffset / scaledImageHeight);
}
}
self.layer.contentsRect = imageViewContentsRect;
}
class AlignmentImageView: UIImageView {
enum HorizontalAlignment {
case left, center, right
}
enum VerticalAlignment {
case top, center, bottom
}
// MARK: Properties
var horizontalAlignment: HorizontalAlignment = .center
var verticalAlignment: VerticalAlignment = .center
// MARK: Overrides
override var image: UIImage? {
didSet {
updateContentsRect()
}
}
override func layoutSubviews() {
super.layoutSubviews()
updateContentsRect()
}
// MARK: Content layout
private func updateContentsRect() {
var contentsRect = CGRect(Origin: .zero, size: CGSize(width: 1, height: 1))
guard let imageSize = image?.size else {
layer.contentsRect = contentsRect
return
}
let viewBounds = bounds
let imageViewFactor = viewBounds.size.width / viewBounds.size.height
let imageFactor = imageSize.width / imageSize.height
if imageFactor > imageViewFactor {
// Image is wider than the view, so height will match
let scaledImageWidth = viewBounds.size.height * imageFactor
var xOffset: CGFloat = 0.0
if case .left = horizontalAlignment {
xOffset = -(scaledImageWidth - viewBounds.size.width) / 2
}
else if case .right = horizontalAlignment {
xOffset = (scaledImageWidth - viewBounds.size.width) / 2
}
contentsRect.Origin.x = xOffset / scaledImageWidth
}
else {
let scaledImageHeight = viewBounds.size.width / imageFactor
var yOffset: CGFloat = 0.0
if case .top = verticalAlignment {
yOffset = -(scaledImageHeight - viewBounds.size.height) / 2
}
else if case .bottom = verticalAlignment {
yOffset = (scaledImageHeight - viewBounds.size.height) / 2
}
contentsRect.Origin.y = yOffset / scaledImageHeight
}
layer.contentsRect = contentsRect
}
}
ImageViewの下部レイアウト制約の優先順位を最低(つまり250)に設定するだけで、作業が実行されます。
同様の問題がありました。最も簡単な方法は、UIImageViewの独自のサブクラスを作成することでした。サブクラス3プロパティを追加し、内部実装を知らなくても簡単に使用できるようにします。
@property (nonatomic) LDImageVerticalAlignment imageVerticalAlignment;
@property (nonatomic) LDImageHorizontalAlignment imageHorizontalAlignment;
@property (nonatomic) LDImageContentMode imageContentMode;
画像が画面サイズよりも大きい場合、画像は常に「押し上げられる」ため、UIImageViewの高さに制約を設定することにより、Interface Builderでこれをネイティブに解決しました。
具体的には、UIImageViewを(高さの制約を介して)ビューと同じ高さに設定し、UIImageViewをIBの間隔制約で配置しました。これにより、UIImageViewには「アスペクトフィット」が設定され、IBで設定した上部の間隔の制約が引き続き考慮されます。