What I'm doing?
I'm adding dynamic views to my UITableViewCell (which isn't subclassed).
Cell Hierarchy :
UITableView > UITableViewCell > cell.contentView > MainView > ([Number Of PointView] + [Options View]).
Here it is:
When a user will tap "Add Another Point", I'll add a PointView (which will be same as above) :
Y position [ ] X position [ ]
which will be look like this,
What is my logic to get this done?
I'm taking MainView from cell.contentView.
Then fetch last two views (Point View & Options View) added into MainView.
Add Another PointView in MainView.
Update frames for newly added PointView based on last PointView and also update frame of OptionsView.
Resizing height of MainView
And reloading particular cell.
I'm able to get it work, to confirm I've logged frame and subviews for that MainView. But once I tap on "Add Another Point" button again, I found that MainView isn't updated at all?
My simple question is, if I have a MainView (which I fetch from a Cell), can I update it directly or not?
P.S. I already have a poor solution for this is, to remove MainView and recreate new – which I found unnecessary. Any thoughts?
Short answer, yes you can.
cell.contentView is a placeholder. What you are likely running into is an entirely different problem: UITableViewCells are cached, then recycled and reused by the system.
Anytime you respond to cellForRowAtIndexPath, you basically need to reset the content.
I think what you should do. Just make this one cell class
This one other cell subclass
Use this method to insert your rows and also update your data source for table view that is the number of rows in section part
Your + button on click method can be like this..
//Use your own logic what you want to do.
Update your data source
NSIndexPath* index=[NSIndexPath indexPathForRow:[table count]-1 inSection:0];
NSMutableArray* indexPathArray=[[NSMutableArray alloc]init];
[indexPathArray addObject:index];
//index will be your new added point cell. Updating your datasource
[_myTableView insertRowsAtIndexPaths:indexPathArray
withRowAnimation:UITableViewRowAnimationTop];
Make this YES
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
// Return YES if you want the specified item to be editable.
return YES;
}
Related
So i have a UITableview with 3 different tabs setup.
I want to scroll the table to a specific item.
If user added a new item, table to scroll all the way to the bottom because that's where the item will be added.
If user picks one of the items and edits it, it should come back to the same position on the table. Not scrolled to the top or bottom.
This is what I have:
This is a class variable.
NSIndexpath lastScrollY;
In my ViewWillDisappear :
lastScrollY = this.tableView.IndexPathForSelectedRow() ;
In my ViewWillAppear:
if(lastScrollY != null) {
this.tableView.ScrollToRow(lastScrollY, UITableViewScrollPosition.None, true);
}
this does not seem to work.
And that is only for when user selects a saved item.
What about when then add a new item/row to the table?
Please explain in detail as I am new to this.
Thank you for your time!
For after you add a new cell to your tableView, use the same method you did before, but change the scroll position (this code is in Objective-C, but does the same thing as yours. I'll try to help with a translation if you need one):
[tableView scrollToRowAtIndexPath:indexPath
atScrollPosition:UITableViewScrollPositionBottom
animated:true];
You might also want to set lastScrollY in an override of the method
(void) tableView: (UITableView *) tableView didSelectRowAtIndexPath: (NSIndexPath *)indexPath
using the automatically passed in value indexPath to save to lastScrollY.
Lastly, I'm not sure if this will help, but in your current scrollToRow call, you have it scrolling to "none", try having it scroll to UITableViewScrollPositionTop instead. If that still doesn't work, try calling [tableView reloadData] at the end of your viewWillAppear method, which is probably something along the lines of tableView.reloadData() in your language.
Hope this helps!
This question already has answers here:
How to know the UITableview row number
(10 answers)
How to get UITableView from UITableViewCell?
(21 answers)
Closed 8 years ago.
I've used this code for to get an UIButton from inside my UITableViewCell but it didn't work. So I've debugged it like half an hour to know what superview it in is.
UIButton *button = (UIButton *)sender;
UITableViewCell* cell = (UITableViewCell*)button.superview.superview.superview;
UITableView* tableView = (UITableView*) cell.superview.superview;
NSIndexPath* indexPath = [tableView indexPathForCell:cell];
The question for me is now: How can I know in the future in what hierarchy it is for a UITableView or others? Isn't there a list where I can see how much superviews I need to go without testing it 100 times and set BreakPoints to see what class it refers to?
Regards
You may just end up going with the superview hierarchy route, but know this is not a good idea because Apple could change their table view hierarchy any time. There are much better ways to get the index path for a table view cell given a button inside one of the cells.
If all the buttons are in one section of the table view, simply set each button's tag to the cell's index path row. Then you can recreate the index path knowing which row the button is in.
You can always subclass UITableViewCell and implement the action method for the button inside the subclass. The subclass might call a delegate method to whichever object wanted to know about the button tap.
So hopefully this gives you an idea of the alternatives to what you were doing before. As you said, it's time-consuming to figure out the superview hierarchy and it could change at any time.
If you want to check multiple superview hierarchy then check like that below:-
UIView * view=(UIView*)sender;
while ((view= [view superview])) {
if(viewisKindOfClass:[UITableView class]) {
//your code
return;
}
}
I'm trying to create a view similar to add/edit contact in iOS and there are a few things that are happening, and I'm not sure how they are implemented. Any help in understanding is greatly appreciated.
For each section in contacts i.e. name, phone number, email, etc are these each their own tableview or are these sections within a larger tableview?
When clicking done when adding or editing a contact, the unused tableview cells disappear. Is this using deleteRowsAtIndexPaths:withRowAnimation: or is there a hide method I haven't found? If it is using that method, then when clicking the edit contact button, how does the view brings back these unused tableview cells?
When clicking on a cell in the tableview cell when editing a contact, you are able to change the text. Is this a textfield within a tableview cell or is it actually modifying the label of the tableview cell?
I am not looking for any specific code, as a fairly new programmer I am just trying to understand the strategies/best way to implement these features.
I tried a lot different ways to implement that. the easiest one: Subclass UITableViewCell and overwrite setFrame:. note that this is easy to achieve for grouped tables, but hard for plain ones. in the datasource's tableView:cellForRowAtIndexPath: create an object of this custom cell for the first section. use another identifier for cells of that section, so that only the correct cells will be re-used.
yes, I assume that. The controller has some sort of definition how many cells has to be show in edit mode and how many are actually used with some sort of information. you can easily create a array of indexPaths that must be deleted.
I would do it in tableView:didSelectRowAtIndexPath: by fetching the cell via tableView:cellForRowAtIndexPath:, hide the label and unhide or add a textfield and make this first responder.
code for 1.
the cell
#interface InsetCell : UITableViewCell
#property(nonatomic)CGFloat inset;
#end
#implementation InsetCell
- (void)setFrame:(CGRect)frame {
CGFloat inset;
if (_inset == 0) {
inset = 70; //default value
} else {
inset = _inset;
}
frame.origin.x += inset;
[super setFrame:frame];
}
-(void)setInset:(CGFloat)inset
{
_inset = inset;
[self setNeedsLayout];
}
#end
a project that uses similar code
I'd like to launch my "add item" form in response to touching an empty cell (the next blank cell), sort of like the stock "Reminders" app. didSelectRowAtIndexPath doesn't work for this and I don't have a clue what does.
Thanks
add a button to the tableFooterView
https://developer.apple.com/library/IOs/#documentation/UIKit/Reference/UITableView_Class/Reference/Reference.html
You could add a tap gesture recognizer to the table view, but be sure to test if the user tapped a table view cell or not.
If you wanna the last cell of your table view to be an add button so that you can add a cell directly without putting the table view in edit mode, then here is what you can do:
For the array you use to populate the table view, always make sure the last cell is a dummy object you use to add a row only.
in your -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath, make sure check whether indexPath.row is equal to [array count], if that's the same, then
insert whatever the object you create to your array at index = [array count]-1.
Call your [tableview reload] method. Then you will see the cell append to the table view.
Hope this helps.
I have a UITableview cell that gets a tally from a core data database. The tallyTable is in a view controller inside a UITab view. I have an NSLog statement that prints out the tally value whenever it gets updated. Another tab has a list to change the source (different day) for the tallies. I am using iOS5 with ARC targeting iOS 4.2.
Here's the problem. When I load the application, the correct tallies for whatever the last selected day show up in the table tab. If I then go to the day tab and change the day and return to the tally tab there is no change in the display. However, the viewWillAppear on the tally tab runs and as the table cycles through cellForIndexPath, my NSLog statement prints out all the correct new values. If I then scroll the top label off the screen and back the label updates to the new value.
I've tried setNeedsLayout and setNeedsDisplay on the UILabel, the UITableViewCell, the UITableView and the view controller loading the table. I tried changing the CellReuse identifier so that it would never reuse a cell.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
CollectionItemTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[CollectionItemTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
NSUInteger row = [indexPath row];
cell.textLabel.text = [[self.collectionKeys objectAtIndex:row] valueForKey:#"collectionTitle"];
NSInteger test1 = indexPath.row + 150;
NSLog(#"tag = %i", test1);
cell.tallyButton.tag = test1;
NSNumber * questionID = [[self.collectionKeys objectAtIndex:row] valueForKey:#"answerID"];
cell.tallyLabel.text = [NSString stringWithFormat:#"%i",[self updatePointTotal:questionID]];
NSLog(#"Collection text should be = %#", [NSString stringWithFormat:#"%i",[self updatePointTotal:questionID]]);
[cell setNeedsLayout];
return cell;
}
I've read over a half dozen other similar questions. Got about three hours invested so far in trying to solve this.
EDIT: I thought I fixed it by using the navigation controller to repush the top level view controller on to the view again. I'll admit now this feels like a classically kludgy hack in every way. When the view is PUSHED everything updates and it is seamless. However, in order to have a fixed footer to make selection settings for the table buttons, I used a UIView with two subviews, a UITableView on top and a simple UIView with four buttons below.
The captions on the buttons need to change with the data source. Now when the view controller is pushed onto the view it obscures my fixed footer view. So, I inserted the fixed footer into the UITableview and everything appeared fine until I scrolled the UITableView and the footer scrolled up with it. The table is basically a tally sheet with buttons next to each item and in the footer is four buttons to note the color of the tallied item. Say the next item was a green lego, you would tap "green" in the footer and the button next to "lego" in the table. When I push the view controller with the two subviews the UITableview labels do not update. Thus the tableview needs to be pushed itself (as far as I can tell).
ANSWER: see comment below but ultimately I needed to reload both the visible UITableView data and the delegate UITableView controller data behind it.
I'll give it a shot. First, are you using ARC? If not, you need to add autorelease when you alloc/init a new cell. Otherwise, it's fine as is.
If I'm understanding your question correctly:
The tableView displays the correct data at app launch
You switch away from the tab with the tableView and change the tableView dataSource
You switch back to the tab with the tableView and you see (via NSLog) that the table cells are reloaded with the correct data yet the old data is still visible in the cells
If you scroll a cell off the display and back forcing it to refresh it contains the correct data
Some thoughts:
the tableView will not reload itself automatically when it's view appears. You need to call [tableView reloadData] whenever the dataSource changes. This is independent of whether the tableView is currently displayed or not. My guess is this alone will solve your problem.
You don't need to call setNeedsLayout on the cell unless you want the cell to relayout its subviews based on the data. You also don't need setNeedsDisplay.
I'm assuming there aren't other complicating factors (such as multiple tableViews displaying the same data) that could confuse things.
If you use prepare for reuse method, remember to over the original method with [super prepareForReuse];
Another method if the above way does not work is re setup cell as describe here.
I use the same method i applied for some of my collection view : we should remove/reset your subview where you create/add it to cell 's content. That mean we need set up data each cell completely for each row.
I move the code reset data value from prepare reuse to where i set value and I worked simply !
In my CustomCell.m :
- (void)configCellWith:(id)item At:(NSUInteger)row {
if (_scrollView) {
[[_scrollView subviews]
makeObjectsPerformSelector:#selector(removeFromSuperview)];
_scrollView = nil;
[_scrollView removeFromSuperview];
}
else {
CGFloat y = labelHeight+15;
float scrollHeight = _imgArray.count*200;
_scrollView=[[UIScrollView alloc]initWithFrame:CGRectMake(10, y,SCREEN_WIDTH-20, scrollHeight)];
_scrollView.scrollEnabled=YES;
_scrollView.userInteractionEnabled=YES;
_scrollView.layer.masksToBounds = YES;
[self.contentView addSubview:_scrollView]; } }
Remember to change your data source appropriately too.