uIImageViewでは、Aspect Fit(InterfaceBuilder)を選択しますが、垂直方向の配置を変更するにはどうすればよいですか?
[編集-このコードは2011年から少しカビの生えたもので、@ ArtOfWarefareのMODを組み込んだものを除く]
UIImageViewを使用してこれを行うことはできません。 UIImageViewを含む簡単なUIViewサブクラスMyImageView
を作成しました。以下のコード。
// MyImageView.h
#import <UIKit/UIKit.h>
@interface MyImageView : UIView {
UIImageView *_imageView;
}
@property (nonatomic, assign) UIImage *image;
@end
そして
// MyImageView.m
#import "MyImageView.h"
@implementation MyImageView
@dynamic image;
- (id)initWithCoder:(NSCoder*)coder
{
self = [super initWithCoder:coder];
if (self) {
self.clipsToBounds = YES;
_imageView = [[UIImageView alloc] initWithFrame:self.bounds];
_imageView.contentMode = UIViewContentModeScaleAspectFill;
[self addSubview:_imageView];
}
return self;
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.clipsToBounds = YES;
_imageView = [[UIImageView alloc] initWithFrame:self.bounds];
_imageView.contentMode = UIViewContentModeScaleAspectFill;
[self addSubview:_imageView];
}
return self;
}
- (id)initWithImage:(UIImage *)anImage
{
self = [self initWithFrame:CGRectZero];
if (self) {
_imageView.image = anImage;
[_imageView sizeToFit];
// initialize frame to be same size as imageView
self.frame = _imageView.bounds;
}
return self;
}
// Delete this function if you're using ARC
- (void)dealloc
{
[_imageView release];
[super dealloc];
}
- (UIImage *)image
{
return _imageView.image;
}
- (void)setImage:(UIImage *)anImage
{
_imageView.image = anImage;
[self setNeedsLayout];
}
- (void)layoutSubviews
{
if (!self.image) return;
// compute scale factor for imageView
CGFloat widthScaleFactor = CGRectGetWidth(self.bounds) / self.image.size.width;
CGFloat heightScaleFactor = CGRectGetHeight(self.bounds) / self.image.size.height;
CGFloat imageViewXOrigin = 0;
CGFloat imageViewYOrigin = 0;
CGFloat imageViewWidth;
CGFloat imageViewHeight;
// if image is narrow and tall, scale to width and align vertically to the top
if (widthScaleFactor > heightScaleFactor) {
imageViewWidth = self.image.size.width * widthScaleFactor;
imageViewHeight = self.image.size.height * widthScaleFactor;
}
// else if image is wide and short, scale to height and align horizontally centered
else {
imageViewWidth = self.image.size.width * heightScaleFactor;
imageViewHeight = self.image.size.height * heightScaleFactor;
imageViewXOrigin = - (imageViewWidth - CGRectGetWidth(self.bounds))/2;
}
_imageView.frame = CGRectMake(imageViewXOrigin,
imageViewYOrigin,
imageViewWidth,
imageViewHeight);
}
- (void)setFrame:(CGRect)frame
{
[super setFrame:frame];
[self setNeedsLayout];
}
@end
ストーリーボードを使用する場合、これは制約付きで実現できます...
まず、目的の最終フレーム/制約を持つUIView。 UIImageViewをUIViewに追加します。 contentModeをAspect Fillに設定します。 UIImageViewフレームを画像と同じ比率にします(これにより、後でStoryboardの警告が表示されなくなります)。標準の制約を使用して、側面をUIViewに固定します。標準の制約を使用してUIViewに上部OR下部(配置する場所に応じて))を固定します。最後にアスペクト比制約をUIImageViewに追加します(画像としての比率を確認します)。
既にコンテンツモード(.scaleAspectFit
)を選択している場合、さらに整列ルールを設定するオプションがないため、これは少し注意が必要です。
ただし、これを回避する方法は次のとおりです。
最初に、寸法を計算してソース画像のサイズを明示的に変更する必要があります(contentMode = .scaleAspectFit
でUIImageView
にある場合)。
extension UIImage {
func aspectFitImage(inRect rect: CGRect) -> UIImage? {
let width = self.size.width
let height = self.size.height
let aspectWidth = rect.width / width
let aspectHeight = rect.height / height
let scaleFactor = aspectWidth > aspectHeight ? rect.size.height / height : rect.size.width / width
UIGraphicsBeginImageContextWithOptions(CGSize(width: width * scaleFactor, height: height * scaleFactor), false, 0.0)
self.draw(in: CGRect(x: 0.0, y: 0.0, width: width * scaleFactor, height: height * scaleFactor))
defer {
UIGraphicsEndImageContext()
}
return UIGraphicsGetImageFromCurrentImageContext()
}
}
次に、imageViewのフレームを渡すことで元の画像でこの関数を呼び出し、その結果をUIImageView.image
プロパティに割り当てるだけです。また、imageViewの希望するcontentMode
をここで設定してください(またはInterface Builderでも)!
let image = UIImage(named: "MySourceImage")
imageView.image = image?.aspectFitImage(inRect: imageView.frame)
imageView.contentMode = .left
設定してみてください:
imageView.contentMode = UIViewContentModeScaleAspectFit;
imageView.clipsToBounds = YES;
これは私のために働いた。
開発者のおかげで画像の配置を変更するためにUIImageViewAlignedを使用しました
私はこれが古いスレッドであることを知っていますが、私が同じ問題を抱えていた場合に備えて、Interface Builderで画像ビューの上部から下部にクリップ領域を簡単に変更するためにしたことを共有したいと思いました。 ViewControllerのViewを埋めるUIImageViewがあり、デバイスの画面のサイズに関係なく、トップを同じにしようとしていました。
Retina 4フォームファクターを適用しました(Editor-> Apply Retina 4 Form Factor)。
高さと幅を固定しました。
現在、画面のサイズが変更されると、UIImageViewは実際には同じサイズになり、View Controllerは画面の外にあるものをクリップします。フレームの原点は0,0のままなので、画像ではなく、画像の下と右が切り取られます。
お役に立てれば。
最初にスケーリングしてからサイズを変更することでそれを行うことができます。ここで言及することは、私が身長によって条件付けられたことです。つまり、幅に関係なく、高さ34pxのイメージが必要でした。
したがって、実際のコンテンツの高さとビューの高さ(34 px)の比率を取得し、幅もスケーリングします。
以下がその方法です。
CGSize size = [imageView sizeThatFits:imageView.frame.size];
CGSize actualSize;
actualSize.height = imageView.frame.size.height;
actualSize.width = size.width / (1.0 * (size.height / imageView.frame.size.height));
CGRect frame = imageView.frame;
frame.size = actualSize;
[imageView setFrame:frame];
お役に立てれば。
私は次の解決策を思いつきました:
UIImageView
コンテンツモードをtop
に設定します:imageView.contentMode = .top
画像を読み込んでサイズを変更するには、 Kingfisher を使用します。
let size = imageView.bounds.size
let processor = ResizingImageProcessor(referenceSize: size, mode: .aspectFit)
imageView.kf.setImage(with: URL(string: imageUrl), options: [.processor(processor)])
AspectFitを達成し、空のスペースを取り除く必要がある場合
ストーリーボードからイメージビューの幅の制約を削除することを忘れないでください
クラスSelfSizedImageView:UIImageView {
override func layoutSubviews() {
super.layoutSubviews()
guard let imageSize = image?.size else {
return
}
let viewBounds = bounds
let imageFactor = imageSize.width / imageSize.height
let newWidth = viewBounds.height * imageFactor
let myWidthConstraint = self.constraints.first(where: { $0.firstAttribute == .width })
myWidthConstraint?.constant = min(newWidth, UIScreen.main.bounds.width / 3)
layoutIfNeeded()
}}
UIImageViewをサブクラス化し、setImage:メソッドをオーバーライドすることでこれを解決しました。サブクラスは最初にOriginの元の値とサイズを保存し、元のセットサイズを境界ボックスとして使用できるようにします。
コンテンツモードをUIViewContentModeAspectFitに設定します。 setImageの内部:イメージの幅と高さの比率を取得し、イメージと同じ比率に合うようにイメージビューのサイズを変更しました。サイズ変更後、フレームプロパティを調整して、前と同じスポットに画像ビューを設定し、スーパーsetImage:を呼び出しました。
これにより、フレームが画像にぴったり合うように調整された画像ビューが作成されるため、アスペクトフィットが機能し、画像ビューのフレームプロパティは、同じ効果を得るために画像ビューを配置する際に重荷を担います。
私が使用したいくつかのコードは次のとおりです。
まず、一般的にかなり便利だと思うのは、左、右、上、下、幅、高さなどのプロパティを介してビューのフレームプロパティを簡単に設定できるUIViewのカテゴリです。
@interface UIView (FrameAdditions)
@property CGFloat left, right, top, bottom, width, height;
@property CGPoint Origin;
@end
@implementation UIView (FrameAdditions)
- (CGFloat)left {
return self.frame.Origin.x;
}
- (void)setLeft:(CGFloat)left {
self.frame = CGRectMake(left, self.frame.Origin.y, self.frame.size.width, self.frame.size.height);
}
- (CGFloat)right {
return self.frame.Origin.x + self.frame.size.width;
}
- (void)setRight:(CGFloat)right {
self.frame = CGRectMake(right - self.frame.size.width, self.frame.Origin.y, self.frame.size.width, self.frame.size.height);
}
- (CGFloat)top {
return self.frame.Origin.y;
}
- (void)setTop:(CGFloat)top {
self.frame = CGRectMake(self.frame.Origin.x, top, self.frame.size.width, self.frame.size.height);
}
- (CGFloat)bottom {
return self.frame.Origin.y + self.frame.size.height;
}
- (void)setBottom:(CGFloat)bottom {
self.frame = CGRectMake(self.frame.Origin.x, bottom - self.frame.size.height, self.frame.size.width, self.frame.size.height);
}
- (CGFloat)width {
return self.frame.size.width;
}
- (void)setWidth:(CGFloat)width {
self.frame = CGRectMake(self.frame.Origin.x, self.frame.Origin.y, width, self.frame.size.height);
}
- (CGFloat)height {
return self.frame.size.height;
}
- (void)setHeight:(CGFloat)height {
self.frame = CGRectMake(self.frame.Origin.x, self.frame.Origin.y, self.frame.size.width, height);
}
- (CGPoint)Origin {
return self.frame.Origin;
}
- (void)setOrigin:(CGPoint)Origin {
self.frame = CGRectMake(Origin.x, Origin.y, self.frame.size.width, self.frame.size.height);
}
@end
これはUIImageViewのサブクラスです。完全にテストされているわけではありませんが、理解を深める必要があります。これを拡張して、独自の新しい整列モードを設定できます。
@interface BottomCenteredImageView : UIImageView
@end
@interface BottomCenteredImageView() {
CGFloat originalLeft;
CGFloat originalBottom;
CGFloat originalHeight;
CGFloat originalWidth;
}
@end
@implementation BottomCenteredImageView
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if(self) {
[self initialize];
}
return self;
}
- (void)awakeFromNib {
[self initialize];
}
- (void)initialize {
originalLeft = self.frame.Origin.x;
originalHeight = CGRectGetHeight(self.frame);
originalWidth = CGRectGetWidth(self.frame);
originalBottom = self.frame.Origin.y + originalHeight;
}
- (void)setImage:(UIImage *)image {
if(image) {
self.width = originalWidth;
self.height = originalHeight;
self.left = originalLeft;
self.bottom = originalBottom;
float myWidthToHeightRatio = originalWidth/originalHeight;
float imageWidthToHeightRatio = image.size.width/image.size.height;
if(myWidthToHeightRatio >= imageWidthToHeightRatio) {
// Calculate my new width
CGFloat newWidth = self.height * imageWidthToHeightRatio;
self.width = newWidth;
self.left = originalLeft + (originalWidth - self.width)/2;
self.bottom = originalBottom;
} else {
// Calculate my new height
CGFloat newHeight = self.width / imageWidthToHeightRatio;
self.height = newHeight;
self.bottom = originalBottom;
}
self.contentMode = UIViewContentModeScaleAspectFit;
[super setImage:image];
} else {
[super setImage:image];
}
}
@end