iOS7 Autolayout 和 UIImageview 过大

iOS7 Autolayout and UIImageview oversized

请看下面我的回答,我有一个可行的解决方案

我已经完全重写了代码,因此它更小更整洁,并且达到了相同的结果。

更新:加载大图像时,似乎正在调整 UIImageView 的固有内容大小,这会抛出其布局并使其成为设备 window 和滚动视图宽度的两倍。我需要弄清楚如何解决这个问题。下面的代码做了一个小改动,减少了 UIImageView 的宽度,但不允许我将它设置为 window 宽度的 100%。

[captionImageView setContentCompressionResistancePriority:1 forAxis:UILayoutConstraintAxisHorizontal];

我为我的视图设置了以下设置,我的问题是 UIImageView 中的图像将其包含视图的宽度推得比设备宽 window。

我有一个 ViewController 可以在 for 循环中加载和添加子视图,一切似乎都正常。

在这些子视图中,我尝试使用自动布局来实现以下目的:

我在视觉格式化语言中使用约束来尝试将 UIImage 视图的大小设置为父视图的宽度,我希望它是设备 window 的宽度。

如果我指定约束如下:

[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]];

然后 UIImage 的大小假设为 960px 将强制父容器视图也为该大小。

我将我的自定义视图内容加载到滚动视图中,因此水平滚动很糟糕。

请注意,我正在使用 UIView 类别指定 view.translatesAutoresizingMaskIntoConstraints 设置为 NO。

#import "UIView+Autolayout.h"

@implementation UIView (Autolayout)
+(id)autoLayoutView {
    UIView *view = [self new];
    view.translatesAutoresizingMaskIntoConstraints = NO;
    return view;
}
@end

自定义视图的代码如下。关于如何确保 UIImageView 的大小不会超出设备范围的任何想法 window?

//
//  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

你可以试试:

[captionImageView setClipsToBounds:YES];

设置宽高比模式后立即尝试...

这可能有帮助:Crop UIImage to fit a frame image

编辑

我刚才说了 clipToBounds,因为即使使用界面生成器的自动布局,我在 AspectFill 模式下的图像也有问题,它们不会尊重图像视图的边界。但似乎你的问题更多地与布局约束有关。

尝试这些约束(注意 superview 旁边的 - 符号表示为管道 |),它只是将默认 aqua space 添加到约束中,它很简单但可能有效:

[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]];

你可以这样处理。

假设ViewA的宽度等于设备window的width.In这种情况,你可以只添加一个UIView。 并设置约束,就像您在上面处理的通常视图一样。

[containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[captionImageView(ViewA)]|" options:0 metrics:metrics views:views]];

希望对您有所帮助。

编辑:

因为我不太确定它是否会以您对我的评论方式起作用。所以我只是展示了我如何处理的代码。

1.set 向上视图A

_viewA = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds];

2.Just 像你的 UIImageView 一样处理它(在本例中,captionImageView)

[self.view addSubView:_viewA];
[_viewA setTranslatesAutoresizingMaskIntoConstraints:NO];

3.Add 把它变成 NSDictionaryBinding

NSDictionary *dictionary = NSDictionaryOfVariableBindings(_textView, _button, _viewA);

4.Custom VFL 并赋值。

NSString *const KButtonHorizontal = @"|[_button(_viewA)]|";

这是解释如何限制滚动视图的技术说明:https://developer.apple.com/library/ios/technotes/tn2154/_index.html

防止滚动视图内容大小增长的一种快速简便的方法是将滚动视图子类化并覆盖 -(CGSize)contentSize 到 return windows 宽度和任何超级 returns 代表身高。

我不一定会称这是一个明确的答案,但我能够让它以我想要的方式工作,尽管我采用的解决方案可能不是 100%。

-- Henry T Kirk 提供的答案在描述带有图像视图的自动布局方面非常有用。我无法使它 100% 正常工作,但我会说这是最正确的答案,因为它遵循最佳实践。

-- WorldOfWarcraft 提供的答案也有效。创建一个拉伸到设备宽度 100% 的新视图 window,并基于此设置 UIImage 的约束将阻止它拉伸超出其范围。

我采用的解决方案是创建一个名为 windowBounds 的新 CGRect 变量。从中提取 window 宽度 (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

我通过对 UIImageView 进行子类化并将 intrinsicContentSize() 覆盖为 return 屏幕尺寸来实现此功能...更少的代码 ;)

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)
    }
}