IOS7 Autolayout and UIImageview oversized

See my answer below where I have a working solution

I have completely rewritten the code so it is much smaller and tidier and achieves the same results

Update. It looks like the size of the internal content of the UIImageView adjusts when the large image is loaded, which throws its layout and makes it twice the width of the device window and scroll. I need to figure out how to fix this. The code below made a small change and reduced the width of the UIImageView, but did not allow me to set it to 100% of the window width.

[captionImageView setContentCompressionResistancePriority:1 forAxis:UILayoutConstraintAxisHorizontal];

      

I have the following setup for my views and my problem is that the image inside the UIImageView is pushing the width of its containing view to the width than the device window.

I have a ViewController that loads and adds a subview to a for loop and everything seems to be working fine.

Within these submenus, I am trying to use autostart to achieve the following:

  • Add UIImageView and make it the same width as the parent window

  • Load the UIImage into that and use UIViewContentModeScaleAspectFill to make sure the image loads nicely and proportionally.

  • Load UITextView underneath it all
  • Repeat this process in the for loop so that they all stack well on top of each other.

I am using a constraint in the Visual Formatting Language to try and set the size of the UIImage view to be the width of the parent view, which I want to be the width of the device window.

If I specify the constraint like this:

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

      

Then it works fine, but it is not a perfect solution as I want the UIImageView to be flush with the device width and it is bad practice to set a fixed width

If I specify the constraint like this:

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

      

Then UIImage with let say size 960px will force the parent container view to be the same size.

I have a custom viewable content that loads into a scroll view and so we have horizontal scrolling which is bad.

Note that I am using the UIView category to indicate that view.translatesAutoresizingMaskIntoConstraints is NO.

#import "UIView+Autolayout.h"

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

      

Below is the code for the custom view. Any ideas as to how I can ensure the size of my UIImageView doesn't extend beyond the device 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

      

+3


source to share


5 answers


I wouldn't call this the definitive answer, but I managed to get it to work the way I wanted it, although the solution I went with might not have been 100%.

- The answer provided by Henry T Kirk is very helpful in describing autoplay with images. I couldn't get this to work 100%, but I would say that this is the most correct answer in that it follows best practice.

- The answer provided by WorldOfWarcraft also works. Creating a new view that stretches to 100% of the device window width and setting a UIImage constraint based on that will stop it from stretching beyond its bounds.

The solution I went with was to create a new CGRect variable called windowBounds. By extracting the window width from this (windowBounds.size.width) I was able to add this to my metrics and apply it to the horizontal visual formatting string rule for the imageView, thus fixing the limitation for my supervisor.

After doing some work refactoring the code for this view, I came up with a much more efficient solution that works as well as solves another problem I ran into when hosting a UITextView with variable string content. The code is below.



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

      

If you are wondering too, I have included an implementation for 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

      

0


source


You can handle it this way.

Suppose the width ViewA

is equal to the width of the device window. In this case, you can simply add UIView

. And customize it with constraints like the regular look you processed above.

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

      

Hope for this help.

Edit:

Because I'm not very sure if it will work or not in the way you comment to me. So I just showed the code I am dealing with.

1.set view A



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

      

2. Just contact, you like your UIImageView (in this case captionImageView)

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

      

3. Add it to NSDictionaryBinding

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

      

4. Configure VFL and assign it.

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

      

+1


source


This is a technical note that explains how to restrict scroll view: https://developer.apple.com/library/ios/technotes/tn2154/_index.html

A quick and easy way to prevent the scroll content from increasing in size is to subclass scrollview and override - (CGSize) contentSize to return the width of the windows and any superoutputs for the height.

+1


source


I got this working by subclassing UIImageView and overriding intrinsicContentSize () to return the screen size ... less code;)

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

      

+1


source


You may try:

[captionImageView setClipsToBounds:YES];

      

try right after setting aspect mode ...

this might help: Crop the UIImage to fit the frame image

EDIT

I just said about clipToBounds because even when using autoplay from the UI constructor, I had problems with my images in AspectFill mode, they would not respect the image borders. But it looks like your problem has more to do with layout constraints.

Try these constraints (note the sign - next to the caption labeled pipe |), it just adds the default space to the constraints, it's simple but might work:

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

      

-1


source







All Articles