What I need is simple: I want my UICollectionView frame to always fill the screen no matter how the device is rotated.
Right now, I am accomplishing this by using the method "willAnimateRotationToInterfaceOrientation:..." and calling a method that re-creates the collection view on rotation. However, this results in a flicker of the view on rotation as the old view is removed and the new one is added.
So I know I need to use autolayout or struts and springs and I'd like to use the latter. I know how to set struts and springs using the interface builder but the project I am working on is not using nibs or storyboards.
Here is my method for creating the collection view (it is called in viewDidLoad), including the code I have that isn't working:
- (void)sceneSetup
{
CGFloat cvWidth;
CGFloat cvHeight;
if ([self getCurrentInterfaceOrientation] || [self getCurrentDeviceOrientation]) {
self.orientationIsLandscape = YES;
cvWidth = 1024;
cvHeight = 768;
} else {
self.orientationIsLandscape = NO;
cvWidth = 768;
cvHeight = 1024;
}
EmailsLayout *layout = [[EmailsLayout alloc]init];
[layout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
self.emailsCollectionView = [[UICollectionView alloc]initWithFrame:CGRectMake(0, 0, cvWidth, cvHeight) collectionViewLayout:layout];
//here is my attempt to programmatically set struts and springs
self.view.autoresizesSubviews = YES;
self.emailsCollectionView.autoresizingMask = (UIViewAutoresizingFlexibleWidth &
UIViewAutoresizingFlexibleHeight & UIViewAutoresizingFlexibleLeftMargin &
UIViewAutoresizingFlexibleRightMargin & UIViewAutoresizingFlexibleTopMargin &
UIViewAutoresizingFlexibleBottomMargin);
self.emailsCollectionView.dataSource = self;
self.emailsCollectionView.delegate = self;
[self.emailsCollectionView setScrollEnabled:YES];
self.emailsCollectionView.userInteractionEnabled = YES;
self.emailsCollectionView.pagingEnabled = YES;
self.emailsCollectionView.backgroundColor = UIColorFromRGB(0x262d32);
[self.emailsCollectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:cellIdentifierEmails];
[self.emailsCollectionView reloadData];
[self.view addSubview:self.emailsCollectionView];
}
Not sure what I am doing wrong. Any help is appreciated.
Try using or | to combine multiple autoresisingMask values together instead of and &.
Related
I am building a tutorial that uses custom subclasses of UIViewController to supply views for the tutorial. I would like to have a subview with instructions appear and then slowly fade out. I am trying to do it this way: a wrapper page controller class, custom UIViewController classes added as child view controllers, and an animation added to the custom UIViewController class's view.
Here is an example of how I add a child view controller to a tutorial page view:
else if(index==2)
{
FollowTutorViewController *next1 = [[FollowTutorViewController alloc] init];
next1.view.userInteractionEnabled = NO;
next1.typeDisplay = 1;
next1.index = index;
[page addChildViewController:next1];
next1.view.frame = page.view.frame;
[page.view addSubview:next1.view];
}
And here is an example of how I do the animation within the subclassed UIViewController:
- (void)messageTutorial
{
CGFloat height = [[UIScreen mainScreen] bounds].size.height;
CGFloat width = [[UIScreen mainScreen] bounds].size.width;
UILabel *directionsLabel = [[UILabel alloc] initWithFrame:CGRectMake(width/2, height/2, 100, 100)];
directionsLabel.backgroundColor = ORANGE_COLOR;
directionsLabel.textColor = BACKGROUND_COLOR;
directionsLabel.text = #"Follower pages show who you're following and who's following you\n\nYou can also see a list of most-controversial posters when you look for New People \n\nBuzz and Judge to gain followers";
directionsLabel.font = [UIFont systemFontOfSize:SMALL_FONT_SIZE];
[directionsLabel setLineBreakMode: UILineBreakModeWordWrap];
[directionsLabel setNumberOfLines:0];
CGSize constraint = CGSizeMake(width*.8 , 200000.0f);
CGSize size = [directionsLabel.text sizeWithFont:[UIFont systemFontOfSize:SMALL_FONT_SIZE] constrainedToSize:constraint];
directionsLabel.alpha = .8;
CGRect f = directionsLabel.frame;
f.size = size;
directionsLabel.frame = f;
directionsLabel.center = self.view.center;
[self.tableView addSubview:directionsLabel];
[UIView animateWithDuration:15 animations:^{
directionsLabel.alpha = 0;
} completion:^(BOOL finished) {
[directionsLabel removeFromSuperview];
}];
}
I would like to make the label disappear slowly starting when the user sees that view, but now when I run this code, regardless of where I call it, the view is gone by the time the user looks at the page. I have tried running this code in viewWillAppear, viewDidAppear, viewDidLayoutSubviews of the child custom UIViewController. Any other suggestions?
I'm working on an iPad app and at some points, I need to show a popover with options for a user to pick from. For this, I use a UITableView in a UIPopoverController. The problem is that, on an iPad (not on the simulator), when scrolling the tableview, I get a sort of "double vision" effect, where it appears like two sets of of the list exist. One that is stationary, and one that scrolls up and down.
I construct the popover like this:
self.fClassTypeList = [[NSMutableArray alloc] init];
[self.fClassTypeList removeAllObjects];
NSUInteger stringLength = 0;
(populate self.fClassTypeList, and set stringLength to the size of the longest entry)
[self setContentSizeForViewInPopover:CGSizeMake(stringLength * 15.0f, [self.fClassTypeList count] * 30)];
CGFloat tableBorderLeft = 5;
CGFloat tableBorderRight = 5;
CGRect viewFrame = self.view.frame;
viewFrame.size.width -= tableBorderLeft + tableBorderRight; // reduce the width of the table
self.fListOfItems = [[UITableView alloc] initWithFrame:viewFrame style:UITableViewStylePlain];
self.fListOfItems.delegate = self;
self.fListOfItems.dataSource = self;
[self.view addSubview:self.fListOfItems];
I put in the viewDidLayoutSubviews(…) part of the view controller, maybe I should put it somewhere else? I am not sure why this happens on the actual machine, but not the simulator.
-viewDidLayoutSubviews is a weird place to put allocations because that method can be called multiple times. So as far as your main issue goes, I believe you should move your allocations into the -init method, and move your layout code into your -viewWillAppear method.
- (id)init
{
self = [super init];
if (self)
{
self.fClassTypeList = [[NSMutableArray alloc] init];
self.fListOfItems = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
self.fListOfItems.delegate = self;
self.fListOfItems.dataSource = self;
[self.view addSubview:self.fListOfItems];
}
return self;
}
- (void )viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
NSUInteger stringLength = 0;
CGFloat tableBorderLeft = 5;
CGFloat tableBorderRight = 5;
CGRect viewFrame = self.view.frame;
viewFrame.size.width -= tableBorderLeft + tableBorderRight; // reduce the width of the table
self.fListOfItems.frame = viewFrame;
[self setContentSizeForViewInPopover:CGSizeMake(stringLength * 15.0f, [self.fClassTypeList count] * 30)];
}
This promotes better memory management.
As an added bonus, I would recommend you refactor the
[self setContentSizeForViewInPopover:CGSizeMake(stringLength * 15.0f, [self.fClassTypeList count] * 30)]; method into a setter method of fClassTypeList. Even better is to simply call -viewWillAppear: in that same setter method instead. This will promote good scalability as you (or someone else) continues to build upon this code later on.
It's a little confusing to see what exactly you're trying to accomplish in this code because it's so hardcoded so let me know if I'm missing the mark you're looking for (w/ an explanation why) and I'll make an edit.
Cheers
I have a static UITableViewController who has 3 what I call Widgets in them. These widgets display data about a game (score, players etc).
In one of my widget I want to display all the players and there icon. I don't know how many players need to be set because this depends on the result the server gives me.
So what I want is to add N times a UIView for all the players the servers returns. I had an idea to do this in a UITableView, but I read somewhere that I cannot add a UITableView inside a TableViewCell.
I would like to be able to make a "Dummy" UIView inside IB and copy and add this for the amount of players or isn't this possible?
I would recomend you to do it in code, it's easy you can create subclass on UIView and you can add UIScrollView. You can override initWithFrame to accept array with yours views:
-(id)initWithFrame:(CGRect)frame data:(NSArray*)myViews
{
if (self = [super initWithFrame:frame])
{
_viewsArray = myViews;
self.scrollView = [[UIScrollView alloc] init];
self.scrollView.backgroundColor = [UIColor clearColor];
[self.scrollView setShowsHorizontalScrollIndicator:NO];
[self addSubview:self.scrollView];
for (int i = 0; i < _viewsArray.count; i++)
{
// This view (v) needs to initialised base on your array content
id obj = _viewsArray[i];
UIView *v = [[UIView alloc] init];
[self.scrollView addSubview:v];
}
}
return self;
}
The last bit left to do is set up a frame for views and scrollView and contentSize in layoutSubviews:
-(void)layoutSubviews
{
[self.scrollView setFrame:self.bounds];
// change your views frames if you need
[self.scrollView setContentSize:CGSizeMake(self.frame.size.width, _viewsArray.count * VIEWHEIGHT)];
}
I have a couple of side-by-side UITableViews in a UIView, and I would like to get the whole thing to autoresize. I have a UIView In my init() method am doing:
// I don't know how big frontBack should be, so I'd like it to autosize
UIView *frontBack = [[UIView alloc] initWithFrame:CGRectZero];
frontBack.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
UITableView *table = [[UITableView alloc]
initWithFrame:CGRectMake(0, 0, r.size.width / 2, height) style:UITableViewStyleGrouped];
table.autoresizingMask = UIViewAutoresizingFlexibleHeight;
table.dataSource = model1;
[table reloadData];
[frontBack addSubview:table];
... (add second table similarly, except with model2)
...
controller.view = frontBack;
This does not work. The tables are 'height' pixels tall (which is smaller than what they need; the text is cut off).
I've tried several ways of getting the UITableViews to resize, with no luck
// contentSize is correct, but frame size does not change
[table reloadData];
table.frame.size.height = table.contentSize.height;
// contentSize is correct, but bounds does not change
[table reloadData];
table.bounds.size.height = table.contentSize.height;
// Nothing appears to change
[table setNeedsLayout];
[table layoutIfNeeded];
// Again, no change
[table sizeToFit];
I assume I am missing something basic here, but I'd be grateful if someone could point out what it is.
table.bounds.size.height = table.contentSize.height;
This is a read-only property, you need to set the frame again.
Also, Are you sure your containing UIView isn't cutting off the table content? You should resize it as well.
I'm programatically adding a UIDatePicker control to a view. I want the DatePicker to appear docked to the bottom of the screen, in the standard way...
I'm setting the frame for the DatePicker and need to be aware of the different screen sizes for 3.5-inch iPhones and 4-inch iPhones.
The following code is producing the desired result, but I have a couple of questions...
// In ViewDidLoad
CGRect defaultFrame = CGRectMake(0,0,0,0);
_datePicker = [[UIDatePicker alloc] initWithFrame:defaultFrame];
CGRect bounds = [self.view bounds];
int datePickerHeight = _datePicker.bounds.size.height;
int navBarHeight = 44;
CGRect datePickerFrame = CGRectMake(0, bounds.size.height - (datePickerHeight + navBarHeight), 0, 0);
[_datePicker setFrame:datePickerFrame];
// In method responding to user tap
[self.view addSubview:_datePicker];
Q1. Is there a more elegant way to do this? Something other than, creating the DatePicker with a frame, checking its height, then setting its frame...
Q2. The view is a UITableView, sitting inside a UINavigationController. When I get the bounds of self.view, the size includes the whole view, including the 44 for the navbar. Yet, when I add the DatePicker with addSubview, if I don't include the offset for the navBar, it's off the bottom by 44...
Why does addSubview work within the smaller bounds when [self.view bounds] returns the full bounds?
Cheers,
Gavin
After looking into this some more, I've realised my original question was flawed. It wasn't clear where I was adding the UIDatePicker as a sub view. I've updated the question.
I now have two answers:
1) Position and add the UIDatePicker in ViewDidLoad. Use Autoresizing to deal with the view size change. Then make it visisible in response to the user tapping a control:
- (void)viewDidLoad
{
[super viewDidLoad];
_tableView = (UITableView*)self.view;
_tableView.backgroundColor = [UIColor colorWithRed:0.941 green:0.941 blue:0.913 alpha:1.000];
_tableView.backgroundView = nil;
_datePicker = [[UIDatePicker alloc] init];
CGRect bounds = [self.view bounds];
int datePickerHeight = _datePicker.frame.size.height;
_datePicker.frame = CGRectMake(0, bounds.size.height - (datePickerHeight), _datePicker.frame.size.width, _datePicker.frame.size.height);
_datePicker.autoresizingMask = UIViewAutoresizingFlexibleTopMargin;
_datePicker.isHidden = YES;
[self.view addSubview:_datePicker];
[_datePicker addTarget:self action:#selector(datePickerChanged:) forControlEvents:UIControlEventValueChanged];
}
2) Just set the frame for the UIDatePicker as required, not in ViewDidLoad:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
switch (indexPath.row) {
case RowDate:
{
CGRect bounds = [self.view bounds];
int datePickerHeight = _datePicker.frame.size.height;
_datePicker.frame = CGRectMake(0, bounds.size.height - (datePickerHeight), _datePicker.frame.size.width, _datePicker.frame.size.height);
[self.view addSubview:_datePicker];
break;
}
default:
break;
}
}
Thanks,
Gavin
The problem is that navigation bar pushes all the view downwards, after view did load initialized.
autoresizing mask may help.
For UIDatePicker, you don't need to specify its size. Because most of the time you will want it as wide as the screen and its height is fixed. But you need still to put it in the correct position. That is, you need to compute the correct position for it, set its frame.
Because most of the time you won't want your UIDatePicker to overlap your navBar. So Apple will let the addSubview work as if the bounds is "smaller".