내 UIImageView의 경우 Aspect Fit (InterfaceBuilder)을 선택했지만 수직 정렬을 어떻게 변경할 수 있습니까?
내 UIImageView의 경우 Aspect Fit (InterfaceBuilder)을 선택했지만 수직 정렬을 어떻게 변경할 수 있습니까?
답변:
[편집-이 코드는 2011 년부터 약간 곰팡이가 났지만 모두 @ArtOfWarefare의 모드를 통합했습니다]
UIImageView로 이것을 할 수 없습니다. MyImageView
UIImageView를 포함 하는 간단한 UIView 하위 클래스 를 만들었습니다 . 아래 코드.
// 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
initWithCoder
(I 기본적으로 복사 한 initWithFrame
하지만 교체 [super initWithFrame:]
로를 [super initWithCoder:]
) 2 - 나는 라인에서 추가 if (!self.image) return;
로 layoutSubviews
이 유효하지 않은 지오메트리와 충돌하지 않을 것이라고 그렇다면 이미지 ISN ' t가 호출 될 때 할당됩니다. 이 두 가지 작은 변경으로 놀랍게 작동합니다.
dealloc
방법을 제거해야합니다.
스토리 보드를 사용하는 경우 제약 조건으로 달성 할 수 있습니다.
먼저 원하는 최종 프레임 / 제약 조건이있는 UIView입니다. UIView에 UIImageView를 추가하십시오. contentMode를 Aspect Fill로 설정합니다. UIImageView 프레임을 이미지와 동일한 비율로 만듭니다 (이렇게하면 나중에 스토리 보드 경고가 표시되지 않음). 표준 제약 조건을 사용하여 측면을 UIView에 고정합니다. 표준 제약 조건을 사용하여 상단 또는 하단 (정렬하려는 위치에 따라)을 UIView에 고정합니다. 마지막으로 가로 세로 비율 제한을 UIImageView에 추가합니다 (비율을 이미지로 확인).
이미 콘텐츠 모드 ( .scaleAspectFit
)를 선택한 경우 추가 정렬 규칙을 설정할 수있는 옵션이 없기 때문에 약간 까다 롭습니다 .
그러나 여기에 대한 해결 방법이 있습니다.
먼저 크기를 계산하여 소스 이미지의 크기를 명시 적으로 조정해야합니다 ( UIImageView
with 인 경우 contentMode = .scaleAspectFit
).
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
속성에 할당하기 만하면 됩니다. 또한 contentMode
여기 에서 원하는 imageView를 설정했는지 확인 하십시오 ( 또는 Interface Builder에서 )!
let image = UIImage(named: "MySourceImage")
imageView.image = image?.aspectFitImage(inRect: imageView.frame)
imageView.contentMode = .left
개발자 덕분에 이미지 정렬을 변경하기 위해 UIImageViewAligned를 사용했습니다.
나는 이것이 오래된 스레드라는 것을 알고 있지만 누군가가 내가 한 동일한 문제가있는 경우를 대비하여 Interface Builder에서 이미지보기의 상단에서 하단으로 잘린 영역을 쉽게 변경하기 위해 내가 한 일을 공유 할 것이라고 생각했습니다. 내 ViewController의 뷰를 채우는 UIImageView가 있었고 장치 화면의 크기에 관계없이 상단을 동일하게 유지하려고했습니다.
Retina 4 폼 팩터를 적용했습니다 (Editor-> Apply Retina 4 폼 팩터).
높이와 너비를 고정했습니다.
이제 화면 크기가 변경 될 때 UIImageView는 실제로 동일한 크기이며 뷰 컨트롤러는 화면에서 벗어난 부분을 잘라냅니다. 프레임 원점은 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), .scaleFactor(UIScreen.main.scale)])
UIImageView를 서브 클래 싱하고 setImage : 메서드를 재정 의하여이 문제를 해결했습니다. 하위 클래스는 먼저 원본 및 크기에 대한 원래 값을 저장하여 원래 설정된 크기를 경계 상자로 사용할 수 있습니다.
콘텐츠 모드를 UIViewContentModeAspectFit로 설정했습니다. setImage 내부 : 이미지 너비 대 높이 비율을 잡고 이미지와 동일한 비율에 맞게 이미지보기의 크기를 조정했습니다. 크기 조정 후 프레임 속성을 조정하여 이전과 같은 지점에서 이미지보기를 설정 한 다음 super setImage :를 호출했습니다.
결과적으로 프레임이 이미지에 정확히 맞도록 조정 된 이미지 뷰가 생성되므로 aspect fit이 작동하고 이미지 뷰 프레임 속성이 동일한 효과를 얻기 위해 이미지 뷰를 배치하는 데 무거운 작업을 수행합니다.
내가 사용한 코드는 다음과 같습니다.
먼저, 일반적으로 꽤 유용하다고 생각하는 것은 왼쪽, 오른쪽, 위쪽, 아래쪽, 너비, 높이 등과 같은 속성을 통해 뷰에서 프레임 속성을 쉽게 설정할 수있는 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
aspectFit을 달성하고 빈 공간을 제거해야하는 경우
스토리 보드에서 이미지 뷰의 너비 제약을 제거하고 즐기십시오.
class 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에서 크기 조정 후 오른쪽 정렬 된 이미지의 예 :
myUIImageView.contentMode = .ScaleAspectFit
myUIImageView.translatesAutoresizingMaskIntoConstraints = false
myUIImageView.image = UIImage(named:"pizza.png")
가로 세로 크기 조정 된 이미지가 이제 UIImageView에서 오른쪽 정렬됩니다.
+----------------------------------+
| [IMAGE]|
+----------------------------------+
제약 조건을 변경하여 이미지보기 내에서 다르게 정렬합니다.