iOS7 Autolayout 和 UIImageview 超大
Posted
技术标签:
【中文标题】iOS7 Autolayout 和 UIImageview 超大【英文标题】:iOS7 Autolayout and UIImageview oversized 【发布时间】:2015-01-04 01:16:58 【问题描述】:请在下面查看我的答案,我有一个可行的解决方案
我已经完全重写了代码,所以它更小更整洁,并且达到了相同的结果。
更新:看起来 UIImageView 的内在内容大小在加载大图像时正在调整,这会抛出其布局并使其成为设备窗口和滚动视图宽度的两倍。我需要弄清楚如何解决这个问题。下面的代码做了一个小改动,减少了 UIImageView 的宽度,但不允许我将其设置为窗口宽度的 100%。
[captionImageView setContentCompressionResistancePriority:1 forAxis:UILayoutConstraintAxisHorizontal];
我为我的视图设置了以下内容,我的问题是 UIImageView 内的图像正在推动其包含视图的宽度比设备窗口宽。
我有一个 ViewController,它在 for 循环中加载和添加子视图,一切似乎都在那里工作正常。
在这些子视图中,我尝试使用自动布局来实现以下目标:
添加一个 UIImageView 并使其与父窗口宽度相同
将 UIImage 加载到其中并使用 UIViewContentModeScaleAspectFill 确保图像加载良好且按比例加载。
在这一切下面加载一个 UITextView 在 for 循环中重复这个过程,这样它们就可以很好地堆叠在一起。我在 Visual 格式化语言中使用约束来尝试将 UIImage 视图的大小设置为父视图的宽度,我希望它是设备窗口的宽度。
如果我指定约束如下:
[containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[captionImageView(320)]|" options:0 metrics:metrics views:views]];
然后它工作正常,但这不是理想的解决方案,因为我希望 UIImageView 与设备的宽度齐平,设置固定宽度是不好的做法
如果我像这样指定约束:
[containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[captionImageView]|" options:0 metrics:metrics views:views]];
然后尺寸为 960px 的 UIImage 将强制父容器视图也为该尺寸。
我将自定义视图内容加载到滚动视图中,因此水平滚动很糟糕。
请注意,我使用 UIView 类别来指定 view.translatesAutoresizingMaskIntoConstraints 设置为 NO。
#import "UIView+Autolayout.h"
@implementation UIView (Autolayout)
+(id)autoLayoutView
UIView *view = [self new];
view.translatesAutoresizingMaskIntoConstraints = NO;
return view;
@end
自定义视图的代码如下。关于如何确保 UIImageView 的大小不会超出设备窗口范围的任何想法?
//
// FigCaptionView.m
//
//
// Created by Matthew Finucane on 18/12/2014.
// Copyright (c) 2014 The App. All rights reserved.
//
#import "FigCaptionView.h"
#import "UIView+Autolayout.h"
@interface FigCaptionView()
@end
@implementation FigCaptionView
-(id)initWithData:(NSDictionary *)viewData
if((self = [FigCaptionView autoLayoutView]))
self.figCaptionData = viewData;
return self;
-(void)layoutItems
[self setBackgroundColor:[UIColor redColor]];
/**
* The container view for everything
*/
UIView *containerView = [UIView autoLayoutView];
/**
* Setting up the caption image
*/
UIImageView *captionImageView = [UIImageView autoLayoutView];
[captionImageView setContentMode:UIViewContentModeScaleAspectFill];
/**
* Grabbing the image (not yet the right way to do this)
*/
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://placekitten.com/960/240"] options:0 error:nil]];
dispatch_async(dispatch_get_main_queue(), ^
captionImageView.image = image;
);
);
/**
* Setting up the caption image
*/
UITextView *captionTextView = [UITextView autoLayoutView];
[captionTextView setText:@"Sample paragraph text will go in here. Sample paragraph text will go in here. Sample paragraph text will go in here. Sample paragraph text will go in here. Sample paragraph text will go in here.Sample paragraph text will go in here"];
/**
* Adding the container view
*/
[self addSubview:containerView];
[containerView addSubview:captionImageView];
[containerView addSubview:captionTextView];
[captionTextView setBackgroundColor:[UIColor blueColor]];
/**
* Dictionaries for autolayout: views and metrics
*/
NSDictionary *views = NSDictionaryOfVariableBindings(containerView, captionImageView, captionTextView);
NSDictionary *metrics = @@"imageHeight": @"160.0", @"margin": @"20.0";
/**
* Setting up the constraints for this view
*/
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[containerView]|" options:0 metrics:metrics views:views]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[containerView]|" options:0 metrics:metrics views:views]];
/**
* Container view constraints
*
* The first constraint is the one that might be causing me trouble.
*/
[containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[captionImageView]|" options:0 metrics:metrics views:views]];
[containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[captionTextView]|" options:0 metrics:metrics views:views]];
[containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[captionImageView(imageHeight)][captionTextView]|" options:NSLayoutFormatAlignAllLeft metrics:metrics views:views]];
for(UIView *view in self.subviews)
if([view hasAmbiguousLayout])
NSLog(@"OOPS");
NSLog(@"<%@:0x%0x>", view.description, (int)self);
@end
【问题讨论】:
【参考方案1】:你可以这样处理。
假设ViewA
的宽度等于设备窗口的宽度。在这种情况下,您只需添加一个UIView
。
并使用您在上面处理的常规视图等约束进行设置。
[containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[captionImageView(ViewA)]|" options:0 metrics:metrics views:views]];
希望对您有所帮助。
编辑:
因为我不太确定它是否会以您对我评论的方式起作用。所以我只是展示了我如何处理的代码。
1.设置viewA
_viewA = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds];
2.就像你的 UIImageView 一样处理它(在这种情况下,captionImageView)
[self.view addSubView:_viewA];
[_viewA setTranslatesAutoresizingMaskIntoConstraints:NO];
3.添加到NSDictionaryBinding中
NSDictionary *dictionary = NSDictionaryOfVariableBindings(_textView, _button, _viewA);
4.自定义 VFL 并分配它。
NSString *const KButtonHorizontal = @"|[_button(_viewA)]|";
【讨论】:
您好,感谢您的帮助。我所做的是抓住主屏幕边界并将宽度放入 imageWidth 中,到目前为止似乎已经成功了。我的解决方案没有解决问题,但在某种程度上回避了它。这是我添加的内容。code
CGRect superBounds = [[UIScreen mainScreen] bounds]; NSDictionary *views = NSDictionaryOfVariableBindings(containerView, captionImageView, captionTextView); NSDictionary *metrics = @@"imageWidth": @(superBounds.size.width), @"imageHeight": @"160.0", @"margin": @"20.0";
我觉得很奇怪,即使我将视图的宽度固定在父视图的两侧,这意味着它应该适合窗口的大小,但它会像这样爆炸。我仍然需要弄清楚如何使用约束来控制 UIImageView 的大小。【参考方案2】:
这是解释如何约束滚动视图的技术说明:https://developer.apple.com/library/ios/technotes/tn2154/_index.html
防止滚动视图内容大小增长的一种快速简便的方法是子类化滚动视图并覆盖 -(CGSize)contentSize 以返回窗口宽度和任何超级返回的高度。
【讨论】:
【参考方案3】:我通过子类化 UIImageView 并覆盖intrinsicContentSize() 来返回屏幕大小...更少的代码;)
class CustomImageView: UIImageView
// - MARK: UIView
override func intrinsicContentSize() -> CGSize
// Return current screen size with width adjusted for frame
let width = UIScreen.mainScreen().bounds.width - frame.origin.x
return CGSize(width: width, height: frame.height)
【讨论】:
【参考方案4】:我不一定称这是一个确定的答案,但我能够让它以我想要的方式工作,尽管我采用的解决方案可能不是 100%。
-- Henry T Kirk 提供的答案在描述带有图像视图的自动布局时非常有用。我无法让这个工作 100%,但我会说这是最正确的答案,因为它遵循最佳实践。
--魔兽世界提供的答案也有效。创建一个拉伸到设备窗口宽度 100% 的新视图,并基于此设置 UIImage 的约束将阻止它超出其边界。
我采用的解决方案是创建一个名为 windowBounds 的新 CGRect 变量。从中提取窗口宽度(windowBounds.size.width),我可以将其添加到我的指标中,并将其应用于 imageView 的可视格式化字符串水平规则,从而更正其超级视图的约束。
在为这个视图重构了一些代码之后,我想出了一个更简洁的解决方案,并且还解决了我在放置带有可变字符串内容的 UITextView 时遇到的另一个问题。代码如下。
** FigcaptionView.h **
//
// FigCaptionView.m
// Anna Christoffer
//
// Created by Matthew Finucane on 18/12/2014.
// Copyright (c) 2014 Anna Christoffer. All rights reserved.
//
#import "FigCaptionView.h"
#import "UIView+Autolayout.h"
@interface FigCaptionView()
@property (nonatomic, strong) UIImageView *figCaptionImageView;
@property (nonatomic, strong) UITextView *figCaptionTextView;
@end
@implementation FigCaptionView
@synthesize figCaptionImageView;
@synthesize figCaptionTextView;
-(id)initWithData:(NSDictionary *)viewData
if((self = [FigCaptionView autoLayoutView]))
self.figCaptionData = viewData;
return self;
-(void)loadImage:(NSString *)imageURLPath
//TODO
-(void)addContentViews
[super layoutSubviews];
/**
* Set up and add the subviews to display the content
*/
self.figCaptionImageView = [UIImageView autoLayoutView];
[self.figCaptionImageView setBackgroundColor:[UIColor lightGrayColor]];
[self addSubview:figCaptionImageView];
self.figCaptionTextView = [UITextView autoLayoutView];
[self.figCaptionTextView setScrollEnabled:NO];
[self.figCaptionTextView setText:@"The digital atlas teaches the cartographic and cultural contents with a highly dynamic and visual method. The idea is based on the phenomenon of “cabinets of wonder” from the 16th and 17th century. At this time European discoverers collected during their expeditions various exotic objects and on the turn to Europe replaced the found pieces to a universal collection."];
[self addSubview:figCaptionTextView];
/**
* Then apply the constraints
*/
[self autoLayoutAddConstraints];
-(void)autoLayoutAddConstraints
/**
* Any set up values that we need
*/
CGRect windowBounds = [[UIScreen mainScreen] bounds];
/**
* Dictionary of views and metrics
*/
NSDictionary *views = NSDictionaryOfVariableBindings(self, figCaptionImageView, figCaptionTextView);
NSDictionary *metrics = @@"imageWidth": @(windowBounds.size.width), @"margin": @20.0f;
/**
* Constraints for this view (Vertical and horizontal)
*/
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[figCaptionImageView(imageWidth)]|"
options:0
metrics:metrics
views:views
]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[figCaptionImageView][figCaptionTextView]|"
options:0
metrics:metrics
views:views
]];
/**
* Constraints for the caption image view to maintain ratio
*/
[self.figCaptionImageView addConstraint:[NSLayoutConstraint constraintWithItem:self.figCaptionImageView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:self.figCaptionImageView
attribute:NSLayoutAttributeWidth
multiplier:0.75f
constant:0.0f
]];
/**
* Constraints for the caption text view - horizontal
*/
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[figCaptionTextView]|"
options:0
metrics:metrics
views:views
]];
@end
如果你也想知道,我已经包含了 UIView+Autolayout 的实现
** UIView+Autolayout.m **
//
// UIView+Autolayout.m
// Anna Christoffer
//
// Created by Matthew Finucane on 19/12/2014.
// Copyright (c) 2014 Anna Christoffer. All rights reserved.
//
#import "UIView+Autolayout.h"
@implementation UIView (Autolayout)
+(id)autoLayoutView
UIView *view = [self new];
view.translatesAutoresizingMaskIntoConstraints = NO;
return view;
@end
【讨论】:
【参考方案5】:你可以试试:
[captionImageView setClipsToBounds:YES];
设置宽高比模式后立即尝试...
这可能会有所帮助:Crop UIImage to fit a frame image
编辑
我刚刚提到了 clipToBounds,因为即使使用界面生成器中的自动布局,我的图像在 AspectFill 模式下也存在问题,它们不会尊重图像视图的边界。但似乎您的问题更多地与布局约束有关。
试试这些约束(注意superview旁边的-符号表示为管道|),它只是将默认的aqua空间添加到约束中,它很简单但可能有效:
[containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[captionImageView]-|" options:0 metrics:metrics views:views]];
[containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[captionTextView]|" options:0 metrics:metrics views:views]];
[containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[captionImageView(imageHeight)][captionTextView]|" options:NSLayoutFormatAlignAllLeft metrics:metrics views:views]];
【讨论】:
嘿。我试了一下,不幸的是它没有用。我尝试的另一件事是将captionImageViews框架(frame.size.width)的大小添加到指标中,但返回0,在自动布局世界中我认为这是正确的(?),因为它是长期寻求的在回答了涉及计算框架和边界的杂乱代码之后...... 我也尝试阅读该链接中的内容,但并没有解决问题。根据我对自动布局的理解,它的工作方式不是让子项的内容大小(在本例中为 UIImage 视图)决定父视图的宽度,所以如果我有一个宽度为 960 的大图像,这将 UIImageView 推为该宽度,然后反过来影响 UIImageView 所在的容器 UIview,然后将容器 UIView 宽度向外推,并一直传递到父滚动视图?如果是这种情况,我需要告诉我的 UIImageView 表现如何? 剪辑到边界与问题无关。以上是关于iOS7 Autolayout 和 UIImageview 超大的主要内容,如果未能解决你的问题,请参考以下文章
UISearchBar AutoLayout ios7 错误?
使用 Autolayout 根据宽度的比率设置 UIImage 高度
使用 Autolayout Xcode6 在 Universal Storyboard 中相对于 UIImage 定位 UILabel
如何在 UIScrollView 内使用 Autolayout 将 UIImage 视图缩放为正方形