uilabel custom positioning with constraints in uipickerview - objective-c

I want to have custom UILabel inside UIPickerView which is right aligned and with width = half of the screen width:
How to position everything with NSConstraints? I had some problems since UILabel was not attached to super view when I have a chance to modify it.
I managed to get it working but it is not done with NSConstraints and is probably wrong (I was able to set up frame if I embeded UILabel inside another view). Any suggestions how to do it properly?
- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view
{
CGFloat width = [UIScreen mainScreen].bounds.size.width;
UIView * newView = [[UIView alloc] init];
UILabel *lbl = [[UILabel alloc] initWithFrame:CGRectMake(0, 0.0f, width / 2 + 18, [pickerView rowSizeForComponent:component].height)];
lbl.text = [self.datasource objectAtIndex:row];
lbl.textAlignment = NSTextAlignmentRight;
lbl.font=[UIFont CPGeneralFontWithSize:22];
[newView addSubview:lbl];
return newView;
}

I don't think there's anything wrong with the way you're adding your label. The view returned by viewForRow:forComponent: is the same width as the picker view by default, so adding the label as a subview is the correct way to get the look you want. If you want to add the label using constraints, you can do it like this,
- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view {
UIView * newView = [[UIView alloc] init];
UILabel *lbl = [[UILabel alloc] init];
lbl.translatesAutoresizingMaskIntoConstraints = NO;
lbl.backgroundColor = [UIColor redColor];
lbl.text = self.datasource[row];
lbl.textAlignment = NSTextAlignmentRight;
lbl.font=[UIFont PGeneralFontWithSize:22];
[newView addSubview:lbl];
[newView addConstraint:[NSLayoutConstraint constraintWithItem:lbl attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:newView attribute:NSLayoutAttributeLeft multiplier:1 constant:0]];
[newView addConstraint:[NSLayoutConstraint constraintWithItem:lbl attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:newView attribute:NSLayoutAttributeWidth multiplier:0.5 constant:0]];
[newView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[lbl]|" options:0 metrics:nil views:#{#"lbl":lbl}]];
return newView;
}

Related

Programmatically created NSTableView within NSScroll view cannot scroll horizontally

I am on macOS 10.16 (BigSur) XCode 12, objective-c.
I have create a NSTableView within an NSScroll View programmatically and filled it with dummy data.
I CAN scroll down while i CANNOT scroll left and right. So i assume there's some misconfiguration in the code but i can't figure it out.
Here's the behaviour -as you can see theres more content on the right, but scrollbar doesn't scroll:
And here's the code:
NSEdgeInsets insets = NSEdgeInsetsMake (0,0,0,0); // This is usually dynamic, just for demo purposes
NSEdgeInsets margins = NSEdgeInsetsMake (0,0,0,0); // This is usually dynamic, just for demo purposes
// Create tableView
NSTableView* tableView = [[NSTableView alloc] initWithFrame:NSZeroRect];
tableView.translatesAutoresizingMaskIntoConstraints = NO;
tableView.backgroundColor = [NSColor clearColor];
tableView.delegate = self.delegate ? self.delegate : weakSelf;
tableView.dataSource = self.delegate ? self.delegate : weakSelf;
tableView.rowHeight = [SHDataTableCellView height];
tableView.intercellSpacing = NSMakeSize(2, 2);
tableView.headerView = [[NSTableHeaderView alloc] initWithFrame:NSMakeRect(0, 0, 0, CGFLOAT_MIN)];
if (#available(macOS 11.0, *)) {tableView.style = NSTableViewStylePlain;}
self.tableView = tableView;
// Create Scroll View
NSScrollView* scrollView = [[NSScrollView alloc] initWithFrame:NSZeroRect];
// Setup scrollView
scrollView.drawsBackground = NO;
scrollView.hasVerticalScroller = YES;
scrollView.hasHorizontalScroller = YES;
scrollView.autohidesScrollers = NO;
scrollView.translatesAutoresizingMaskIntoConstraints = NO;
scrollView.documentView = tableView;
scrollView.scrollerStyle = NSScrollerKnobStyleDefault;
scrollView.automaticallyAdjustsContentInsets = NO;
scrollView.contentInsets = insets;
scrollView.scrollerInsets = NSEdgeInsetsMake(-(insets.top), -(insets.left), -(insets.bottom), -(insets.right));
self.scrollView = scrollView;
[self.view addSubview:scrollView];
// Add constraints
NSDictionary *viewBindings = NSDictionaryOfVariableBindings(view,scrollView);
NSDictionary *metrics = #{ #"marginLeft" : #(margins.left),
#"marginRight" : #(margins.right),
#"marginBottom" : #(margins.bottom),
#"marginTop" : #(margins.top),
#"insetLeft" : #(insets.left),
#"insetRight" : #(insets.right),
#"insetBottom" : #(insets.bottom),
#"insetTop" : #(insets.top)};
[view addConstraints: [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-(marginLeft)-[scrollView]-(marginRight)-|" options:0 metrics:metrics views:viewBindings]];
[view addConstraints: [NSLayoutConstraint constraintsWithVisualFormat:#"V:|-(marginTop)-[scrollView]-(marginBottom)-|" options:0 metrics:metrics views:viewBindings]];
[scrollView addConstraint:[NSLayoutConstraint constraintWithItem:self.tableView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:scrollView
attribute:NSLayoutAttributeWidth
multiplier:1.0
constant:0]];
[scrollView addConstraint:[NSLayoutConstraint constraintWithItem:scrollView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:60]]; // equals 2 rows of content
NSEdgeInsets margin and insets are set to 0 in this example are tend to be used as dynamic variables (you may ignore them)
Removed the width constraint and it worked. Sometimes its just too obvious and you still don't see it.

Content in Table cell of iOS 8 is not display

Everything works well in iOS 9.
But in iOS 8, the content is not displayed, only imageview is showed.
What i did is that I create a view and add label and UIImage to that view. Then that view is added to contentView of table Cell
create View
- (UIView *)getHeaderView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, tableView.frame.size.width, HEADER_SECTION_HEIGHT)];
[view setBackgroundColor:[[RNThemeManager sharedManager] colorWithHexString:[_themeComponent valueForKey:#"Layer1Color"]]];
UILabel *taskName = [[UILabel alloc] initWithFrame:CGRectMake(5.0, SECTION_BREAK+3.0, view.frame.size.width-23.0, 20)];
[taskName setFont:[UIFont boldSystemFontOfSize:[[_themeComponent valueForKey:#"RegularFontSize"] intValue]]];
[taskName setText:combinedTask.taskDescription];
[taskName setTextColor: [[RNThemeManager sharedManager] colorWithHexString:[_themeComponent valueForKey:#"textPrimary"]]];
[view addSubview:taskName];
UIImageView *addressView = [[UIImageView alloc]initWithFrame:CGRectMake(5.0, SECTION_BREAK+28.0, 20, 20)];
addressView.image = [UIImage imageNamed:[NSString stringWithFormat:#"%#.png", #"Attr_Pin"]];
[view addSubview:addressView];
UILabel *address = [[UILabel alloc] initWithFrame:CGRectMake(35.0, SECTION_BREAK+23.0, view.frame.size.width-35.0, 30)];
[address setFont:[UIFont boldSystemFontOfSize:[[_themeComponent valueForKey:#"SmallFontSize"] intValue]]];
address.lineBreakMode = NSLineBreakByWordWrapping;
address.numberOfLines = 0;
[address setText:[NSString stringWithFormat:#"%#", unit]];
[address setTextColor: [[RNThemeManager sharedManager] colorWithHexString:[_themeComponent valueForKey:#"textPrimary"]]];
[view addSubview:address];
return view;
}
Add view to table cell
UIView *header= [self getHeaderView:tableView viewForHeaderInSection:section];
cell.taskIdLabel.hidden = YES;
[cell.contentView addSubview:header];
Anyone has any ideas? Thanks much for your help.
This is because iOS 9 Apple handle good autolayout than before.
Let add [cell layoutIfNeeded] before return cell.
Update
I have same problem before. Here is block of code that i use to solved my problem.
- (void) sizeHeaderToFit {
//call in viewLayoutSubView
UIView *myHeaderView = self.tableView.tableHeaderView;
[myHeaderView setNeedsLayout];
[myHeaderView layoutIfNeeded];
CGFloat height = [myHeaderView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
myHeaderView.frame = ({
CGRect headerFrame = myHeaderView.frame;
headerFrame.size.height = height;
headerFrame;
});
self.tableView.tableHeaderView = myHeaderView;
}
call it at viewDidLayoutSubView. Hope it helps bạn :))

iOS7.0 and iOS 7.1 doesn't honor Dynamic tableview Height

I have used autolayout in various implementations for UITableViewCell, the approach being let the intrinsic size define the size and which in turn will provide height for tableview rows.
Strangely but targeting iOS7 and above with Autolayout in UITableViewCell isn't working as desired.
To fix one of the other issues where tableview cells became squeezed (on iOS8 and above) I added following check
if (NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_7_1 ){
self.tblvChatList.rowHeight = UITableViewAutomaticDimension;
self.tblvChatList.estimatedRowHeight = 44;
}
The only other tableview methods that I have used are
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if ([self.arrDataSource count] > ZERO_VALUE) {
self.tblvChatList.backgroundView = nil;
self.tblvChatList.separatorStyle = UITableViewCellSeparatorStyleNone;
return [self.arrDataSource count];
}
else {
// Display a message when the table is empty
if (!viewTableBackground) {
self.viewTableBackground = [[UIView alloc] initWithFrame:self.tblvChatList.bounds];
UIImageView* imgConChatLogo = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"IconConChatTheme"]];
[imgConChatLogo setContentMode:UIViewContentModeCenter];
[imgConChatLogo setTranslatesAutoresizingMaskIntoConstraints:NO];
UILabel* lblNoListDataError = [[UILabel alloc] initWithFrame:CGRectMake(ZERO_VALUE, ZERO_VALUE,
(2*self.view.bounds.size.width)/3, self.view.bounds.size.height)];
lblNoListDataError.text = NSLocalizedString(#"STR_WRITE_SOMETHING_TO_MATCH",
#"No data is currently available. Please pull down to refresh.");
[lblNoListDataError setTranslatesAutoresizingMaskIntoConstraints:NO];
lblNoListDataError.textColor = [UIColor lightGrayColor];
lblNoListDataError.numberOfLines = ZERO_VALUE;
lblNoListDataError.textAlignment = NSTextAlignmentCenter;
lblNoListDataError.font = [Theme fontForRegularBody];
[lblNoListDataError sizeToFit];
[viewTableBackground addSubview:lblNoListDataError];
[viewTableBackground addSubview:imgConChatLogo];
[viewTableBackground addConstraint:
[NSLayoutConstraint constraintWithItem:imgConChatLogo
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:viewTableBackground
attribute:NSLayoutAttributeCenterX
multiplier:1
constant:0]];
[viewTableBackground addConstraint:
[NSLayoutConstraint constraintWithItem:lblNoListDataError
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:viewTableBackground
attribute:NSLayoutAttributeCenterX
multiplier:1
constant:0]];
[viewTableBackground addConstraint:
[NSLayoutConstraint constraintWithItem:imgConChatLogo
attribute:NSLayoutAttributeBaseline
relatedBy:NSLayoutRelationEqual
toItem:viewTableBackground
attribute:NSLayoutAttributeCenterY
multiplier:1
constant:-10]];
[viewTableBackground addConstraint:
[NSLayoutConstraint constraintWithItem:lblNoListDataError
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:viewTableBackground
attribute:NSLayoutAttributeCenterY
multiplier:1
constant:10]];
}
self.tblvChatList.backgroundView = self.viewTableBackground;
self.tblvChatList.separatorStyle = UITableViewCellSeparatorStyleNone;
}
return ZERO_VALUE;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell* cell = nil;
NSUInteger userId = [[NSUserDefaults standardUserDefaults] integerForKey:#"USER_ID"];
ChatMessage* message = (ChatMessage*)[self.arrDataSource objectAtIndex:indexPath.row];
if (userId == [message messageSenderId]) {
static NSString* reuseIdentifierReceiverCell = #"ChatReceiverCustomCell";
cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifierReceiverCell forIndexPath:indexPath];
[(ChatReceiverCell*)cell showMessage:message];
}
else {
static NSString* reuseIdentifierSenderCell = #"ChatSenderCustomCell";
cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifierSenderCell forIndexPath:indexPath];
// Configure the cell...
[(ChatSenderCell*)cell showMessage:message];
}
return cell;
}
I haven't used either estimateHeightForRowAtIndexPath: or heightForRowAtIndexPath: and let the content decide the height for tableviewRow.
Issue:
Why the tableView cells are all squeezed up when running on iOS7, iOS7.1 (Simulator and devices) but show perfectly on iOS8 and above for same content for the same content.
To fix this squeezing, If I implement estimatedHeightForRowAtIndexPath: then not implementing heightForRowAtIndexPath: results in a crash on iOS7. Is there are way to let tableview infer the row height from the autolayout system itself (As derived from intrinsic content size of UILabel with extra padding kept in consideration as I have added required margins) ?
The autolayout constrains for UILabel inside the cell are as follows

How do I add an NSTextView to an NSScrollView?

This document. explains how to programmatically add an NSTextview (that can scroll) to a window. However, how do I programmatically add an NSTextView into an NSScrollView?
EDIT: Here's is the code that works with windows. I want to be able to programmatically insert an NSTextView into a NSScrollView I created with Interface Builder
-(IBAction)drawTextViews:(id)sender {
NSScrollView *scrollview = [[NSScrollView alloc]
initWithFrame:[[theWindow contentView] frame]];
NSSize contentSize = [scrollview contentSize];
NSTextView *theTextView = [[NSTextView alloc] initWithFrame:NSMakeRect(0, 0,
contentSize.width, contentSize.height)];
[theTextView setMinSize:NSMakeSize(0.0, contentSize.height)];
[theTextView setMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
[theTextView setVerticallyResizable:YES];
[theTextView setHorizontallyResizable:NO];
[theTextView setAutoresizingMask:NSViewWidthSizable];
[[theTextView textContainer]
setContainerSize:NSMakeSize(contentSize.width, FLT_MAX)];
[[theTextView textContainer] setWidthTracksTextView:YES];
[scrollview setDocumentView:theTextView];
[theWindow setContentView:scrollview];
[theWindow makeKeyAndOrderFront:nil];
[theWindow makeFirstResponder:theTextView];*/
[[theTextView enclosingScrollView] setHasHorizontalScroller:YES];
[theTextView setHorizontallyResizable:YES];
[theTextView setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
[[theTextView textContainer] setContainerSize:NSMakeSize(FLT_MAX, FLT_MAX)];
[[theTextView textContainer] setWidthTracksTextView:NO];
As pointed out in the comments you can achieve an NSTextView within the scroll view by setting it as document view. If you want the textview only to take up a small part of the scroll view you have to construct that in another way. What is the goal you want to achieve?
I also had issues with programmatic creation of scrollable NSTextView. Based on my attempts I have created working example app: How to create scrollable NSTextView programmatically?.
Here is relevant code:
- (void)viewDidLoad {
[super viewDidLoad];
CGFloat margin = 20;
NSRect scrollViewRect = NSMakeRect(
margin,
margin,
self.view.bounds.size.width - margin * 2,
self.view.bounds.size.height - margin * 2
);
NSScrollView *scrollview = [[NSScrollView alloc] initWithFrame:scrollViewRect];
scrollview.backgroundColor = [[NSColor blueColor] colorWithAlphaComponent:0.2];
scrollview.drawsBackground = YES;
NSSize contentSize = [scrollview contentSize];
scrollview.borderType = NSGrooveBorder;
scrollview.hasVerticalScroller = YES;
scrollview.hasHorizontalScroller = NO;
scrollview.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
NSTextView *theTextView = [[NSTextView alloc] initWithFrame:scrollview.bounds];
theTextView.drawsBackground = NO;
theTextView.minSize = NSMakeSize(0.0, contentSize.height);
theTextView.maxSize = NSMakeSize(CGFLOAT_MAX, CGFLOAT_MAX);
theTextView.verticallyResizable = YES;
theTextView.horizontallyResizable = NO;
theTextView.autoresizingMask = NSViewWidthSizable;
theTextView.textContainer.containerSize = NSMakeSize(contentSize.width, CGFLOAT_MAX);
theTextView.textContainer.widthTracksTextView = YES;
NSString *string = #"Once upon a time there was a little-known patent clerk in Bern who received a disappointing annual performance review in ’05";
[theTextView insertText:string replacementRange:NSMakeRange(0, 0)];
scrollview.documentView = theTextView;
[self.view addSubview:scrollview];
}

UIScrollView showing only part of UIView after rotation

This is my first post to Stack Overflow, and I'm a iOS beginner, so please bear with me!
I have an example app where I have three UIViews (headerView, scrollViewContainer, and bodyView) in a parent UIView (topView), and all of these views are created in code. The topView is added to a UIScrollView (pageScrollView) created in storyboard.
pageScrollView is filling the full screen of an iPhone, and I used Autolayout. The app only contains the ViewController.h and companioning .m-file seen below, plus Appdelegate.x. I think I used the single view application template to start with. I'm using iOS 6 and Xcode 4.6, but I also tried 4.5.
I've tried to remove as much as possible of other code that's irrelevant to this problem.
The problem:
When the app starts it shows all its views correctly, and the scrollView allows to view all three views as intended. But after rotating to landscape, the scrollView somehow offsets the content. For example: Stay at top and rotate = content looks OK, but scroll down a bit and rotate makes the top of the content not to show.
What I have tried: I've searched the net for help, but I haven't found anything that seemed to help me. I've added logging of various data like origin, and contentSize, and also tried to set some of them but without any success. I also used 'po [[UIWindow keyWindow] _autolayoutTrace]' to ensure that the constraints are OK.
I can't see what I'm doing wrong. Are there any obvious things missing in my code?
Thanks in advance!
Here's the ViewController.m:
#import "ViewController.h"
#interface ViewController ()
{
UIView *topView;
UIView *headerView;
UIView *bodyView;
UIView *scrollViewContainer;
UIInterfaceOrientation newOrientation;
CGFloat bodyViewHeight;
CGSize newBounds;
float pictureScrollHeight;
}
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
newBounds = [self sizeInOrientation:[UIApplication sharedApplication].statusBarOrientation];
newOrientation = [UIApplication sharedApplication].statusBarOrientation;
bodyViewHeight = 1200; // The height of the body view varies in size depending on orientation
self.pageScrollView.translatesAutoresizingMaskIntoConstraints = NO;
topView = [[UIView alloc] init];
[topView setBackgroundColor:[UIColor clearColor]];
topView.translatesAutoresizingMaskIntoConstraints = NO;
[self.pageScrollView addSubview:topView];
headerView = [[UIView alloc] init];
[headerView setBackgroundColor:[UIColor redColor]];
headerView.translatesAutoresizingMaskIntoConstraints = NO;
[topView addSubview:headerView];
scrollViewContainer = [[UIView alloc] init];
[scrollViewContainer setBackgroundColor:[UIColor blueColor]];
scrollViewContainer.translatesAutoresizingMaskIntoConstraints = NO;
[topView addSubview:scrollViewContainer];
bodyView = [[UIView alloc] init];
[bodyView setBackgroundColor:[UIColor greenColor]];
bodyView.translatesAutoresizingMaskIntoConstraints = NO;
[topView addSubview:bodyView];
[self updateViewConstraints];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
}
- (void)updateViewConstraints
{
[super updateViewConstraints];
// Remove old constraints
[self.view removeConstraints:self.view.constraints];
[self.pageScrollView removeConstraints:self.pageScrollView.constraints];
[topView removeConstraints:topView.constraints];
[scrollViewContainer removeConstraints:scrollViewContainer.constraints];
if ((newOrientation == UIDeviceOrientationLandscapeLeft) || (newOrientation == UIDeviceOrientationLandscapeRight)) {
pictureScrollHeight = 300;
} else {
pictureScrollHeight = 203;
}
[headerView setNeedsDisplay];
[bodyView setNeedsDisplay];
CGFloat topViewHeight = bodyViewHeight + 55 + pictureScrollHeight;
//self.pageScrollView = _pageScrollView
NSDictionary *viewsDict = NSDictionaryOfVariableBindings(_pageScrollView, topView, headerView, bodyView, scrollViewContainer);
NSDictionary *metricsDict = #{#"topViewHeight": [NSNumber numberWithFloat:topViewHeight],
#"newBoundsWidth": [NSNumber numberWithFloat:newBounds.width],
#"pictureScrollHeight": [NSNumber numberWithFloat:pictureScrollHeight],
#"bodyViewHeight": [NSNumber numberWithFloat:bodyViewHeight]};
// pageScrollView - child to self.view
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-0-[_pageScrollView]-0-|" options:0 metrics:nil views:viewsDict]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-0-[_pageScrollView]-0-|" options:0 metrics:nil views:viewsDict]];
// topView - child to pageScrollView
[self.pageScrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-0-[topView(newBoundsWidth)]-0-|" options:0 metrics:metricsDict views:viewsDict]];
[self.pageScrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-0-[topView(topViewHeight)]-0-|" options:0 metrics:metricsDict views:viewsDict]];
// headerView - child to topView
[topView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-0-[headerView]-0-|" options:0 metrics:nil views:viewsDict]];
[topView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-0-[headerView(55.0)]" options:0 metrics:nil views:viewsDict]];
// scrollViewContainer - child to topView
[topView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-0-[scrollViewContainer]-0-|" options:0 metrics:nil views:viewsDict]];
[topView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:[headerView]-0-[scrollViewContainer(pictureScrollHeight)]" options:0 metrics:metricsDict views:viewsDict]];
// bodyView - child to topView
[topView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-0-[bodyView]-0-|" options:0 metrics:nil views:viewsDict]];
[topView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:[scrollViewContainer]-0-[bodyView(bodyViewHeight)]-0-|" options:0 metrics:metricsDict views:viewsDict]];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
newOrientation = toInterfaceOrientation;
newBounds = [self sizeInOrientation:toInterfaceOrientation];
}
-(CGSize) sizeInOrientation:(UIInterfaceOrientation)orientation
{
CGSize size = [UIScreen mainScreen].bounds.size;
UIApplication *application = [UIApplication sharedApplication];
if (UIInterfaceOrientationIsLandscape(orientation))
{
size = CGSizeMake(size.height, size.width);
}
if (application.statusBarHidden == NO)
{
size.height -= MIN(application.statusBarFrame.size.width, application.statusBarFrame.size.height);
}
return size;
}
#end
First of all you do not need to recreate all constraints in -updateViewConstraints method. You need to just update them in this place.
To achieve your aim do the following:
Create your constraints only once. For example in method -setupConstraints. And keep reference to those that need to be updated. See code below.
In method -updateViewConstraints just update topView height and width constraints and height for scrollViewContainer.
Here's the ViewController.m should look like:
#import "ViewController.h"
#interface ViewController ()
#property (nonatomic, strong) IBOutlet UIScrollView* pageScrollView;
#property (nonatomic, strong) NSLayoutConstraint* pictureHeightConstraint;
#property (nonatomic, strong) NSLayoutConstraint* topViewWidthConstraint;
#property (nonatomic, strong) NSLayoutConstraint* topViewHeightConstraint;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
newBounds = [self sizeInOrientation:[UIApplication sharedApplication].statusBarOrientation];
newOrientation = [UIApplication sharedApplication].statusBarOrientation;
bodyViewHeight = 1200; // The height of the body view varies in size depending on orientation
self.pageScrollView.translatesAutoresizingMaskIntoConstraints = NO;
topView = [[UIView alloc] init];
[topView setBackgroundColor:[UIColor clearColor]];
topView.translatesAutoresizingMaskIntoConstraints = NO;
[self.pageScrollView addSubview:topView];
headerView = [[UIView alloc] init];
[headerView setBackgroundColor:[UIColor redColor]];
headerView.translatesAutoresizingMaskIntoConstraints = NO;
[topView addSubview:headerView];
scrollViewContainer = [[UIView alloc] init];
[scrollViewContainer setBackgroundColor:[UIColor blueColor]];
scrollViewContainer.translatesAutoresizingMaskIntoConstraints = NO;
[topView addSubview:scrollViewContainer];
bodyView = [[UIView alloc] init];
[bodyView setBackgroundColor:[UIColor greenColor]];
bodyView.translatesAutoresizingMaskIntoConstraints = NO;
[topView addSubview:bodyView];
[self setupConstraints];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
}
- (void)setupConstraints {
// Remove old constraints
[self.view removeConstraints:self.view.constraints];
[self.pageScrollView removeConstraints:self.pageScrollView.constraints];
[topView removeConstraints:topView.constraints];
[scrollViewContainer removeConstraints:scrollViewContainer.constraints];
if ((newOrientation == UIDeviceOrientationLandscapeLeft) || (newOrientation == UIDeviceOrientationLandscapeRight)) {
pictureScrollHeight = 300;
} else {
pictureScrollHeight = 203;
}
[headerView setNeedsDisplay];
[bodyView setNeedsDisplay];
CGFloat topViewHeight = bodyViewHeight + 55 + pictureScrollHeight;
//self.pageScrollView = _pageScrollView
NSDictionary *viewsDict = NSDictionaryOfVariableBindings(_pageScrollView, topView, headerView, bodyView, scrollViewContainer);
// pageScrollView - child to self.view
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-0-[_pageScrollView]-0-|" options:0 metrics:nil views:viewsDict]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-0- [_pageScrollView]-0-|" options:0 metrics:nil views:viewsDict]];
// topView - child to pageScrollView
[self.pageScrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-0-[topView]-0-|" options:0 metrics:nil views:viewsDict]];
[self.pageScrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-0-[topView]-0-|" options:0 metrics:nil views:viewsDict]];
NSLayoutConstraint* topViewWidthConstraint = [NSLayoutConstraint constraintWithItem:topView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:newBounds.width];
self.topViewWidthConstraint = topViewWidthConstraint;
[topView addConstraint:self.topViewWidthConstraint];
NSLayoutConstraint* topViewHeightConstraint = [NSLayoutConstraint constraintWithItem:topView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:topViewHeight];
self.topViewHeightConstraint = topViewHeightConstraint;
[topView addConstraint:self.topViewHeightConstraint];
// headerView - child to topView
[topView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-0-[headerView]-0-|" options:0 metrics:nil views:viewsDict]];
[topView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-0-[headerView(55.0)]" options:0 metrics:nil views:viewsDict]];
// scrollViewContainer - child to topView
[topView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-0-[scrollViewContainer]-0-|" options:0 metrics:nil views:viewsDict]];
[topView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:[headerView]-0-[scrollViewContainer]" options:0 metrics:nil views:viewsDict]];
NSLayoutConstraint* pictureHeightConstraint = [NSLayoutConstraint constraintWithItem:scrollViewContainer attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:pictureScrollHeight];
self.pictureHeightConstraint = pictureHeightConstraint;
[scrollViewContainer addConstraint:self.pictureHeightConstraint];
// bodyView - child to topView
[topView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-0-[bodyView]-0-|" options:0 metrics:nil views:viewsDict]];
[topView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V: [scrollViewContainer]-0-[bodyView]-0-|" options:0 metrics:nil views:viewsDict]];
}
- (void)updateViewConstraints
{
[super updateViewConstraints];
if ((newOrientation == UIDeviceOrientationLandscapeLeft) || (newOrientation == UIDeviceOrientationLandscapeRight)) {
pictureScrollHeight = 300;
} else {
pictureScrollHeight = 203;
}
CGFloat topViewHeight = bodyViewHeight + 55 + pictureScrollHeight;
self.pictureHeightConstraint.constant = pictureScrollHeight;
self.topViewHeightConstraint.constant = topViewHeight;
self.topViewWidthConstraint.constant = newBounds.width;
[self.pageScrollView setNeedsUpdateConstraints];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
newBounds = [self sizeInOrientation:toInterfaceOrientation];
}
-(CGSize)sizeInOrientation:(UIInterfaceOrientation)orientation
{
CGSize size = [UIScreen mainScreen].bounds.size;
UIApplication *application = [UIApplication sharedApplication];
if (UIInterfaceOrientationIsLandscape(orientation))
{
size = CGSizeMake(size.height, size.width);
}
if (application.statusBarHidden == NO)
{
size.height -= MIN(application.statusBarFrame.size.width, application.statusBarFrame.size.height);
}
return size;
}
#end
ScrollView calculates its content size automatically depending on subviews constraints added into it. Off course it works only in autolayout enviroument.
Check the auto-resizing masks.
[self.pageScrollView setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
It looks like that you are NOT doing anything with the newBounds in willRotateToInterfaceOrientation. Shouldn't you call your updateView method after getting the new bounds.