I have a tableViewCell in a TableView that gets big if you click on it and if you click it again it goes back to its original size.
What I'd like it to do is, display a datePicker when its big but every time I try to simply add a datePicker in my code it is at the bottom of the tableView and not inside the big cell.
This is my code for adding the datePicker when the cell gets big.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
if (indexPath.row == 0) {
return 150.0;
}
else if ([self cellIsSelected:indexPath] && indexPath.row == 1 ){
[_dateLabel removeFromSuperview]; //just the label of the cell
// Add the picker
UIDatePicker *pickerView = [[UIDatePicker alloc] initWithFrame:CGRectMake(0, 0, 350, 200)];
pickerView.datePickerMode = UIDatePickerModeDate;
[_cell addSubview:pickerView];
return kCellHeight * 4.0;
}
else if (![self cellIsSelected:indexPath]) {
[_myPicker removeFromSuperview];
}
return kCellHeight;
}
How do I add a UIDatePicker to a TableViewCell?
Please take a look at this answer on SO, as it may help you further.
Just remember to set the delegates:
#interface YourTableViewViewController : UITableViewController <UIPickerViewDataSource, UIPickerViewDelegate>
And make sure you return values from these methods:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return <NUM_OF_SECTIONS>;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return <NUM_OF_ROWS_IN_SECTION>;
}
For the rest, it is self-explanatory there.
Related
I have an application where I regularly use a UIDatePicker inside a table view. Therefore, I made custom DatePickerTableViewCell class, which used to work (a couple of years ago, I don't know the exact date). Now that I'm testing everything again on iOS 14, the date picker does not react on my gestures intended to scroll the wheels. Instead, the table view seems to steal the scroll gesture. Even if I don't set the preferred style to 'Wheels', I can't interact with the date picker.
To reproduce it, you need a table view controller with enough cells to make it scrollable (which cells doesn't matter):
#implementation TableViewController
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 20;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return indexPath.row == 0 ? 216 : tableView.rowHeight;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row > 0)
return [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
return [[DatePickerTableViewCell alloc] initWithFrame:CGRectMake(0, 0, 320, 216)];
}
#end
and of course the DatePickerTableViewCell class itself:
#interface DatePickerTableViewCell () {
UIDatePicker *datePicker;
}
#end
#implementation DatePickerTableViewCell
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
datePicker = [[UIDatePicker alloc] initWithFrame:CGRectMake((frame.size.width - 320) / 2, 0, 320, 216)];
datePicker.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleBottomMargin
| UIViewAutoresizingFlexibleRightMargin;
datePicker.datePickerMode = UIDatePickerModeDate;
if (#available(iOS 13.4, *)) {
datePicker.preferredDatePickerStyle = UIDatePickerStyleWheels;
}
[self addSubview:datePicker];
}
return self;
}
#end
The date picker shows, but I'm not able to interact with it:
You're adding the UIDatePicker as a subview of the UITableViewCell subclass rather than as a subview of the UITableViewCellContentView so it's a sibling rather than child of the content view. My guess is the touches are being absorbed by the content view or the content view isn't being instantiated properly since it's never used.
The structure of your cell as it currently stands:
DatePickerTableViewCell
-- DatePicker
-- UITableViewCellContentView
Switching this line:
[self addSubview:datePicker];
to this:
[self.contentView addSubview:datePicker];
within the DatePickerTableViewCell's - (id)initWithFrame:(CGRect)frame should allow the DatePicker to scroll properly and the structure will be:
DatePickerTableViewCell
-- UITableViewCellContentView
---- DatePicker
(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
Above Function is not Getting called when i select the cell inside UITableView which i have inserted inside the footerView of another UITableView
I have added the UITableView inside the below function and I able to see all the items which i have inserted
But I am not able to click on Cells.
I Have Also inserted Some UIButton to check if the click is working ,which working fine
(UIView *)tableView:(UITableView * )tableView viewForFooterInSection:(NSInteger)section
thanks in advance.
- (UIView *)tableView:(UITableView * )tableView viewForFooterInSection:(NSInteger)section {
if(tableView==_ordersListTable)
{
//creating view to pass to footerview
UIView *footerView;
footerView.userInteractionEnabled=true;
if(footerView == nil) {
//allocate the view if it doesn't exist yet
footerView = [[UIView alloc] init];
}
//initializing table
_paymentInfoTable = [[UITableView alloc] initWithFrame:CGRectMake(0, 40, 320, 80)];
_paymentInfoTable.backgroundColor = [UIColor whiteColor];
_paymentInfoTable.delegate = self;
_paymentInfoTable.dataSource = self;
//_paymentInfoTable.separatorStyle = UITableViewCellSeparatorStyleNone;
_paymentInfoTable.separatorInset = UIEdgeInsetsMake(0, 110, 0, 180);
[footerView addSubview:_paymentInfoTable];
}
//return the view for the footer
return footerView;
} else
{
return 0;
}
}
Since you have two UITableViews to control, the delegates of both the UITableViews have to be set correctly. Did you set these delegates?
By checking the UITableView in the delegate methods, you can control both UITableViews:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (tableView == self.tableView1) {
// Do your thing with the first UITableView
}
else {
// Do your thing with the other UITableView
}
}
my platform is ios8 and xcode 6.3.1
tableview's delegate like this:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 3;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 1;
}
so, the delegate of heightForRowAtIndexPath: should be execute three times , but my code execute four, why ?
My code :
init tableView
- (void)setupTableView {
_selectTableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
_selectTableView.delegate = self;
_selectTableView.dataSource = self;
_selectTableView.separatorStyle = UITableViewCellSeparatorStyleNone;
[self.view addSubview:_selectTableView];
}
other delegate method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSInteger section = indexPath.section;
static NSString *identified = #"selectCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identified];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identified];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
return [self cellWith:cell andSection:section];
}
- (UITableViewCell *)cellWith:(UITableViewCell *)cell andSection:(NSInteger)section {
....
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
CGFloat height = 0;
if (section != SVCellTypeHot) {
height = 5;
}
return height;
}
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section {
UIView *footerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, kScreenSize.width, 5)];
[footerView setBackgroundColor:[UIColor lightGrayColor]];
return footerView;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
CGFloat height = 0;
switch (indexPath.section) {
case SVCellTypeBanner:
{
height = kHeaderViewHeigth;
}
break;
case SVCellTypeRecommand:
{
height = kRecommandViewHeight;
}
break;
case SVCellTypeHot:
{
height = kHotViewHeight;
}
break;
default:
break;
}
return height;
}
heightForRowAtIndexPath allows the delegate to specify rows with varying heights. If this method is implemented, the value it returns overrides the value specified for the rowHeight property of UITableView for the given row. There is no guarentee that this method can only be called 'section count * item count' times in the UITableView. As you can tell from its name, it will calculate the height for the cells at IndexPath, so combining the re-using technique, this method will be called many times, as long as it needs to calculate the height for cell at IndexPath
So actually, it is a system behaviour to decide how many times it should be called and when. In your comment, it seems like something changed in indexPath {1-0} so heightForRowAtIndexPath is called twice for {1-0}. You might need to check have you changed any content that cause iOS to re-calculate the cell's height.
Without knowing more details, this is the best we can do to provide you some clues to debug. However, you should not rely on how many times it calls heightForRowAtIndexPath, again, this can be called at any time, as long as you scroll or change any frame inside that cell
heightForRowAtIndexPath: will execute as many times as it needs to. If you are scrolling, for example, it will execute as offscreen cells are about to come onscreen. That method should always be able to provide the correct height and you normally shouldn't be concerned with how often it's called. cellForRowAtIndexPath: executes 3 times as it should.
I created one tableview with 2 section and i displayed the array of the data in the tableview .. now i want to expand and collapse the section…
i am just a beginner please give any sample code for expand and collapse the tableview section…
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 2;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [arraytable count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellitem = #"simpletableitem";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellitem];
if (!cell) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellitem];
}
cell.textLabel.text = [arraytable objectAtIndex:[indexPath row]];
return cell;
}
This is my cellForRowAtIndexPath and arraytable is my array i give it in view did load
arraytable = #[#"hari12",#"narayanan",#"Praba",#"Deepak",#"Sailesh",#"Ram charan"];
Here's a sample code I've made to achieve what you want.
You can use this as a general guideline, since there are plenty of ways to achieve this, other than what I've done.
I've noticed from your example above that you have a table view with 2 sections, so this is what I'll use for the sample code.
There are maybe better ways to implement the below, but that was at the top of my head, and I think it's pretty simple and straightforward.
I've also included explanations as comments in the code below.
Note that you'll probably need to change some variables' names to fit your code (such as self.tableView, if you use something else) and section1DataArray, section2DataArray
// I've declared 2 BOOL properties to hold whether each section is visible or not
#interface ViewController ()
#property (nonatomic) BOOL section1visible, section2visible;
#end
-(void)viewDidLoad {
// After creating the table view, I've set the footer view frame to CGRectZero,
// so when a table view is collapsed you won't have the table columns 'bounds'
self.tableView.tableFooterView = [[UIView alloc] initWithFrame: CGRectZero];
}
// Then I've created a custom header for each table since I've wanted to make the header
// name a button which collapse/expand the table view.
-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
// Here I've set the height arbitrarily to be 50 points
return 50;
}
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
// Change the below frame to fit your needs. In my example, I've used a table view
// to be at the width of the screen, and the height of 50 points (as we've set above)
UIView *header = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 50)];
// Then create a button
// I've arbitrarily chosen a size of 100x20 and created a frame to be placed in the
// middle of the above header
UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(header.frame.size.width/2 - 50, header.frame.size.height/2 - 10, 100, 20)];
// Now I'm setting the tag (for later use) and title of each button
if(section == 0) { // First section
[button setTitle:#"Section 1" forState:UIControlStateNormal];
button.tag = 0;
} else { // Else, second section, since we only have two
[button setTitle:#"Section 2" forState:UIControlStateNormal];
button.tag = 1;
}
// I've arbitrarily chose to set the button colour to gray colour
button.titleLabel.textColor = [UIColor grayColor];
// Then we need to actually add an action to the button
[button addTarget:self action:#selector(updateTableView:) forControlEvents:UIControlEventTouchUpInside];
// Then we need to add the button to the header view itself
[header addSubview:button];
return header;
}
// Then we need to update our tableView:numberOfRowsInSection: to check for our BOOL value
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if(section == 0 && self.section1visible) {
return [self.section1DataArray count];
} else if (section == 1 && self.section2visible) {
return [self.section2DataArray count];
} else {
return 0;
}
}
// Then we need to create the actual method the button calls
-(void)updateTableView:(UIButton *)sender {
// Check the button tag, to identify which header button was pressed
NSInteger section = sender.tag;
if(section == 0) {
self.section1visible = !self.section1visible;
} else { // section == 1
self.section2visible = !self.section2visible;
}
// Use an animation to update the UI to create a 'smooth' expand/collapse
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:section] withRowAnimation:UITableViewRowAnimationFade];
}
Good luck mate.
I am trying to get section header view using this code:
[tableView headerViewForSection:indexPath.section];
but this code always returns me nil.
Could you give me some examples to get section header view from table view?
This is my viewForHeader implementation:
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
DynamicHeader *headerView = [[DynamicHeader alloc] init];
headerView.frame = CGRectMake(0, 0, 320, 40);
UILabel *headerLbl = [[UILabel alloc] init];
headerLbl.frame = CGRectMake(10, 10, 300, 20);
if(((SectionViewController *)sharedInstance.currentViewController).currentSectionType == 25)
{
UIImageView *imgView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"minus.png"]];
imgView.frame = CGRectMake(285, 14.5, 16, 13);
[headerView addSubview:imgView];
UITapGestureRecognizer *recognizer = [[UITapGestureRecognizer alloc] initWithTarget:sharedInstance action:#selector(headerTap:)];
[headerView addGestureRecognizer:recognizer];
headerView.tableView = tableView;
headerView.heightForRows = 95;
headerView.isOpen = YES;
}
headerLbl.text = [[[[[((SectionViewController *)sharedInstance.currentViewController).responseDictionary valueForKey:DATA_PARAMETER] valueForKey:SECTION_TABLE_PARAMETER] objectAtIndex:section] valueForKey:TABLE_SECTION_HEADER] capitalizedString];
[headerView addSubview:headerLbl];
return headerView;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if((DynamicHeader *)[tableView headerViewForSection:indexPath.section] != nil)
{
return ((DynamicHeader *)[tableView headerViewForSection:indexPath.section]).heightForRows;
}
else
{
return 95;
}
}
- (void)headerTap: (UITapGestureRecognizer *)recognizer
{
DynamicHeader *view = (DynamicHeader *)[recognizer view];
if(view.isOpen)
{
view.heightForRows = 0;
}
else
{
view.heightForRows = 95;
}
view.isOpen = !view.isOpen;
[view.tableView beginUpdates];
[view.tableView endUpdates];
}
Quite old question, but maybe a solution is helpful to others too...
An UITableView does create cell, header and footer views only if they are needed (e.g. they are visible in the table view content area).
If the cell, header or footer view isn't visible in the table view, a call to 'cellForRowAtIndexPath:', 'headerViewForSection:' or 'footerViewForSection:' might return 'nil'.
(See UITableView.h for documentation of this behaviour. The only exception would be, that the view has not jet been recycled by the table view)
Of course you can create any table view subview by calling the responsible delegate method directly, but UITableView wouldn't do so by itself.
So the solution to access a cell, header oder footer view is to make it visible in the table view first.
An example for an header view:
CGRect sectionHeaderRect = [self.tableView rectForHeaderInSection:groupSectionIndex];
[self.tableView scrollRectToVisible:sectionHeaderRect
animated:NO];
// Let the tableview load the needed views
dispatch_async(dispatch_get_main_queue(), ^{
UITableViewHeaderFooterView* groupSectionHeaderView = [self.tableView headerViewForSection:sectionIndex];
// Use groupSectionHeaderView
});
Use this delegate method to access the header view:
- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section
Have you implemented
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
and
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section;
in your ViewController subclass?
And if yes, probably you have some problem in one of these methods.
Your header view must inherit from UITableViewHeaderFooterView or else this call will not work and always returns nil.
Where are you calling [tableView headerViewForSection:indexPath.section];?
If you are calling it in - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath before the tableView is visible then you will get nil back as the tableView is not setup yet.
If you call it else where once the tableView is loaded, you should get a UITableViewHeaderFooterView back.
heightForRowAtIndexPath called before viewForHeaderInSection so of course you will get nil.