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.
Related
I need to do a horizontal scroll in my table view and I search for all the Google and I don't find anything, I do that
CGRect tableFrame = CGRectMake(15, heightView-360, widthView+50, heightView-200);
UITableView *tableView = [[UITableView alloc]initWithFrame:tableFrame style:UITableViewStylePlain];
tableView.layer.cornerRadius=7;
tableView.rowHeight = 40;
tableView.sectionFooterHeight = myData.count;
tableView.sectionHeaderHeight = myData.count;
tableView.scrollEnabled = YES;
tableView.showsVerticalScrollIndicator = YES;
tableView.showsHorizontalScrollIndicator=YES;
tableView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
tableView.userInteractionEnabled = YES;
tableView.bounces = YES;
tableView.delegate = self;
tableView.dataSource = self;
[self.view addSubview:tableView];
what are wrong? why don't go the horizontal scroll?
What you are looking for is a UICollectionView, not a UITableView. Here you can implement cells and scroll in either direction.
In Interface Builder when you select the CollectionView it has a property called 'Scroll Direction' - change that to 'horizontal'
From the docs
You were able to access properties related to horizontal scrolling because UITableView is a subclass of UIScrollView, but they aren't meant for use in UITableView
Please take a look at this. This should solve your problem.
https://github.com/alekseyn/EasyTableView
I did this when I was Stuck:
CGRect frame = tblView.frame;
tblView.transform = CGAffineTransformRotate(stressTblView.transform, M_PI / 2);
tblView.frame = frame;
Follow these steps to make a scrollable horizontal table view :
Subclass UIView and create a table view with appropriate frames.
Rotate the table view by -90 degrees ( self.tableView.transform = CGAffineTransformMakeRotation(-M_PI_2);).
Set Autoresizing mask (self.tableView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin);).
Create a cell View and rotate it by 90 degrees and populate the table view with that cell.
implement - (void)handleTapGestureRecognizer:(UITapGestureRecognizer *)tapGesture; delegate method to get the location of the tapped cell and scroll to it automatically.
Hope that helps!!!!
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.
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".
I'm making a horizontal picker by using a UICollectionView. It's simple enough: A UIView with a UICollectionView created programmatically, using UICollectionViewFlowLayout with one section, scrolling set to horizontal. It appears onscreen, complete with the correct data in the correct cells. But it doesn't scroll---in fact it doesn't respond to user interaction at all.
Here's the initializer for the view:
- (id)initWithFrame:(CGRect)frame andItemData:(NSArray *)itemData
{
self = [super initWithFrame:frame];
if (self) {
_itemData = itemData;
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
[flowLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
[flowLayout setItemSize:CGSizeMake(kCellWidth, kCellHeight)];
[flowLayout setMinimumInteritemSpacing:0.f];
[flowLayout setMinimumLineSpacing:0.f];
_collectionView = [[UICollectionView alloc] initWithFrame:[self frame] collectionViewLayout:flowLayout];
[_collectionView setDataSource:self];
[_collectionView setDelegate:self];
[_collectionView setBounces:NO];
[_collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:#"HorizontalPickerCell"];
[self addSubview:_collectionView];
}
return self;
}
I tried programmatically setting UserInteractionEnabled to YES, but that didn't make any difference (nor should it have, since UserInteractionEnabled is set to YES by default). FWIW, the collection view uses standard UICollectionViewCells with UILabels added to their contentViews as subviews.
Any thought as to why this isn't scrolling? Any and all help much appreciated.
Ok, this turned out to be both dumb on my part and easy to fix. I set the frame of the collection view to its parent view's frame rather than its bounds. This caused all sorts of autolayout issues and resulted in touch events simply not registering. All fixed now.
I'd like to call the following method from my view controller class:
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section;
However for the life of me I can't figure out how to do it. I tried:
UIView *view = [tableView viewForHeaderInSection:section];
UIView *view = [self viewForHeaderInSection:section];
UIView *view = [self tableView:viewForHeaderInSection:section];
All give me errors. It's that extra tableView: bit on the beginning. Can anyone give some advice or at least explain what that tableView:(UITableView *)tableView means?
Thanks!
Steve
I don't know why you would want to call it, but if it is implemented in the same object that you're calling it from then you can use self:
UIView* view = [self tableView:tableView viewForHeaderInSection:section];
otherwise, you can get the delegate from the tableView and call the delegate:
id<UITableViewDelegate> theDelegate = tableView.delegate;
UIView* view = [theDelegate tableView:tableView viewForHeaderInSection:section];
Why would you want to call it? This is one of the UITableViewDelegate methods that are normally called automatically when the table is being constructed by the tableView. The tableView class object fills in the parameters that it needs when it makes the call to this method. The view controller only needs to provide the right delegate methods, customized by you, so it can set it up properly.
Did you customize the code, as in this example, in your delegate class?
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
// create the parent view that will hold header Label
UIView* customView = [[UIView alloc] initWithFrame:CGRectMake(10.0, 0.0, 300.0, 44.0)];
// create the button object
UILabel * headerLabel = [[UILabel alloc] initWithFrame:CGRectZero];
headerLabel.backgroundColor = [UIColor clearColor];
headerLabel.opaque = NO;
headerLabel.textColor = [UIColor blackColor];
headerLabel.highlightedTextColor = [UIColor whiteColor];
headerLabel.font = [UIFont boldSystemFontOfSize:20];
headerLabel.frame = CGRectMake(10.0, 0.0, 300.0, 44.0);
// If you want to align the header text as centered
// headerLabel.frame = CGRectMake(150.0, 0.0, 300.0, 44.0);
headerLabel.text = <Put here whatever you want to display> // i.e. array element
[customView addSubview:headerLabel];
return customView;
}
I'm not near my Mac, or I would give you one of my own examples. But this is the general way this method is used.
By the way, you can see that the parameter tableView is not referenced in the sample code above. If you really want to call this method, use nil. UITableViewDelegate protocol allows the controller to be delegate for more than one tableView. If this happens, the method should test to see which tableView is reference, so that specialized behavior can be accommodated for each tableView.
Additional info:
If you just want to see what the height of your tableView's header is, you can evaluate its sectionHeaderHeight property. There are other properties like this, such as sectionFooterHeight and rowHeight.
You should know that delegate methods are there to help the tableView, using your customization. So the delegate method tableView:heightForHeaderInSection: is actually for you to customize the header height. Your delegate methods tells the tableView what the height is. It isn't a way to examine a property of the tableView.
Apples documentation says that if you customize by using tableView:heightForHeaderInSection: then the tableView sectionHeaderHeight is not valid. You would expect this, because that property refers to the height of all of the section headers.
Using the sectionHeaderHeight property, which you can write to in this case, you can set all of the headers to the same height.
Here is some sample code from something I'm working on now. I've added an NSLog statement for you.
resultsTableVC = [[[ResultsTableVC alloc] initWithController:self] retain];
self.tableView = [[[UITableView alloc] initWithFrame:CGRectMake(0, 110, self.view.frame.size.width, self.view.frame.size.height-120) style:UITableViewStyleGrouped] retain];
self.tableView.autoresizingMask = UIViewAutoresizingFlexibleHeight;
self.tableView.autoresizesSubviews = YES;
self.tableView.layer.cornerRadius = 10.0f;
self.tableView.delegate = resultsTableVC;
self.tableView.dataSource = resultsTableVC;
self.tableView.backgroundView = nil;
self.tableView.backgroundColor = [UIColor clearColor];
self.tableView.separatorColor = [UIColor defaultResultTableBackgroundColor];
self.tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
[self.view addSubview:self.tableView];
NSLog(#"header: %f, row: %f", tableView.sectionHeaderHeight, tableView.rowHeight);
(Someone will probably point out that I don't need some of those retains. I'm still working on that.)
This tells me that the standard section height is 100 and the standard row height is 44.0. I have a pointer to my tableView, a property that I can use through this class.
Now if you are setting the header height using tableView:heightForHeaderInSection: then you should have the height already calculated in your program. I don't think you can query for the height of a particular section (or row) once you set it.
Does this help?