I have a UIScrollView, in which I want to contain a number of UITableViews, each one being a page. I've added them to my scroll view, and verified that the frames of the UITableViews are set correctly. The first UITableView is displayed correctly, but it will not let me scroll horizontally to see the others. Here's the code I'm using to at the table views:
scrollView.delegate=self;
scrollView.scrollEnabled=YES;
tableViews = [[NSMutableArray alloc] initWithCapacity:recipOrgs.count];
for (NSDictionary *orgDict in recipOrgs) {
int index = [recipOrgs indexOfObject:orgDict];
NSLog(#"Creating table view for index: %d",index);
CGRect frame;
frame.origin.x = self.scrollView.frame.size.width * index;
frame.origin.y = 0;
frame.size = self.scrollView.frame.size;
OrganizationTableView *tableView = [[OrganizationTableView alloc] init];
tableView.index=index;
tableView.parentCon=self;
tableView.dataSource=tableView;
tableView.delegate=tableView;
[tableViews addObject:tableView];
[scrollView addSubview:tableView];
[tableView setFrame:frame];
}
Any ideas why this isn't working? As I mentioned, I checked the x values of the UITableView origins, and I get 0, 320, 640, etc. like I would expect.
You are probably forgetting to set the contentSize for your scrollView.
scollView.contentSize = CGSizeMake(recipOrgs * CGRectGetWidth(scrollView.frame), CGRectGetHeight(scrollView.frame));
But you should probably consider using UICollectionView instead of UIScrollView, then you get reuse logic for free and you do not have to worry about the contentSize.
Related
I have a 100-row table and want to scroll it programmatically to any element and select that element. In first controller I specify row and section and push the controller with the UITableView onto navigation stack. In viewWillAppear of "tableView-controller" I use the code:
[tableView_ selectRowAtIndexPath:[NSIndexPath indexPathForRow:row inSection:section] animated:NO scrollPosition:UITableViewScrollPositionMiddle];
The curious part is, it scrolls perfectly to any of 99 first rows, 100-th row gets selected, but remains "below" the visible area. I have to scroll the table manually to reveal it.
If I place that code in viewDidAppear, table scrolls nicely, but after a noticeable delay.
What did I also try:
Reducing the height of tableView. I got tableView which partly covers the screen with last row obscured indeed.
Playing with contentSize - setting its height to small large values - no luck.
Setting contentInset.bottom - worked, but I've got a useless space at the bottom.
In viewDidAppear, processing 99 rows as usual and setting custom contentOffset for the 100-th row:
offset.y += tableView_.contentSize.height - tableView_.bounds.size.height + 44;
worked too, but it seems to be an ugly way.
So, what should I do to get my tableView pre-scrolled even to 100-th element when "tableView-controller" appears?
UPDATE.
I do not use any xibs or storyboards, just defining views in viewDidLoad:
- (void)viewDidLoad {
[super viewDidLoad];
tableView_ = [[UITableView alloc] initWithFrame:self.view.frame style:UITableViewStyleGrouped];
tableView_.dataSource = self;
tableView_.delegate = self;
tableView_.sectionFooterHeight = 0.0f;
self.view = tableView_;
numbers = [NSMutableDictionary dictionary];
numberSectionTitles = [NSMutableArray array];
//... some model initialization
headerView = [[UIView alloc] initWithFrame:(CGRect){0, 0, 320, 60}];
headerView.backgroundColor = [UIColor greenColor];
UILabel *l = [[UILabel alloc] initWithFrame:(CGRect){20, 20, 280, 20}];
l.textColor =[UIColor whiteColor];
l.tag = 121;
[headerView addSubview:l];
}
And adjust selection in viewDidAppear (dirty workarounds)
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
int row = _selectedIndex % 10;
int section = (_selectedIndex - row) / 10;
if(row == 9 && section == 9){
CGSize contentSize = tableView_.contentSize;
CGPoint offset = tableView_.contentOffset;
offset.y += tableView_.contentSize.height - tableView_.bounds.size.height + 44;
tableView_.contentOffset = offset;
}
[tableView_ selectRowAtIndexPath:[NSIndexPath indexPathForRow:row inSection:section] animated:NO scrollPosition:UITableViewScrollPositionMiddle];
}
may be your view height is not same of tableview. your superview(on which you are adding your tableview) should be same. your last row is hiding because your view is not as same height as your tableview,may be this solve your problem.
You can do it manually:
[_tableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:row inSection:section] animated:NO scrollPosition:UITableViewScrollPositionNone];
CGRect rect = [_tableView rectForRowAtIndexPath:[NSIndexPath indexPathForRow:row inSection:section]];
CGFloat offsetY = rect.origin.y+rect.size.height/2-_tableView.frame.size.height/2-_tableView.contentInset.top/2;
if (offsetY < -_tableView.contentInset.top)
offsetY = -_tableView.contentInset.top;
else if (offsetY > _tableView.contentSize.height-_tableView.frame.size.height)
offsetY = _tableView.contentSize.height-_tableView.frame.size.height;
_tableView.contentOffset = CGPointMake(_tableView.contentOffset.x, offsetY);
if (cell==nil)
if you've written an if statement like this in your CellforRowatIndexpath remove that particular if statement and proceed. That line causing problem
Enjoy coding
I want to add the elements in scroll view during the button click.. if the elements add means the scroll view want to become big. depends upon the adding elements in scroll view.. the elements should be added one by one in scrollview when i clicked the button..
Maintain one height index in viewcontroller say
float = scrollViewheight;
When adding any object say adding UILabel to scrollView then increase scrollViewheight like this
UILabel *lblText = [UILabel new];
lblText.frame = CGRectMake(20,20,280,22);
[scrollView addSubview:lblText];
//update scrollViewheight
scrollViewheight = lblText.frame.origin.y+lblText.frame.size.height;
//update scrollView's content size
[scrollView setContentSize:CGSizeMake(0,scrollViewheight);
When adding new object use scrollViewheight
UILabel *lblText1 = [UILabel new];
lblText1.frame = CGRectMake(20,scrollViewheight+20,280,22);
[scrollView addSubview:lblText1];
//update scrollViewheight
scrollViewheight = lblText1.frame.origin.y+lblText1.frame.size.height;
//update scrollView's content size
[scrollView setContentSize:CGSizeMake(0,scrollViewheight);
EDIT : Just formatted
You can add your UIView elements with [self.scroll addSubview:myView] and resize your content size accordingly.
- (void)buttonClicked:(UIButton *)button {
// adds new view to scrollView
[self.scrollView addSubview:anotherView];
int padding = 10;
// set scrollView content size
[self.scrollView setContentSize:CGSizeMake(self.scrollView.contentView.size.width, self.scrollView.frame.size.height + padding + anotherView.frame.size.height)];
[self.scrollView setContentOffset:CGPointMake(0, anotherView.frame.origin.y) animated:YES]; // scrolls to new view
}
Hope it helps
Is it possible to use UIScrollViewController to scroll or "page" two or more views coming from UIViewControllers?
Example (in viewDidLoad)
self.a1 = [[CustomViewController1 alloc] init];
self.a2 = [[CustomViewController2 alloc] init];
//Scroller
self.scroller = [[UIScrollView alloc] initWithFrame:CGRectMake(0,0,1000,400
400)];
[self.scroller addSubview:self.a1.view];
[self.scroller addSubview:self.a2.view];
[self.view addSubview:self.scroller];
But I can see in the scroller only the view of controller a2.
You need to set the frames of the views so they they sit one below another. Currently they are both there, just on top of one another.
Try putting in
self.a2.view.frame = CGRectMake(0, 480, 320, 480);
You have to modify the frames aswell. Now a1 and a2 have the same, and they are on top of eachother, so the a2 is visible, because you added the later.
Try
self.a2.view.frame = CGRectOffset(self.a2.view.frame, self.a1.view.frame.size.width, 0);
The solution is to set the frame coordinates of the subviews inside the scroller:
CGRect frame = CGRectMake(0, 0, 1000, 600);
self.a1 = [[CustomViewController1 alloc] init];
self.a1.view.frame = frame;
self.a2 = [[CustomViewController2 alloc] init];
frame.origin.x = frame.size.width +10;
self.a2.view.frame = frame;
[self.scroller addSubview:self.a1.view];
[self.scroller addSubview:self.a2.view];
[self.view addSubview:self.scroller];
You'll need to add the custom view controllers as child view controllers. See Apple's documentation for more information on doing that correctly.
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".