iOS7自动布局和UIImageview超大尺寸问题

3
请看下面我的答案,我有一个可行的解决方案。
我已经完全重写了代码,使其更小、更整洁,并实现了相同的结果。
更新:当加载大图时,UIImageView 的固有内容大小被调整,导致其布局失调,使其宽度是设备窗口和滚动视图的两倍。我需要想办法解决这个问题。下面的代码做了一个小改变,减小了 UIImageView 的宽度,但没有让我将其设置为窗口宽度的 100%。
[captionImageView setContentCompressionResistancePriority:1 forAxis:UILayoutConstraintAxisHorizontal];

我设置了我的视图以及其中包含的一个图片UIImageView。该图片使其包含的视图宽度比设备屏幕更宽。我有一个ViewController,通过for循环加载并添加子视图,一切似乎都正常工作。在这些子视图中,我正在尝试使用自动布局来实现以下目标:
  • 添加一个UIImageView并将其宽度与父窗口相同
  • 将UIImage加载到其中,并使用UIViewContentModeScaleAspectFill确保图像加载得好且比例协调。
  • 在此之下加载UITextView
  • 在for循环中重复此过程,以便它们全部堆叠在彼此上方。
我使用Visual Formatting Language中的约束来设置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]];

假设UIImage的大小为960像素,那么它将强制其父容器视图也具有该大小。

我将我的自定义视图内容加载到滚动视图中,因此我们有水平滚动,这不好。

请注意,我正在使用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
5个回答

1
你可以采用以下方式处理。假设 ViewA 的宽度等于设备屏幕的宽度,这种情况下,你只需添加一个 UIView 并设置其约束即可,与你通常处理的视图一样。
[containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[captionImageView(ViewA)]|" options:0 metrics:metrics views:views]];

希望这能帮到你。
编辑:
因为我不太确定按照你对我的评论所说的方式是否有效。所以我只是展示了我处理代码的方式。
1.设置视图A。
_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)]|";

嗨,感谢您的帮助。我所做的是获取主屏幕边界,并将其宽度作为图像宽度放入其中,到目前为止似乎已经解决了问题。我的解决方案并没有解决这个问题,但以某种方式绕过了它。这是我添加的内容。 code CGRect superBounds = [[UIScreen mainScreen] bounds]; NSDictionary *views = NSDictionaryOfVariableBindings(containerView, captionImageView, captionTextView); NSDictionary *metrics = @{@"imageWidth": @(superBounds.size.width), @"imageHeight": @"160.0", @"margin": @"20.0"}; - matfin
我觉得很奇怪,尽管我将一个视图的宽度固定在父视图的两侧,这意味着它应该适合窗口的大小,但它还是会出现问题。我仍然需要弄清楚如何使用约束来控制UIImageView的大小。 - matfin

1

1

我通过子类化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)
    }
}

0

我不会将这称为明确的答案,但我成功地让它按照我想要的方式工作了,尽管我采用的解决方案可能不是100%。

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

-- WorldOfWarcraft提供的答案也有效。创建一个新视图,将其拉伸到设备窗口的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

-1

你可以尝试:

[captionImageView setClipsToBounds:YES];

在设置纵横比模式后立即尝试它...

这可能有所帮助:将UIImage裁剪以适合框架图像

编辑

我之前提到clipToBounds,因为即使从界面构建器中使用自动布局,我在AspectFill模式下也遇到了我的图片问题,它们不会尊重imageview的边界。但似乎您的问题更多与布局约束有关。

尝试这些约束(注意管道|旁边的减号-),它只是将默认的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,在自动布局世界中,我认为这是正确的(?)因为它应该是解决涉及计算框架和边界的混乱代码的答案... - matfin
我也尝试阅读了链接中的内容,但并没有解决问题。根据我对自动布局的理解,它的工作方式是子视图(在这种情况下是UIImage视图)的内容大小决定了父视图的宽度。因此,如果我有一个宽度为960的大图像,它会将UIImageView的宽度推到那个宽度,然后影响包含UIImageView的容器UIView,进而将容器UIView的宽度推出,一直传递到父滚动视图。如果是这种情况,我需要告诉我的UIImageView如何行为? - matfin
裁剪边界与问题无关。 - Henry T Kirk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接