Autoresizing of subviews ( UICollectionView) on orientation change - ios

I have Created a CustomView ganttChartView and added it from storyboard . Now on ganttChartView I have a UICollection View which will represent timeLine and added programatically.
// Initialize GanttChat View from Interface Builder or Storyboard File
-(id)initWithCoder:(NSCoder *)aDecoder
{
self= [super initWithCoder:aDecoder];
if (self) {
self.timeLineHeight =KMinTimeLineCellHeight;
self.timeLineCellWidth=kMinTimeLineCellWidth;
self.backgroundColor = [UIColor redColor];
self.autoresizesSubviews = YES;
}
return self;
}
-(void)reloadTimelineView
{
[self initializeTimeLineView];
[self.timeLineCollectionView reloadData];
}
-(void) initializeTimeLineView
{
// Initialization of StartDate End Date and DateMode Property
[self initializeTimeLineDates];
// Creating Layout for Collection view
UICollectionViewFlowLayout* flowLayout = [[UICollectionViewFlowLayout alloc]init];
[flowLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
CGSize cellSize =CGSizeMake(self.timeLineCellWidth, self.timeLineHeight) ;
flowLayout.itemSize = cellSize ;
flowLayout.minimumInteritemSpacing= 1.0f;
flowLayout.minimumLineSpacing=5.0f;
CGRect timeLineFrame =CGRectMake(self.bounds.origin.x, self.bounds.origin.y, self.bounds.size.width, self.timeLineHeight);
// Initialization of CollectionView for TimeLine
self.timeLineCollectionView = [[UICollectionView alloc] initWithFrame:timeLineFrame collectionViewLayout:flowLayout];
[self.timeLineCollectionView registerClass:[A3TimeLineCollectionViewCell class] forCellWithReuseIdentifier:timeLineCell_ID];
self.timeLineCollectionView.backgroundColor = self.timeLineBackgroundColor;
// Initialization of CollectionView DataSource and Delegate with Start Date and End date and DateMode
self.timeLineDataSource = [[A3GanttChartTimeLineDelegate alloc] initWithDate:self.startDate andDate:self.endDate withMode:self.dateType];
self.timeLineDataSource.gantChartView = self;
self.timeLineDataSource.timeLineEachCellColor = self.timeLineEachCellColor;
self.timeLineCollectionView.delegate=self.timeLineDataSource;
self.timeLineCollectionView.dataSource=self.timeLineDataSource;
[self addSubview:self.timeLineCollectionView];
}
Now From Storyboard I have disabled AutoLayout option and from size Inspector of ganttChartView I have set top and left corner fixed so that it resized after orientation change .
Now the problem is that TimeLineCollection View is not resizing on orientation change to Landscape. As its added programatically So What I need to do make it resized on orientation change .
Profit Mode
Landscape Mode

You need to set also right corner fixed in order to resize after orientation change

self.timeLineCollectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleBottomMargin;

I have fixed this issue using NSLayoutConstraint .
// NSLayoutConstraint for making same width of timelineCollectionView with the GanttChart
NSLayoutConstraint *timeLineCollectionViewWidth =[NSLayoutConstraint
constraintWithItem:self.timeLineCollectionView
attribute:NSLayoutAttributeWidth
relatedBy:0
toItem:self
attribute:NSLayoutAttributeWidth
multiplier:1.0
constant:0];
[self addConstraint:timeLineCollectionViewWidth];
// NSLayoutConstraint for making same left position of timelineCollectionView with the GanttChart
NSLayoutConstraint *timeLineCollectionViewLeft = [NSLayoutConstraint
constraintWithItem:self.timeLineCollectionView
attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeLeft
multiplier:1.0f
constant:0.f];
[self addConstraint:timeLineCollectionViewLeft];
// NSLayoutConstraint for seting height of timelineCollectionView
NSLayoutConstraint *heightConstraint =
[NSLayoutConstraint constraintWithItem:self.timeLineCollectionView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:self.timeLineHeight];
[self.timeLineCollectionView addConstraint:heightConstraint];

Related

IOS/Objective-C: Center Line under Button Programmatically

I am trying to do a simple line under three buttons to create a Tabs effect. While I could do this in Storyboard, I'd like to do it in code and ideally make the line a subview of an element already in the view to avoid having to give it special constraints.
My approach has been to create a UILabel with no text and a background color. I can make the UILabel a subview of the View, however, that does not attach it to the bottom of the buttons.
On the other hand, if I make the UILabel a subview of one of the buttons, I can't see it.
Can anyone suggest a simple way to do this?
[centerButton setTitle:#"Favorites" forState:UIControlStateNormal];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(20, 120, 280, 2)];
label.backgroundColor = [UIColor redColor];
label.textAlignment = NSTextAlignmentCenter;
label.numberOfLines = 1;
label.text = #"";
[self.view addSubview: label];
Thanks in advance for any suggestions.
Edit:
I tried adding some NSLayoutConstraints Programmatically:
NSLayoutConstraint *con3 = [NSLayoutConstraint
constraintWithItem:label attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual toItem:centerButton
attribute:NSLayoutAttributeBottom multiplier:1 constant:0];
[label addConstraints:#[con3]];
//tried with and without
[self.view layoutIfNeeded];
This returned the exception:
[LayoutConstraints] The view hierarchy is not prepared
for the constraint: <NSLayoutConstraint:0x174e85500 V:
[UIButton:0x100b0baf0'Now']-(0)-[UILabel:0x108555160]
(inactive)>
When added to a view, the constraint's items
must be descendants of that view (or the view itself).
This will crash if the constraint needs to be resolved
before the view hierarchy is assembled.
Break on -[UIView(UIConstraintBasedLayout)
_viewHierarchyUnpreparedForConstraint:] to debug.
The button created in storyboard is a subview of self.view and I add the label to self.view as a subview in code so not sure why the exception is occurring.
I wonder from the error message if you're possibly attempting to add the NSLayoutConstraint prior to the redLabel view being added to it's parentView (or too early in the lifecycle). In any event, I think this is pretty close to what you're attempting to accomplish:
#import "ViewController.h"
#interface ViewController ()
#property (strong, nullable) UILabel *previousRedLabel;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (IBAction)buttonClicked:(id)sender {
if ([sender isKindOfClass:[UIButton class]]) {
UIButton *clickedButton = (UIButton *)sender;
UIView *buttonSuperview = [clickedButton superview];
if (buttonSuperview != nil) {
[self _putRedLineWithHeight:3.0f atTheBottomOfView:buttonSuperview animate:YES];
}
}
}
- (void)_putRedLineWithHeight:(CGFloat)height atTheBottomOfView:(UIView *)viewToPutUnder animate:(BOOL)animate {
// remove our previous red line
if (self.previousRedLabel) {
// if you want it to be a no-op here if they click the same button
// you'll need to add some logic to check if the superView == viewToPutUnder
[self.previousRedLabel removeFromSuperview];
self.previousRedLabel = nil;
}
UILabel *redLabel = [[UILabel alloc] init];
// we're using autolayout so we don't want any resizing from it
redLabel.translatesAutoresizingMaskIntoConstraints = NO;
redLabel.backgroundColor = [UIColor redColor];
// start out with alpha = 0
redLabel.alpha = 0.0f;
// add it to our parentView
[viewToPutUnder addSubview:redLabel];
// height (determined by passed in value)
NSAssert(height >= 0, #"Height must be a positive number");
NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:redLabel attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:height];
// width equal to parentView's width
NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:viewToPutUnder attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:redLabel attribute:NSLayoutAttributeWidth multiplier:1.0f constant:0.0f];
// center x == parentView's center x
NSLayoutConstraint *centerConstraint = [NSLayoutConstraint constraintWithItem:viewToPutUnder attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:redLabel attribute:NSLayoutAttributeCenterX multiplier:1.0f constant:0.0f];
// now the bottom constraint (place it at the bottom of the parent view)
NSLayoutConstraint *bottomConstraint = [NSLayoutConstraint constraintWithItem:viewToPutUnder attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:redLabel attribute:NSLayoutAttributeBottom multiplier:1.0f constant:0.0f];
// add the height constraint to our label
[redLabel addConstraint:heightConstraint];
// and all the other constraints to our parent view
[viewToPutUnder addConstraints:#[widthConstraint, centerConstraint, bottomConstraint]];
redLabel.alpha = 1.0f;
if (animate) {
[UIView animateWithDuration:0.6f animations:^{
[redLabel layoutIfNeeded];
}];
}
self.previousRedLabel = redLabel;
}
Example of Animated:
And one of Non-Animated:
EDITED ANSWER TO HANDLE THE CASE IF EACH BUTTON ISN'T IN IT'S OWN SUPERVIEW
Adjusted for if all buttons are in one superview (width based on button width, center to button center, and pinning the top of the label to the bottom of the button)
#import "ViewController.h"
#interface ViewController ()
#property (strong, nullable) UILabel *previousRedLabel;
- (void)_putRedLineWithHeight:(CGFloat)height atTheBottomOfButton:(UIButton *)button animate:(BOOL)animate;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (IBAction)buttonClicked:(id)sender {
if ([sender isKindOfClass:[UIButton class]]) {
UIButton *clickedButton = (UIButton *)sender;
// if you want it to be a no-op here if they click the same button
// you'll need to add some logic to store the previous clicked button and check whether it's the same button
[self _putRedLineWithHeight:3.0f atTheBottomOfButton:clickedButton animate:YES];
}
}
- (void)_putRedLineWithHeight:(CGFloat)height atTheBottomOfButton:(UIButton *)button animate:(BOOL)animate {
UIView *buttonSuperview = button.superview;
NSAssert(buttonSuperview != nil, #"Button has to have a superview");
// remove our previous red line
if (self.previousRedLabel) {
[self.previousRedLabel removeFromSuperview];
self.previousRedLabel = nil;
}
UILabel *redLabel = [[UILabel alloc] init];
// we're using autolayout so we don't want any resizing from it
redLabel.translatesAutoresizingMaskIntoConstraints = NO;
redLabel.backgroundColor = [UIColor redColor];
// start out with alpha = 0
redLabel.alpha = 0.0f;
// add it to our parentView
[buttonSuperview addSubview:redLabel];
// height (determined by passed in value)
NSAssert(height >= 0, #"Height must be a positive number");
NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:redLabel attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:height];
// width equal to button's width
NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:button attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:redLabel attribute:NSLayoutAttributeWidth multiplier:1.0f constant:0.0f];
// center x == button's center x
NSLayoutConstraint *centerConstraint = [NSLayoutConstraint constraintWithItem:button attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:redLabel attribute:NSLayoutAttributeCenterX multiplier:1.0f constant:0.0f];
// now pin the top of the label to the bottom of the button
NSLayoutConstraint *bottomConstraint = [NSLayoutConstraint constraintWithItem:redLabel attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:button attribute:NSLayoutAttributeBottom multiplier:1.0f constant:0.0f];
// add the height constraint to our label
[redLabel addConstraint:heightConstraint];
// and all the other constraints to our parent view
[buttonSuperview addConstraints:#[widthConstraint, centerConstraint, bottomConstraint]];
redLabel.alpha = 1.0f;
if (animate) {
[UIView animateWithDuration:0.6f animations:^{
[redLabel layoutIfNeeded];
}];
}
self.previousRedLabel = redLabel;
}
#end
Animated:
Not Animated:

iOS Objective C ScrollView

I am trying to implement a UIScrollView and load it with images from an array of images in Xcode using objective-C, each image in the UIScrollView must be full screen both in portrait and in the landscape mode.I have been able to make it work in portrait mode but not in landscape mode. It should be fullscreen in all iOS device sizes. Below is the code I have written so far. I have UIScrollView in my storyboard, a button and a label. Any answer or pointing to a tutorial that implements this will be appreciated. Thanks in advance.
CGRect screen = [[UIScreen mainScreen] bounds];
CGFloat widthInPixel = screen.size.width;
CGFloat heightInPixel = screen.size.height;
float increaseAmount = widthInPixel;
self.imageScrollView.contentMode = UIViewContentModeScaleAspectFit;
self.imageScrollView.pagingEnabled = YES;
[self.imageScrollView setAlwaysBounceVertical:NO];
[self.imageScrollView setAlwaysBounceHorizontal:NO];
imageViews = [[NSMutableArray alloc] init];
self.imageScrollView.clipsToBounds = YES;
NSInteger imageNumbers = [self.images count];
UIImageView *image;
for(NSInteger i = 0; i < imageNumbers; i++) {
CGFloat xOrigin = i * self.view.frame.size.width;
image = [[UIImageView alloc] initWithFrame:
CGRectMake(xOrigin, 0,
widthInPixel,
self.imageScrollView.frame.size.height)];
image.contentMode = UIViewContentModeScaleAspectFit;
image.clipsToBounds = YES;
image.image = self.images[i];
[image setAutoresizingMask:
UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleHeight];
[self.imageScrollView addSubview:image];
}
self.imageScrollView.contentSize = CGSizeMake(image.frame.size.width *
imageNumbers,
self.imageScrollView.frame.size.height);
You really should learn how to use auto-layout and constraints. Use your favorite search engine and search for ios auto layout tutorial ... you'll find plenty of material.
Edit:
Scroll offset is an inherent issue when rotating a scroll view with paging enabled. See the edit below for an implementation of viewWillTransitionToSize.
But, to give you an idea, this will do what you want, including auto-resizing on device rotation:
//
// ViewController.m
// ScrollingImages
//
// Created by Don Mag on 7/19/18.
//
#import "ViewController.h"
#interface ViewController ()
#property (strong, nonatomic) IBOutlet UIScrollView *theScrollView;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSArray *images = #[#"a", #"b", #"c", #"d", #"e"];
[_theScrollView setPagingEnabled:YES];
[_theScrollView setAlwaysBounceVertical:NO];
[_theScrollView setAlwaysBounceHorizontal:NO];
// we'll use this to hold the most recently added view
UIImageView *prevImageView = nil;
for (int i = 0; i < images.count; i++) {
// create an image view with named image from array
UIImageView *v = [[UIImageView alloc] initWithImage:[UIImage imageNamed:images[i]]];
// we want to use auto-layout
v.translatesAutoresizingMaskIntoConstraints = NO;
// we want aspect-fit
v.contentMode = UIViewContentModeScaleAspectFit;
// add it to the scroll view
[_theScrollView addSubview:v];
// set width and height constraints equal to the scroll view
[[NSLayoutConstraint
constraintWithItem:v
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:_theScrollView
attribute:NSLayoutAttributeWidth
multiplier:1.0
constant:0.0] setActive:YES];
[[NSLayoutConstraint
constraintWithItem:v
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:_theScrollView
attribute:NSLayoutAttributeHeight
multiplier:1.0
constant:0.0] setActive:YES];
if (i == 0) { // if it's the first image
// add top constraint
[[NSLayoutConstraint
constraintWithItem:v
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:_theScrollView
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:0.0] setActive:YES];
// and leading constraint
[[NSLayoutConstraint
constraintWithItem:v
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:_theScrollView
attribute:NSLayoutAttributeLeading
multiplier:1.0
constant:0.0] setActive:YES];
} else {
// constrain leading to previous image view trailing
[[NSLayoutConstraint
constraintWithItem:v
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:prevImageView
attribute:NSLayoutAttributeTrailing
multiplier:1.0
constant:0.0] setActive:YES];
// and top to previous image view top
[[NSLayoutConstraint
constraintWithItem:v
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:prevImageView
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:0.0] setActive:YES];
}
if (i == images.count - 1) { // if it's the last image
// add trailing constraint
[[NSLayoutConstraint
constraintWithItem:v
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:_theScrollView
attribute:NSLayoutAttributeTrailing
multiplier:1.0
constant:0.0] setActive:YES];
// and bottom constraint
[[NSLayoutConstraint
constraintWithItem:v
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:_theScrollView
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:0.0] setActive:YES];
}
// reference to most recently added view
prevImageView = v;
}
}
- (void) viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
// execute before rotation
// get the "index" of the current image in the scroll view
NSUInteger idx = (unsigned)(_theScrollView.contentOffset.x / _theScrollView.frame.size.width);
[coordinator animateAlongsideTransition:^(id _Nonnull context) {
// execute during rotation
// update the scroll view's contentOffset, based on the "index"
self.theScrollView.contentOffset = CGPointMake(idx * self.theScrollView.frame.size.width, 0);
} completion:^(id _Nonnull context) {
// execute after rotation (if additional code wanted)
}];
}
#end
You can download a working example project here: https://github.com/DonMag/ScrollingImages

How to get constraints from UIView Programmatically

I want get UILabel constraints from UIView but I can't get any constraints.
I set the constraints in CustomView.m like this:
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
_titleLabel = [UILabel new];
[self addSubview:_titleLabel];
}
return self;
}
- (void)layoutSubviews {
[super layoutSubviews];
_titleLabel.translatesAutoresizingMaskIntoConstraints = NO;
NSLayoutConstraint *titleLabelBottom = [NSLayoutConstraint constraintWithItem:_titleLabel
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeCenterY
multiplier:1
constant:0];
[self addConstraints:#[titleLabelBottom]];
...more code
}
in ViewController.m
CustomView *view = [CustomView alloc] initWithFrame:viewFrame];
NSLog(#"%#",view.titleLabel.constraints); // nil
you can get constraints in NSArray like,
NSArray *constraintArr = self.backButton.constraints;
NSLog(#"cons : %#",constraintArr);
And you can set instance variable like,
NSLayoutConstraint *titleLabelBottom;
and then use,
titleLabelBottom = [NSLayoutConstraint constraintWithItem:_titleLabel
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeCenterY
multiplier:1
constant:0];
[self addConstraints:#[titleLabelBottom]];
so, you can use titleLabelBottom anywhere in class.
hope this will help :)
You are getting nil because the constraint has not been created yet.
Try logging your constraints in:
- (void)viewDidLayoutSubviews;
Assumming that constraint is essential to your CustomView, you should create that constraint in your initWithFrame method method.

Add subview to UITextView and using autolayout

I have problem with adding subview to UITextView using autoLayout:
in SubTextView : UITextView .m file:
- (instancetype)initWithFrame:(CGRect)frame
{
if(self = [super initWithFrame:frame]) {
_baseline = [[UIView alloc] init];
[self addSubview:_baseline];
[self setBackgroundColor: [UIColor blackColor]];
_baseline.translatesAutoresizingMaskIntoConstraints = NO;
[self setNeedsUpdateConstraints];
}
}
- (void)updateConstraints
{
[super updateConstraints];
NSLayoutConstraint *constraint = nil;
constraint = [NSLayoutConstraint constraintWithItem:self.baseline
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeTrailing
multiplier:1.f
constant:0.f];
[self addConstraint:constraint];
constraint = [NSLayoutConstraint constraintWithItem:self.baseline
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeLeading
multiplier:1.f
constant:0.f];
[self addConstraint:constraint];
constraint = [NSLayoutConstraint constraintWithItem:self.baseline
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeCenterY
multiplier:1.f
constant:0.f];
[self addConstraint:constraint];
}
But, this do not work... the self.baseline's frame is always (0, 0, 0, 0)...
Anyone can help?
Edited:
I set a break point at layout subviews, at that time, when layoutSubviews the subviews are inited, and the UITextView is :
<InventoryOverviewListingNameTextView: 0x7fd92b2a1800;
baseClass = UITextView;
frame = (234 36; 399 70.2);
text = '11111111';
clipsToBounds = YES;
gestureRecognizers = <NSArray: 0x7fd92cbd8ca0>;
layer = <CALayer: 0x7fd92cb08900>;
contentOffset: {-0, 10};
contentSize: {399, 70.199997425079346}>
But the frame of the baseline is:
<UIView: 0x7fd92cb90710;
frame = (0 -10; 399 0.5);
layer = <CALayer: 0x7fd92cb907e0>>.
Do not know how to make the y = -10 to y = 69.7.
I feel it is a little like scrollView, to which I solve by add a UIView as contentView on UIScrollView, and UIScrollView itself is added on another UIView. Then I set the contentView's top to scrollView's top, contentView's heigh, and !!!(this is important or autoLayout won't work properly)
contentView's left and right to UIView rather than scrollView.
But I do not see it works for UITextView...
Anyone can help?
The frame will always be (0,0,0,0) because that is the default one that comes whit [[UIView alloc] init].
Have you tried defining the view setting a frame?
- (instancetype)initWithFrame:(CGRect)frame
{
if(self = [super initWithFrame:frame]) {
//Add a frame, does not matter the size
_baseline = [[UIView alloc] initWithFrame:CGRectMake(0,0,20,20)];
//Just to make sure it's there let us give it a color
[_baseline setBackgroundColor:[UIColor green]];
[self addSubview:_baseline];
//Don't run this line just yet.
//[self setNeedsUpdateConstraints];
}
}
If that works, then we found the problem, if it does not, maybe the problem is on the - (void)updateConstraints method.
UPDATE:
So, I sat down and ran your code, I got a few crashes but eventually I managed to make the black box apear inside the text view. I found that the box was not instantiated when the view was looking to layout its subviews, so I tinkered around and here goes, this works, it throws a few constraints warnings but I guess you can work those by yourself.
- (instancetype)initWithFrame:(CGRect)frame
{
if(self = [super initWithFrame:frame]) {
}
return self;
}
-(void)layoutSubviews{
[super layoutSubviews];
if (!_baseline) {
_baseline = [[UIView alloc] init];
[self addSubview:_baseline];
[self setBackgroundColor: [UIColor blackColor]];
[self setNeedsUpdateConstraints];
}
}
- (void)updateConstraints {
[super updateConstraints];
if (_baseline) {
NSLayoutConstraint *constraint = nil;
constraint = [NSLayoutConstraint constraintWithItem:self.baseline
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeTrailing
multiplier:1.f
constant:0.f];
[self addConstraint:constraint];
constraint = [NSLayoutConstraint constraintWithItem:self.baseline
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeLeading
multiplier:1.f
constant:0.f];
[self addConstraint:constraint];
constraint = [NSLayoutConstraint constraintWithItem:self.baseline
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeCenterY
multiplier:1.f
constant:0.f];
[self addConstraint:constraint];
}
}

Center UITableView within a subView

I'm ultimately trying to vertically center my table view cells within a UITableView if the total amount of cells * row height < the height of the tableView
My problem is that whenever I try to reference the tableview height (which should be resized when added to its superview. It returns original height of the view as defined in Interface Builder.
Here is the method that adds the subView with the tableView:
- (void)addMissonListView {
missionView = [BSMissionListView loadMissionView:YES];
BSList *list = (BSList *)self.dataModel;
missionView.missionList = list.arrayMissions;
missionView.delegate = self;
missionView.heightofSuperView = [NSNumber numberWithFloat:viewBottomContainer.frame.size.height];
[viewBottomContainer addSubview:missionView];
[viewBottomContainer setTranslatesAutoresizingMaskIntoConstraints:NO];
[BSUtility setConstraintsOnView:viewBottomContainer relativeTo:missionView withConstant:0];
}
This is the setsConstraintsOnView method that's called:
+ (void)setConstraintsOnView:(UIView *)superView relativeTo:(UIView *)subView withConstant:(int)constant
{
[subView setTranslatesAutoresizingMaskIntoConstraints:NO];
[superView addConstraint:[NSLayoutConstraint constraintWithItem:subView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:superView attribute:NSLayoutAttributeBottom multiplier:1 constant:constant]];
[superView addConstraint:[NSLayoutConstraint constraintWithItem:subView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:superView attribute:NSLayoutAttributeTop multiplier:1 constant:constant]];
[superView addConstraint:[NSLayoutConstraint constraintWithItem:subView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:superView attribute:NSLayoutAttributeRight multiplier:1 constant:constant]];
[superView addConstraint:[NSLayoutConstraint constraintWithItem:subView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:superView attribute:NSLayoutAttributeLeft multiplier:1 constant:constant]];
}
The subview consists of a tableView inside of UIView. In Interface Builder, the size of the UIView is 320 X 586 and the tableView is 310 x 558.
viewBottomContainer's size in IB is 320 x 408
I'm trying to get the information about the view's and tableView's height in the configureGUI method. And once that works, I'll pass it to another method to create a contentOffset in the TableView. but the NSLog's keep returning the original values, not the resized values.
These are the methods from the BSMissionListView class:
- (void)awakeFromNib {
[super awakeFromNib];
[self configureGUI];
}
- (void)configureGUI {
[super configureGUI];
NSLog(#"Bounds height of the View is %f",self.bounds.size.height);
NSLog(#"Bounds height of the tableView is %f",self.tableViewMissionList.bounds.size.height);
[self setBackgroundColor:[UIColor clearColor]];
}
I'll be happy to post more code if that will be helpful. Thank you!
I was able to solve the problem by passing in the tableView's superView's height by ways of the method that the loaded the tableView nib.
-I added a CGFloat variable to the method that loads the nib in the BSMissionListView Class
-I passed in the viewBottomContainer's height and then used that to set the heightOfSuperView value in the newly modified method.
-heightOfSuperView's value is used to calculate to contentInset of the TableView to center it within the superView
Thank you to #Alex Renyolds for helping me out.
- (void)addMissonListView {
[viewBottomContainer setNeedsLayout];
[viewBottomContainer layoutIfNeeded];
[viewBottomContainer setTranslatesAutoresizingMaskIntoConstraints:NO];
NSLog(#"Height of bottomViewContrainer: %f", viewBottomContainer.bounds.size.height);
BSList *list = (BSList *)self.dataModel;
missionView = [BSMissionListView loadMissionView:YES heightOfSuperView:viewBottomContainer.bounds.size.height listArray:list.arrayMissions];
missionView.delegate = self;
[viewBottomContainer addSubview:missionView];
[viewBottomContainer setTranslatesAutoresizingMaskIntoConstraints:NO];
[BSUtility setConstraintsOnView:viewBottomContainer relativeTo:missionView withConstant:0];
}
BSMissionList
+ (BSMissionListView *)loadMissionView:(BOOL)isEditable heightOfSuperView:(CGFloat)height listArray:(NSMutableArray *)list {
BSMissionListView *missionListView = [[[NSBundle mainBundle] loadNibNamed:NSStringFromClass([BSMissionListView class]) owner:nil options:nil] lastObject];
missionListView.missionList = list;
missionListView.isEditable = isEditable;
missionListView.heightofSuperView = (height- 49);
[missionListView configureGUI];
return missionListView;
}

Resources