How to scroll cutsom UITextFieldCell above UIKeyboard - ios

I have a UITableView that uses a custom UITableViewCell. My UITableVewCell has two textfields inside it, which I have added a tag to in my main ViewController that holds the UITableView which houses my custom UITableViewCell.
So this is the code inside my tableView:cellForRowAIndexPath:
static NSString *CellIdentifier = #"Cell";
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[CustomFCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
NSString *widthString = [currentFDictionary objectForKey:#"MM"];
if ((NSNull *) widthString != [NSNull null]) {
cell.widthTexField.text = widthString;
cell.widthTexField.tag = indexPath.row;
} else {
cell.widthTexField.text = #" ";
}
NSString *heightString = [currentFDictionary objectForKey:#"NM"];
if ((NSNull *) heightString != [NSNull null]) {
cell.heightTextField.text = heightString;
cell.heightTextField.tag = indexPath.row;
} else {
cell.heightTextField.text = #" ";
}
return cell;
I would like to know how to then use this .tag to scroll the UITableViewCell above the UIKeyboard that will now be shown in the view.
Anyhelp would be greatly apprecited.

A simple way i can think of is by using the -scrollToRowAtIndexPath:atScrollPosition:animated:
Set the delegate on the UITextField objects.
cell.widthTexField.delegate = self;
//...
cell.heightTextField.delegate = self;
Now, use -textFieldShouldBeginEditing: delegate method in this manner:
-(BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
NSIndexPath *currentSelectedIndexPath = [self.tableView indexPathForSelectedRow];
[self.tableView scrollToRowAtIndexPath:currentSelectedIndexPath
atScrollPosition:UITableViewScrollPositionTop
animated:YES];
}
//NOTE: this way we don't really need to work with the textField tag per se
//(unless you are using it elsewhere as well)
//Instead, we work with the entire cell and scroll it to the desired position
this may not be perfect since i haven't tested it here but it's the general idea

Related

Get UITableViewCell of UIButton?

I'm trying to perform a segue using a UIButton, which is located within in a custom UITableViewCell class called GFHomeCell.
The GFHomeCell has a postID property, which I want to send in the prepare for segue. I set up a method to run when the button is pressed; however, in the button-pressed method, I need the sender to be a GFHomeCell(or at least that's what I assume).
Does anyone have any ideas how I can do that? Here is my code
My cellForRowAtIndexPath:
GFHomeCell *cell = [tableView dequeueReusableCellWithIdentifier:#"newsfeedCell" forIndexPath:indexPath];
NSDictionary *rootObject = self.posts[indexPath.row];
NSDictionary *post = rootObject[#"post"];
NSDictionary *group = post[#"group"];
NSString *groupName = group[#"name"];
cell.actionLabel.text = [NSString stringWithFormat:#"New post trending on %#", groupName];
cell.descriptionLabel.text = post[#"body"];
cell.descriptionLabel.numberOfLines = 0;
cell.descriptionLabel.lineBreakMode = NSLineBreakByWordWrapping;
cell.likesLabel.text = [NSString stringWithFormat:#"%#", post[#"likes"]];
cell.postId = post[#"id"];
cell.groupName = group[#"name"];
cell.postBody = post[#"body"];
cell.likeButton.tag = indexPath.row;
[cell.likeButton addTarget:self action:#selector(likeButtonClick:) forControlEvents:(UIControlEvents)UIControlEventTouchDown];
[cell.commentButton addTarget:self action:#selector(commentButtonClick:) forControlEvents:(UIControlEvents)UIControlEventTouchDown];
NSString *urlString = [NSString stringWithFormat:#"%s/%#", kBaseURL, #"images/"];
NSURL *url = [NSURL URLWithString:urlString];
[cell.imageView setImageWithURL:url
placeholderImage:[UIImage imageNamed:#"Newsfeed-Image-Placeholder"]];
return cell;
Here is the method I'm running when the button is clicked. My thought was that I need the sender here to be a cell, not a button, as the postId property I'm sending in my prepareForSegue only exists on a GFHomeCell:
- (void)commentButtonClick:(id)sender {
[self performSegueWithIdentifier:#"addCommentSegue" sender:sender];
}
Finally my prepareForSegue(I only included the part relevant to this segue):
} else if ([segue.identifier isEqualToString:#"addCommentSegue"]) {
GFPostShowViewController *destViewController = segue.destinationViewController;
GFHomeCell * cell = sender;
destViewController.postId = [cell.postId copy];
destViewController.groupName = [cell.groupName copy];
destViewController.postBody = [cell.postBody copy];
} else {}
I'm new to iOS and this has me stumped so any help would be much appreciated, thanks.
There are basically two common approaches to this situation. One is to search up through the button's superviews until you find the cell. You shouldn't rely on going up one or two levels, because the hierarchy has changed in the past, and may change again (you need to go up two levels in iOS 6, but 3 in iOS 7). You can do it like this,
-(void)commentButtonClick:(UIButton *) sender {
id superView = sender.superview;
while (superView && ![superView isKindOfClass:[UITableViewCell class]]) {
superView = [superView superview];
}
[self performSegueWithIdentifier:#"addCommentSegue" sender:superView];
}
The other way is to assign a tag to your button in cellForRowAtIndexPath: equal to the indexPath.row (if you only have one section), and then use sender.tag to get the indexPath of the cell that contained the tapped button.
Well, one answer would be to just go up a level in the view hierarchy:
- (void)commentButtonClick:(id)sender {
GFHomeCell * cell = (GFHomeCell *) [(UIButton*)sender superview];
if (cell && [cell Class] == [GFHomeCell class]) {
//do whatever with cell.postID
[self performSegueWithIdentifier:#"addCommentSegue" sender:sender];
}
}
Oh, I forget... you may have to go up two levels to get past the contentView property:
GFHomeCell * cell = (GFHomeCell *) [[(UIButton*)sender superview] superview];

How to get value of uiTextField created programmatically in a uiTableView?

I'm a beginner in iOS and I try to get the value of my uiTextField that I created programmatically.
So my problem is that I create a form in an UITableViewController with a .json file. I have created my form, but I don't know how I can get the different values.
In my cellForRowAtIndexPath I created my different elements (I have textFields, textFields with picker and uiswitch). When the user have finished to fill out the form, he click on a "save" button and it is here that I want to get my values.
If someone can help me and put some code for explain .... :) Thanks.
some of my code :
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
NSString *cellValue = [self getItemName:indexPath.section and:indexPath.row];
cell.textLabel.text = cellValue;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
NSString *itemType=[self getItemType:indexPath.section and:indexPath.row];
NSLog(#"%#",itemType);
if ([itemType isEqualToString:#"text"]) {
UITextField *Reference = [self createTextField];
[cell.contentView addSubview:Reference];
}else if ([itemType isEqualToString:#"checkbox"]) {
UIView *checkbox = [self createCheckbox:indexPath.section and:indexPath.row];
[cell.contentView addSubview:checkbox];
}else if ([itemType isEqualToString:#"picker"]) {
UITextField *Reference = [self createPicker:indexPath.section and:indexPath.row];
[cell.contentView addSubview:Reference];
}else if ([itemType isEqualToString:#"datePicker"]) {
UITextField *Reference = [self createDatePicker];
[cell.contentView addSubview:Reference];
}
return cell;
}
it is here that i create dynamically the elements. For example an uixtField :
-(UITextField*)createTextField{
UITextField *Reference = [[UITextField alloc] initWithFrame:CGRectMake(200 , 10, 200, 40)];
Reference.layer.borderColor=[[UIColor blackColor]CGColor];
Reference.layer.borderWidth=1.0f;
Reference.textAlignment=NSTextAlignmentCenter;
Reference.tag=_tag;
_tag++;
return Reference;
}
http://hpics.li/04b98ca
here it is an example of that i obtained with my dynamical generation.
Use:
[textField setTag:(integer value)]
when you creating fields in cellForRow... method.
Then use in saveMethod this:
[[tableView cellForIndexPath:indexPath] viewWithTag:(integer value)]
for get concrete field of concrete cell.
if ([itemType isEqualToString:#"text"]) {
UITextField *Reference = [self createTextField];
[Reference setTag:1];
[cell.contentView addSubview:Reference];
}
-(void)saveMethod
{
NSString *string = [[[self.tableView cellForRowAtIndexPath:indexPath] viewwithTag:1] text];
}
You can create elements in the method cellForRowAtIndexPath for your cells if after you want to get info from them, because it will be very difficult to get it.
The best way is creating your custom UITableViewCell with all elements you want and after, in the method didSelectRowAtIndexPath to get the info of your elements.
The way I get an indexPath from a view is by checking the superview until I get the parent cell, then using -indexPathForCell:.
- (UITableViewCell *)cellForView:(UIView *)view
{
while (view != nil && ![view isKindOfClass:[UITableViewCell class]]) {
view = view.superview;
}
return (UITableViewCell *)view;
}
- (NSIndexPath *)indexPathForView:(UIView *)view
{
return [self.tableView indexPathForCell:[self cellForView:view]];
}
Overall, this solution will run into problems. Cells do not persist in a table view. As soon as the cell is off the screen it is recycled by the table view.
This means you should not attempt to store data in a cell. A cell is used to present data and get user input, but never store data. Data is meant to be stored in the table data source.
In addition, it means you need to be careful when adding subviews to a cell. As the cell get recycled, the views you added in it's previous use will still be in the cell. You will need to have a cleanup section to -tableView:cellForRowAtIndexPath: to remove all the views you previously added.
My recommendation is to subclass UITableViewCell. You can either have 4 subclasses, one for each JSON type you have, or have 1 subclass which can be instantiated with in the 4 different ways. In my example, I have 1 subclass that can be instantiated 4 different ways.
Keep the different types of cells differentiated by using different reuse identifiers.
Use target/actions and delegates to get input from the controls on the cell.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *cellIdentifier = nil;
NSString *itemType=[self getItemType:indexPath.section and:indexPath.row];
NSLog(#"%#",itemType);
if ([itemType isEqualToString:#"text"]) {
cellIdentifier = #"TextCell";
} else if ([itemType isEqualToString:#"checkbox"]) {
cellIdentifier = #"CheckboxCell";
} else if ([itemType isEqualToString:#"picker"]) {
cellIdentifier = #"PickerCell";
} else if ([itemType isEqualToString:#"datePicker"]) {
cellIdentifier = #"DatePickerCell";
}
MyTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
if ([cellIdentifier isEqualToString:#"TextCell"]) {
cell = [MyTableViewCell textCellWithIdentifier:cellIdentifier];
} else if ([cellIdentifier isEqualToString:#"CheckboxCell"]) {
cell = [MyTableViewCell checkboxCellWithIdentifier:cellIdentifier];
} else if ([cellIdentifier isEqualToString:#"PickerCell"]) {
cell = [MyTableViewCell pickerCellWithIdentifier:cellIdentifier];
} else if ([cellIdentifier isEqualToString:#"DatePickerCell"]) {
cell = [MyTableViewCell datePickerCellWithIdentifier:cellIdentifier];
}
}
NSString *itemName = [self getItemName:indexPath.section and:indexPath.row];
cell.textLabel.text = itemName;
if ([itemType isEqualToString:#"text"]) {
NSString *itemValue = [self getItemValue:indexPath.section and:indexPath.row];
cell.textField.text = itemValue;
} else if ([itemType isEqualToString:#"checkbox"]) {
BOOL itemChecked = [self getItemChecked:indexPath.section and:indexPath.row];
cell.checkbox.selected = itemChecked;
} else if ([itemType isEqualToString:#"picker"]) {
NSString *itemValue = [self getItemValue:indexPath.section and:indexPath.row];
cell.pickerLabel = itemValue;
} else if ([itemType isEqualToString:#"datePicker"]) {
NSDate *itemDate = [self getItemDate:indexPath.section and:indexPath.row];
cell.datePickerLabel = itemDate;
}
return cell;
}
For my problem, I have create a NSMutableDictionaryin which i put my element like that :
key : "name"
value : "UITextField"
Like that i can get the textField everywhere in my class.
in .h file
create the dictionary
in .m
just put the element and when you want to go the text value do :
UITextField* myTextField= [dictionnary objectForKey:key];

SearchBar filtering and adapting the UITableView cells?

My aim is to filter tableview's cells using search bar. The point is i have a button in a custom cell, this button is whether hidden or not it is added to list on the right(this is another uiview)
For instance, i have added one cell using plus button to the right and hide plus button, and filtered using search bar. When i filtered for the cell i have added, it should come with hidden plus button. Since it is already added before filtering.
I have written some code to textDidChange method of the searchBar but still could not do it.
How to achieve this goal?
My tryout code;
-(void)searchBar:(UISearchBar*)searchBar textDidChange:(NSString*)text
{
NSArray *cells = [tableView visibleCells];
for (DoctorListCell *cell in cells)
{
NSLog(#"Cell: %d",cell.plusButton.tag);
if(cell.plusButton.tag==0)
{
[cell.plusButton setHidden:YES];
[tableView reloadData];
}
}
if(text.length == 0)
{
isFiltered = FALSE;
}
else
{
isFiltered = TRUE;
filteredListContent = [[NSMutableArray alloc] init];
for (PlannedCustomer* docs in doctorsTable)
{
NSRange nameRange = [docs.customerName rangeOfString:text options:NSCaseInsensitiveSearch];
if(nameRange.location != NSNotFound)
{
[filteredListContent addObject:docs];
}
}
}
[self.tableView reloadData];
}
Just try to set hidden property of cell in your cellForRowAtIndexpath method after filtering the cells from your filtered list. Or you can set hidden in tableView:willDisplayCell:forRowAtIndexPath:
UPDATED:
If your plus button is a subview then override then set the hidden property in some method in your custom cell class. And then call that method.
Or you can just remove the plus button instead of hiding.
For example:
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSArray *nib;
static NSString *cellIdentifier= #"cell";
UITableViewCell *theCell = [self.tblView dequeueReusableCellWithIdentifier:cellIdentifier];
if([theCell.contentView subviews]){
for(UIView *view in [theCell.contentView subviews]){
[view removeFromSuperview];
}
}
if(theCell== nil)
{
nib = [[NSBundle mainBundle] loadNibNamed:#"Your custom cell name" owner:self options:nil];
theCell = [nib objectAtIndex:0];
theCell.selectionStyle = UITableViewCellSelectionStyleNone;
}
UIButton *btn=(UIButton*)[theCell.contentView viewWithTag:101];
if(yourcondition)
//hide button
else
//show button
}

UILabel inside cell in UITableView is always null (two cell prototypes)

I am trying to populate cells in table view ( I have two custom types of cells with with different elements created in storyboard, with identifiers "info_cell" and "person_cell", on segmented control above UITableView I decide what to load [tableView reload]). When I try to access UILabels inside cell I get that labels are null.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *CellIdentifier = (viewType == INFO_VIEW) ? #"info_cell" :#"person_cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
if(viewType == INFO_VIEW){
NSLog(#"INFO = %#", info_text_some_string);
UILabel *lblInfo = (UILabel *)[cell viewWithTag:200];
[lblInfo setText:info_text_some_string];
}
else{
// there is part for person
}
return cell;
}
Same code works when I have just one prototype cell inside table (UITableView is inside UIVewController). What can be problem here, I have checked 100 times: cell identifiers are OK, label tag is 200.
This is action for UISegmentControl
- (IBAction)changeView:(id)sender {
UISegmentedControl *segmentedControl = (UISegmentedControl *) sender;
NSInteger selectedSegment = segmentedControl.selectedSegmentIndex;
if (selectedSegment == 0) {
viewType = INFO_VIEW;
}
else{
viewType = PERSON_VIEW;
}
[tableView reloadData];
}
I have added and necessary methods for tableView and connect delegate i datasource.
Does anyone have any idea why it is null ?
Try this usually i follow this process whenever i go with custom cell in CellRorRowAtIndexPath
if(!cell)
{
cell =[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
//customcell is your UITableViewCell created by you in ur xib
NSData *archivedData =[NSKeyedArchiver archivedDataWithRootObject:customcell];
cell =[NSKeyedUnarchiver unarchiveObjectWithData:archivedData];
}
if(viewType ==INFO_VIEW)
{
[(UILabel *)[cell viewWithTag:200] setText:#"you text"];
}
else{
// person view....
}
This way your collecting all your elements of your cell and setting value for it. share your results please
Assuming that you have subclass your UITableViewCells correctly (I use InfoCell and PersonCell for example), you can try this:
if(viewType == INFO_VIEW)
{
InfoCell *cell = (InfoCell *)[tableView dequeueReusableCellWithIdentifier:#"info_cell"];
// do your stuff for info here
}
else if(viewType == PERSON_VIEW)
{
PersonCell *cell = (PersonCell *)[tableView dequeueReusableCellWithIdentifier:#"person_cell"];
// do your stuff for person here
}
Why not do something like this?
[[cell textLabel] setText: #"text goes here"];
And skip the UILabel part?

UITableView in UIView in UIScrollview : On tap in UITableView data gets cleared

For work purposes I need to create a UIScrollView which embeds a UIView which in his turn embeds an UITableView via the container feature in Xcode.
My UIScrollView is a full page scrollview with Paging enabled.
My UIView is filled with a UIImage, some UIButton's and a container linking to a UITableView.
On initial launch, the data is loaded perfectly, meaning the UITableView is filled with the data, the UIImage is filled, and the Buttons are placed correctly.
But for some strange reason the when I try to tap or scroll in the UITableView in the container all the data from my UITableView gets cleared.
I'm posting this question here, as I have not found any other similar issue on StackOverFlow or any other website.
UITableViewCode:
- (void)viewDidLoad
{
[super viewDidLoad];
[self.productTable setBackgroundView:nil];
self.productTable.backgroundColor = [UIColor clearColor];
self.productTable.delegate = self;
self.productTable.dataSource = self;
}
- (void) viewDidAppear:(BOOL)animated {
/*CGSize tmp = self.productTable.contentSize;
self.productTable.frame = CGRectMake(0, 0, tmp.width, tmp.height * 3);*/
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
NSLog(#"section count : %i", [self.Products count]);
return [self.Products count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
xcsSectionInfo *sectionInfo = [self.Products objectAtIndex:section];
if (sectionInfo.isOpen == NO) {
return 1;
} else {
return 3;
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
xcsSectionInfo *sectionInfo = [self.Products objectAtIndex:indexPath.section];
if (indexPath.row == 0) {
static NSString *CellIdentifier = #"Header";
xcsProductHeaderCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
cell.articleNumber.text = sectionInfo.product.articleNumber;
cell.articleColor.text = sectionInfo.product.articleColor;
cell.backgroundColor = [UIColor grayColor];
if (sectionInfo.isOpen == YES && sectionInfo == self.currentSectionInfo) {
cell.expandImage.image = [UIImage imageNamed:#"arrow_down.png"];
} else if (sectionInfo.isOpen == NO) {
cell.expandImage.image = [UIImage imageNamed:#"arrow_up.png"];
}
return cell;
} else if (indexPath.row == 1) {
static NSString *CellIdentifier = #"ProductHeader";
xcsProductTitleCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
cell.colorTempHeader.text = #"Color Temperature";
cell.sourceQualityHeader.text = #"Source Quality";
cell.sourceTypeHeader.text = #"Source Type";
cell.luminaireFluxHeader.text = #"Luminaire Flux";
cell.powerConsumptionHeader.text = #"Power Consumption";
cell.luminaireEfficacyHeader.text = #"Luminaire Efficacy";
cell.backgroundColor = [UIColor grayColor];
return cell;
} else if (indexPath.row == 2) {
static NSString *CellIdentifier = #"Product";
xcsProductCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
cell.colorTemp.text = sectionInfo.product.colorTemperature;
cell.sourceQuality.text = sectionInfo.product.sourceQuality;
cell.sourceType.text = sectionInfo.product.sourceType;
cell.luminaireFlux.text = sectionInfo.product.luminaireFlux;
cell.powerConsumption.text = sectionInfo.product.powerConsumption;
cell.luminaireEfficacy.text = sectionInfo.product.luminaireEfficacy;
cell.backgroundColor = [UIColor grayColor];
return cell;
}
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
xcsSectionInfo *sectionInfo = [self.Products objectAtIndex:indexPath.section];
NSIndexPath *path0 = [NSIndexPath indexPathForRow:[indexPath row]+1 inSection:[indexPath section]];
NSIndexPath *path1 = [NSIndexPath indexPathForRow:[indexPath row]+2 inSection:[indexPath section]];
NSArray *indexPathArray = [NSArray arrayWithObjects: path0, path1, nil];
if (sectionInfo.isOpen == NO) {
sectionInfo.isOpen = YES;
[tableView insertRowsAtIndexPaths:indexPathArray withRowAnimation:NO];
} else {
sectionInfo.isOpen = NO;
[tableView deleteRowsAtIndexPaths:indexPathArray withRowAnimation:NO];
}
[self.Products replaceObjectAtIndex:indexPath.section withObject:sectionInfo];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
self.currentSectionInfo = sectionInfo;
[tableView reloadData];
}
Btw.: I'm using storyboards
Regards and thanks in advance.
UPDATE 2:
I think a UIPageViewController would be more appropriate (link‌​). It looks like it accomplishes what you are trying to achieve. And probably much more simple than managing scroll views embedded in other scroll views.
UPDATE:
It looks like what you are trying to achieve is made possible in the UIPageViewController (link). If this works, it would be better than trying to manage scroll views embedded in other views.
Embedding a UITableView is specifically NOT recommended by Apple. Conflicts arise when the system is trying to figure out where to send events:
Important: You should not embed UIWebView or UITableView objects in
UIScrollView objects. If you do so, unexpected behavior can result
because touch events for the two objects can be mixed up and wrongly
handled.
(source)
But here is the stupid part, when you go to the source link, you will notice that appears in the docs for the UIWebView. Apple forgot to include it in the docs for UITableView.

Resources