i have designed a pop over (tableview style) for ipad. Now like in asp.net i want a option at the end, so that if user clicks it he can enter value into it. Can it be done?If so how? I have played with tableviewcellstyles and got a text box as well but for all options. If anybody has done, can you give me some ideas. Thanks.
EDIT : I should have mentioned i am using Monodevelop to develop this app.
One approach, assuming you're using a Storyboard to create view and set properties:
In your UITableView object properties set "content" property to "Dynamic Prototypes".
Then add an additional Table View Cell to your table from the storyboard editor's UI object list (just like adding another label or button or whatever).
You should now have two TableViewCell objects in your table view. If not, add another.
Give both table view cell objects different identifiers (that is, set property "identifier" for each to different strings).
Set up the first cell to display your normal content.
Set up the second cell to display your unique "last row" layout.
In your code, in cellForRowAtIndexPath return the "main" cell for most rows, but the alternate cell for the last row:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// rows are 0-indexed
if (indexPath.row == myDataSource.count) {
NSString *CellIdentifier = #"AlternateCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// populate contents...
}
else {
NSString *CellIdentifier = #"NormalRow";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// populate contents...
}
}
For that to work, you'll have to tell the TableView that there's one more row than you have actual data for:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return myDataSource.count +1;
}
Related
I have a populated array which I can display in the tableview, but I want to hide 3 of the cells text (out of 7 cells). I know the below code is wrong, but in this case I only want to show the text in cell 0.
cell.animal.text[0] = animalarray[0]
cell.animal.hidden = true
Because you don't have codes, I can only use words to describe how it should be done.
You need to have an array of the unwanted text that you do not want to show.
Inside your cellForRowAtIndexPath, you need to have a for loop, to go through the animalarray, and within the for loop, have an if-else statement to check whether if(unwantedtext == animalarray), then cell!.textLabel.text = " "
You need to show me codes for me to help you.
I'm gonna try to help you in Objective C, hopefully I can make the logic so clear the language difference doesn't matter.
Generally you are telling the TableView what to print for each cell in the below delegate method in your ViewController.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
cell.textLable.text = animalArray[indexPath.row];
return cell;
}
This is where you will decided which index in the animalArray you do or do not want to print. If your requirement is a static the simplest is to hardcode the the blocking.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
if(!(indexPath.row == self.indexIDontWantToPrint)) {
cell.textLable.text = animalArray[indexPath.row];
}
return cell;
}
If the indexes you do not want to print is dynamic and submitted to you by say an array.
You need to replace if(!(indexPath.row == self.indexIDontWantToPrint)) with checking if indexPath.row is inside the array of indexes you are to ignore.
NSArray has a handy containsObject method you can use to check if the array contains the current index the tableView wants to print. Be careful of the type difference of indexPath.row is NSInteger while NSArray needs to carry NSNumber for simple numeric numbers.
Adding more efficient logic than jo3birdtalk
1) Instead of having a extra array, you can creat an Object which contains a string & Bool.Add these objects in animalarray
2) Get the object from array at indexpath & check
if(animal.isShow == YES),if Yes show the text else hide label Or set blank string whatever you required
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
Animal * animal = animalArray[indexPath.row];
if(animal.isShow == YES)
{
show the text
}else
{
hide label Or set blank string whatever you requered
}
return cell;
}
I am working with tableviews in iOS. Reusable cells are reloaded when scrolling.
So, when updating -for example- textfields inside a cell, it disappears once scrolling over. I solved it by using an Array that saves all texts in all cells, but I wonder if there's a better way to solve this issue.
Thanks.
Using String array you have to store data of all textfields in tableview.
Use delegate methods of UITableView to implement more efficiently.
-(void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
MyCell * mc = (MyCell *) cell;
names[indexPath.row] = mc.myTf.text;
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
MyCell * mc = (MyCell *) cell;
mc.myTf.text = names[indexPath.row];
}
Here, MyCell is the custom cell which has UITextField. name[] is the NSString array declared at class scope like NSString * names[20].
What you are describing is how tableviews are meant to work! The tableView is a display, not a store, and the reusable cells are only those currently displayed
You are right to use an array (or collection) to hold the data and just use the tableView to display it
for memory management (to releasing memory) tableview remove cell memory which are not displaying in current screen its only keep those cell in memory which are currently displaying on screen so you have to store that text separate from tableview.
You issue can be because of multithreading. If you are reloading data from a GCD operation or any NSOperation(different thread), then you have to use the below code to get the handle to main thread
dispatch_sync(dispatch_get_main_queue(), ^{
//perform the reload activity
});
Yes you are doing right, as cells are reused you need to save your data, something like this -
1 . Have an array to hold your data.
2 . Update your array whenever you make any change in your textFields, so that your UI and data are in sync.
Use this array to populate your tableView.
You need to define the cellIdentifier as unique. Then each cell created with unique identifier.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *CellIdentifier = [NSString stringWithFormat:#"Cell%dR%d",indexPath.section,indexPath.row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier];
//your logic here
}
return cell;
}
I have a simple UITableView
I'm doing my first Edit implementation, to add Delete functionality. Most of this stuff is the default apparently. Pretty much the only method I added to my Controller is
- (void) tableView:(UITableView *)tableView
commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
forRowAtIndexPath:(NSIndexPath *)indexPath
{
Program *victim = Site.current.sortedPrograms[indexPath.row];
[Site.current removeProgram: victim];
[self.tableView
deleteRowsAtIndexPaths: #[indexPath]
withRowAnimation:UITableViewRowAnimationAutomatic];
}
When I hit the Edit button, I see
which is good. But When I hit the minus button on one with a shorter title, I see the following
The title is completely scrolled out of site! Similarly, if I use the iOS 7 swipe left gesture, even on a longer title, the title is scrolled out of view:
The code I use to create the cell is pretty simple:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"ProgramCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
Program *program = Site.current.sortedPrograms[indexPath.row];
cell.textLabel.text = program.name;
cell.detailTextLabel.text = [program.script prettyCycleDuration];
return cell;
}
This isn't what I want my users to see. I would rather see it scroll the title only if necessary, so that context (not whitespace) associates with the delete button. I am just using a stock UITableViewCell (not a subclass), and I'm setting the 'style' to Subtitle. I've looked at the delegate methods, and a book I have, but I don't see anything that shows how to deal with this. Is there a way? Will I need to do my own Cell subclass and handle the states more explicitly? Or is there something else I can do?
Update
Even after converting to a custom subclass, with constraint based layouts for my cell, it still slides the whole view over, rather than compress it.
I'm using storyboard with UITableView in UINavigationController.
In this UITableView, used custom tableViewCell having interior properties.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
CustomTableViewCell *cell = nil;
if (SYSTEM_VERSION_LESS_THAN(#"6.0") ) {
//iOS 6.0 below
cell = [tableView dequeueReusableCellWithIdentifier:#"Cell"];
}
else {
//iOS 6.0 above
cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath]; //work segue
}
Above code work well with push segue. But not when I used
cell = [[CustomTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Cell"]; //not work segue
I used this alloc method for preserve cell's data from reusing cell.
It's just alloc vs deque.. method difference. What am I missing?
edit) I know that not using the dequeReusableCell method is bad for the performance reason. But, the number of cells would not be many. This is why I don't need the deque method.
"not working" means "do not perform push segue", not crash.
It shows cell same like when dequeReusable method used except the disclosure indicator icon at the right of cell. The indicator icon come from storyboard setting.
And when I touch the cell, the cell highlighted blue but the push segue does not performed.
CustomTableViewCell has 4 properties. That's all different from UITableViewCell. Users set the properties at DetailViewController(push segue lead to this). The cell doesn't have IBOutlet ref. In MasterViewController(having the tableView), cellForRowAtIndexPath method returns CustomTableViewCell above code.
cellForRowAtIndexPath method adds a on/off button on the left of indicator on CustomTableViewCell
And set a tag number for the cell.
The use of dequeueReusableCellWithIdentifier is what enables you to use your prototype cell. If you use initWithStyle instead of dequeueReusableCellWithIdentifier, then you don't and you therefore lose any segues, disclosure indicators, other UI appearance that you've defined for those cell prototypes, too.
If you're determined to go this route, you'll have to go "old school" (i.e. do what we all used to do before cell prototypes) and write your own didSelectRowForIndexPath. But if you already have that segue defined, let's say you called it "SelectRow", then your didSelectRowForIndexPath can perform that:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
[self performSegueWithIdentifier:#"SelectRow" sender:cell];
}
If you need to have your disclosure indicator, then your custom cell routine (or the cellForRowAtIndexPath) will have to set that manually. And if you add it with
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
Then you need to manually handle it:
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
[self performSegueWithIdentifier:#"SelectAccessory" sender:cell];
}
Bottom line, you can get this to work, but you're just doing a lot of extra work and losing losing the performance and memory benefits of dequeuing cells. I'd heartily encourage you to revisit the decision to not use dequeueCellWithIdentifier.
I HAVE READ apple documentation and it's not understandable for such a beginner in Objective-C as me. I'm trying to implement multicolumn UITableView following this link example and it just doesn't work so i need to comprehend how cellForRowAtIndexPath work, cause for me personally this method seems pretty complicated.
1) What does it return? UITableViewCell? But why does it look so odd?
-(UITableViewCell *)tableView:(UITableView *)tableView
What is that? Could you please explain?
2) How does it get called and what is more important how am i to connect it to a certain UITableView??? What if i have two UITableView's named firstTableView and secondTableView and i want them to be different (to perform cellForRowAtIndexPath differently)? How am i supposed to link my UITableViews to this
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
the method accepts NSIndexPath, not UITableView. What am i gonna do?
I'll try and break it down (example from documention)
/*
* The cellForRowAtIndexPath takes for argument the tableView (so if the same object
* is delegate for several tableViews it can identify which one is asking for a cell),
* and an indexPath which determines which row and section the cell is returned for.
*/
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
/*
* This is an important bit, it asks the table view if it has any available cells
* already created which it is not using (if they are offScreen), so that it can
* reuse them (saving the time of alloc/init/load from xib a new cell ).
* The identifier is there to differentiate between different types of cells
* (you can display different types of cells in the same table view)
*/
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"MyIdentifier"];
/*
* If the cell is nil it means no cell was available for reuse and that we should
* create a new one.
*/
if (cell == nil) {
/*
* Actually create a new cell (with an identifier so that it can be dequeued).
*/
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"MyIdentifier"] autorelease];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
/*
* Now that we have a cell we can configure it to display the data corresponding to
* this row/section
*/
NSDictionary *item = (NSDictionary *)[self.content objectAtIndex:indexPath.row];
cell.textLabel.text = [item objectForKey:#"mainTitleKey"];
cell.detailTextLabel.text = [item objectForKey:#"secondaryTitleKey"];
NSString *path = [[NSBundle mainBundle] pathForResource:[item objectForKey:#"imageKey"] ofType:#"png"];
UIImage *theImage = [UIImage imageWithContentsOfFile:path];
cell.imageView.image = theImage;
/* Now that the cell is configured we return it to the table view so that it can display it */
return cell;
}
This is a DataSource method so it will be called on whichever object has declared itself as the DataSource of the UITableView. It is called when the table view actually needs to display the cell onscreen, based on the number of rows and sections (which you specify in other DataSource methods).
1) The function returns a cell for a table view yes? So, the returned object is of type UITableViewCell. These are the objects that you see in the table's rows. This function basically returns a cell, for a table view.
But you might ask, how the function would know what cell to return for what row, which is answered in the 2nd question
2)NSIndexPath is essentially two things-
Your Section
Your row
Because your table might be divided to many sections and each with its own rows, this NSIndexPath will help you identify precisely which section and which row. They are both integers. If you're a beginner, I would say try with just one section.
It is called if you implement the UITableViewDataSource protocol in your view controller. A simpler way would be to add a UITableViewController class. I strongly recommend this because it Apple has some code written for you to easily implement the functions that can describe a table. Anyway, if you choose to implement this protocol yourself, you need to create a UITableViewCell object and return it for whatever row. Have a look at its class reference to understand re-usablity because the cells that are displayed in the table view are reused again and again(this is a very efficient design btw).
As for when you have two table views, look at the method. The table view is passed to it, so you should not have a problem with respect to that.
Basically it's designing your cell, The cellforrowatindexpath is called for each cell and the cell number is found by indexpath.row and section number by indexpath.section . Here you can use a label, button or textfied image anything that you want which are updated for all rows in the table.
Answer for second question
In cell for row at index path use an if statement
In Objective C
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *CellIdentifier = #"CellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(tableView == firstTableView)
{
//code for first table view
[cell.contentView addSubview: someView];
}
if(tableview == secondTableView)
{
//code for secondTableView
[cell.contentView addSubview: someView];
}
return cell;
}
In Swift 3.0
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell:UITableViewCell = self.tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier) as UITableViewCell!
if(tableView == firstTableView) {
//code for first table view
}
if(tableview == secondTableView) {
//code for secondTableView
}
return cell
}