nfarina / calloutview

A lightweight callout view class for iOS mimicking UICalloutView.
http://nfarina.com/post/78014139253/smcalloutview-for-ios-7
Apache License 2.0
1.2k stars 189 forks source link

ContentView with auto layout #82

Closed amcastror closed 9 years ago

amcastror commented 9 years ago

Hi, has anyone tried to set auto layout constraints inside a contentView? I subclassed SMCalloutView and on init I'm adding them. For now it's a simple UIView with a UILabel inside:

-(void)setupConstraints{    
self.customTitleView.translatesAutoresizingMaskIntoConstraints = NO;
[self.customTitleView setContentCompressionResistancePriority:UILayoutPriorityDefaultHigh forAxis:UILayoutConstraintAxisHorizontal];
[self.customTitleView setContentCompressionResistancePriority:UILayoutPriorityDefaultHigh forAxis:UILayoutConstraintAxisVertical];
[self.customTitleView setContentHuggingPriority:UILayoutPriorityDefaultHigh forAxis:UILayoutConstraintAxisHorizontal];
[self.customTitleView setContentHuggingPriority:UILayoutPriorityDefaultHigh forAxis:UILayoutConstraintAxisVertical];

self.customContentView.translatesAutoresizingMaskIntoConstraints = NO;
[self.customContentView setContentCompressionResistancePriority:UILayoutPriorityDefaultHigh forAxis:UILayoutConstraintAxisHorizontal];
[self.customContentView setContentCompressionResistancePriority:UILayoutPriorityDefaultHigh forAxis:UILayoutConstraintAxisVertical];
[self.customContentView setContentHuggingPriority:UILayoutPriorityDefaultHigh forAxis:UILayoutConstraintAxisHorizontal];
[self.customContentView setContentHuggingPriority:UILayoutPriorityDefaultHigh forAxis:UILayoutConstraintAxisVertical];

[self.customContentView addConstraint:[NSLayoutConstraint constraintWithItem:self.customTitleView
                                                 attribute:NSLayoutAttributeTop
                                                 relatedBy:NSLayoutRelationEqual
                                                    toItem:self.customContentView
                                                 attribute:NSLayoutAttributeTop
                                                multiplier:1.f
                                                  constant:0.f]];
[self.customContentView addConstraint:[NSLayoutConstraint constraintWithItem:self.customTitleView
                                                 attribute:NSLayoutAttributeLeading
                                                 relatedBy:NSLayoutRelationEqual
                                                    toItem:self.customContentView
                                                 attribute:NSLayoutAttributeLeading
                                                multiplier:1.f
                                                  constant:0.f]];
[self.customContentView addConstraint:[NSLayoutConstraint constraintWithItem:self.customTitleView
                                                 attribute:NSLayoutAttributeTrailing
                                                 relatedBy:NSLayoutRelationEqual
                                                    toItem:self.customContentView
                                                 attribute:NSLayoutAttributeTrailing
                                                multiplier:1.f
                                                  constant:0.f]];
[self.customContentView addConstraint:[NSLayoutConstraint constraintWithItem:self.customTitleView
                                                 attribute:NSLayoutAttributeBottom
                                                 relatedBy:NSLayoutRelationEqual
                                                    toItem:self.customContentView
                                                 attribute:NSLayoutAttributeBottom
                                                multiplier:1.f
                                                  constant:0.f]];

[self.customContentView addConstraint:[NSLayoutConstraint constraintWithItem:self.customContentView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.f constant:80.f]];
[self.customContentView addConstraint:[NSLayoutConstraint constraintWithItem:self.customContentView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.f constant:30.f]];
}

But when it appears on the map it has the callout didn't take into account the view's contents. Here's a screenshot of how it looks (the conentView's background color is orange):

captura de pantalla 2015-05-08 a las 19 17 47

Any ideas?? Thanks a lot!

florianbuerger commented 9 years ago

I came across this issue the other day, maybe it is useful for others. You have to set the contentView.frame to the correct size before the call out is shown on the map. Something like this:

// force layout pass on the content view
[contentView setNeedsLayout];
[contentView layoutIfNeeded];

// calculate minimum size required to display all subviews
CGSize compressedSize = [contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
CGRect frame = contentView.frame;
frame.size = compressedSize;
contentView.frame = frame;

// https://github.com/nfarina/calloutview/issues/73
UIView *container = [[UIView alloc] initWithFrame:contentView.frame];
[container addSubview:contentView];
self.calloutView.contentView = container;

I still have no idea why the last part is required but it works pretty well.

Be sure to setup all required constraints inside your custom contentView. The same rules apply as for UITableViewCellCells with dynamic height as described in this wonderful post on Stackoverflow.

amcastror commented 9 years ago

Thanks @florianbuerger, I already finished that proyect but I'll definitely try it out next time.