I have a bunch of custom UITableViewCells with a label and textbox. I have the textbox disabled but I want to make it so when the user taps the Edit button it will make the textboxes editable. How can I do this so that ALL the UITextFields in the UITableView become enabled?
I have
- (void)setEditing:(BOOL)editing animated:(BOOL)animated {
[super setEditing:editing animated:animated];
[self.navigationItem setHidesBackButton:editing animated:YES];
if (editing) {
}
}
but cannot add the textbox enable in there since I don't have access to all the textfields. Would I need to add code to grab all the cells and loop through them and enable the textfields?
I would do this by setting a isEditing BOOL on your UITableViewDelegate in the setEditing:animated: method and just updating visible cells when the value is changed.
NSArray *visibleCells = [myTable visibleCells];
for (MyTableViewCell *cell in visibleCells)
cell.textField.enabled = isEditing;
Then, using your UITableViewDelegate again, update new cells as they appear in tableView:willDisplayCell:forRowAtIndexPath:
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
cell.textField.enabled = isEditing;
}
Edit your subclass of UITableViewCell and register your instances for an editing notification in your subclass's viewDidLoad or init method:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(disableTextBox) name:#"EditingIsEnabled" object:nil];
And implement a method called disableTextBox that disables the text box for that cell.
Then in your setEditing:animated method, post the notification when you want to start editing:
[[NSNotificationCenter defaultCenter] postNotificationName:#"EditingIsEnabled" object:self];
Override the method dealloc in your UITableViewCell and remove yourself as an observer, or you'll crash:
[[NSNotificationCenter defaultCenter] removeObserver:self];
If you're not using ARC, make sure to call [super dealloc]. If you're using ARC, do not call super.
You can do the same thing when you want to disable all the cells, just post a notification with a different name like EditingIsDisabled.
Let me know if you need me to flesh out the code a bit more.
Edit: I like DBD's method better in this situation.
Related
I have a quite complicated view. What I basicly have is the following
You can see I have a vertical tableview. In each cell I have a horizontal tableview. What I want to do now is when I scroll one horizontal tableview, every other horizontal tableview should scroll also.
In my subClass of the vertical tableviewCell I have the following.
for(HorizontalTableCell *cell in mainTable.subviews){
if([cell isKindOfClass:[HorizontalTableCell class]]){
for(UITableView *cellTable in cell.subviews){
if([cellTable isKindOfClass:[UITableView class]]){
NSLog(#"cell table is table %#",cellTable);
[cellTable setContentOffset:CGPointMake(scrollView.contentOffset.x, 0) animated:NO];
}
}
}
}
But this is not working OK. Can anybody help me with this?
You will need to use the scroll view delegate methods. I'd suggest posting a Notification and then picking it up in the cells like so...
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
[[NSNotificationCenter defaultCenter] postNotificationName:#"CellScrolledHorizontally" object:self.tableView];
}
Then in the horizontal cells you can observe the notification.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(scrolled:) name:#"CellScrolledHorizontally" object:nil];
- (void)scrolled:(NSNotification *)notification
{
UITableView *notificationTableView = notification.object;
if (notificationTableView == self.tableView)
return;
[self.tableView setContentOffset:notificationTableView.contentOffset];
}
Alternatively, use a UICollectionView.
Can u try this logic:
Instead of Horizontal tableviews use a UIScrollView. Now the base is a UITableView on which the horizontal scrollviews. Now use UIScrollview delegate methods for event handling.
Although this is not the solution but you can look at EASYTABLEVIEW
I have a modalViewController that comes up over the top of a viewController with a tableView. When the user clicks a button on the modalViewController I want to reload the tableView within the viewController with this:
[tableView1 reloadData];
I do not want to put the reload in the viewDidAppear or viewWillAppear methods as they get called when i do not need the tableView to reload (i.e. when the user clicks the back button to return to the tableView).
Is there a way to do this?
Try
1) write one method which reloads the table data.
2) Call it on the back button clicked.
This is the classic delegate pattern problem, in your modal view controller you need a delegate reference to the current view controller presenting it
//Modal
#protocol ModalVCDelegate
- (void)tappedBackButton;
#end
#class ModalVC: UIViewController
#property id<ModalVCDelegate> delegate;
#end
#implementation
- (void)backButtonTapped:(id)sender
{
if (self.delegate)
[self.delegate tappedBackButton];
}
#end
Now, in your presenting VC, just process this delegate message
//Parent VC
- (void)showModal
{
ModalVC *vc = [ModalVC new];
vc.delegate = self;
//push
}
- (void)tappedBackButton
{
[self.tableView reloadData];
//close modal
}
You can use delegate . If find it more harder then alternative is to use NSNotificationCenter. You can see accepted answer for Refreshing TableView. This is really very short, easy and understandable way.
using Notification like bellow Method:-
Create NSNotificationCenter at yourViewController's ViewdidLoad Mehod
- (void)viewDidLoad
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(ReloadDataFunction:)
name:#"refresh"
object:nil];
[super viewDidLoad];
}
-(void)ReloadDataFunction:(NSNotification *)notification {
[yourTableView reloadData];
}
Now you can Call this Notification from your modelViewController BackButton or else you want from calling this Refresh notification like putting this line of code:-
[[NSNotificationCenter defaultCenter] postNotificationName:#"refresh" object:self];
NOTE: postNotificationName:#"refresh" this is a key of particular Notification
Try to use this one
Make a Button and click on this button and than you can reload your data.
This button make custom and use it on background.
- (IBAction)reloadData:(id)sender
{
[tblView reloadData];
}
You can use NSNotification to refresh table on ViewController.
Inside viewController :
-(void)dealloc{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
Write code in viewDidLoad:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(reloadMainTable:)
name:#"ReloadTable"
object:nil];
- (void) reloadMainTable:(NSNotification *) notification
{
[tableView reload];
}
Inside ModelViewController:
[[NSNotificationCenter defaultCenter]
postNotificationName:#"ReloadTable"
object:nil];
Here you can also send custom object instead of nil parameter. But be care full about removal of NSNotification observer.
I have a table view with a data source/delegate in another file. In addition, there is a search bar above the table view that belongs to the first file. In other to hide the keyboard when scrolling, I would need to call:
[self.searchBar resignFirstResponder]
But the
(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
method is in the delegate. So how would I hide the keyboard when scrolling in this case?
Thanks!
you could send a notification in scrollviewwillbegindragging. tableview delegate:
-(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{
[[NSNotificationCenter defaultCenter] postNotificationName:#"resign" object:nil];
}
searchbar delegate:
-(void)viewDidLoad{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(goTo:) name:#"resign" object:nil];
}
-(void)goTo:(NSNotification*)notification {
[self.searchBar resignFirstResponder];
}
There are many ways to do,a couple of them are below.
option 1:
add below line after initializing your table object
[yourTableView setKeyboardDismissMode:UIScrollViewKeyboardDismissModeOnDrag];
or
option 2:
Get your tableview's superview(i'm expecting that as aViewcontrollerObj.view) and forcibly end its editing .
-(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
UIView *tableviewSuperView = yourTableView.superview;
[tableviewSuperView endEditing:true];
}
Hope that helps
Happy coding :)
I've noticed that scrollToRowAtIndexPath:atScrollPosition:animated: doesn't scroll to cell that are not currently in view, so If I have 100 cells and I need to get to the one at 70, the call to that selector will do nothing.
Is there a way I can get that cell into memory? I already have the cell's index path...
I need to scroll to that position in my app when the user would want to go there.
Thanks for any thoughts!
EDIT: #dasblinkenlight
- (void)viewDidLoad
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHide) name:UIKeyboardWillHideNotification object:nil];
}
- (void)keyboardWillHide
{
//Load remote cell here then scroll
// :( dont know how to load remote cell yet
}
- (void)keyboardWillShow
{
//Load remote cell here then scroll
// :( dont know how to load remote cell yet
//_cellIndexPath gets assigned on didSelectRowAtIndexPath:
[self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:_cellIndexPath.row inSection:_cellIndexPath.section] atScrollPosition:UITableViewScrollPositionBottom animated:YES];
}
EDIT2:
- (void)keyboardWillShow
{
//Load remote cell here then scroll
[NSThread detachNewThreadSelector:#selector(keyboardWillShowThreaded) toTarget:self withObject:nil];
}
- (void)keyboardWillShowThreaded
{
[NSThread sleepForTimeInterval:2.0];
[self performSelectorOnMainThread:#selector(keyboardWillShowMainThread) withObject:nil waitUntilDone:YES];
}
- (void)keyboardWillShowMainThread
{
//Get the cell
//_textFieldThatHasFirstResponder is a subview in the cell
//This returns null, probably because the cell is not loaded into memory
UITableViewCell *cell = [_textFieldThatHasFirstResponder superview];
NSLog(#"CELL TO SCROLL TO: %#",cell);
NSIndexPath *indexPathForCell = [self.tableView indexPathForCell:cell];
[self.tableView scrollToRowAtIndexPath:indexPathForCell atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
}
OK, I've got the cause of this, see, you have:
NSIndexPath *indexPathForCell = [self.tableView indexPathForCell:cell]; // nil here
[self.tableView scrollToRowAtIndexPath:indexPathForCell atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
When you send indexPathForCell: for an out-of-view cell it returns nil, so tableView doesn't know where to scroll to.
you can implement a delegate so that you can call it from the class where you are in, so that is can update the position
"I've noticed that scrollToRowAtIndexPath:atScrollPosition:animated:
doesn't scroll to cell that are not currently in view, so If I have
100 cells and I need to get to the one at 70, the call to that
selector will do nothing. "
No. it is not true. I have just tried with a tableview with 100 rows. The following code works well.
[tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:78 inSection:0]
atScrollPosition:UITableViewScrollPositionNone animated:YES];
I don't think adding sleep is changing anything. It just delays execution but does not affect the order. Can you check if the index your are passing to scrollToRowAtIndexPath is valid? I remember seeing the same problem myself but it was related to invisible cell. It was impossible to retrieve invisible cell (tableView returned nil) and therefore its index path was nil and thus scrolling failed.
You could store locations of all cells or compute it on the fly and then pass it to
- (void)scrollRectToVisible:(CGRect)rect animated:(BOOL)animated;
It's the only solution I can imagine.
I am sending a notification from one view to another view. My problem is that the notification in the view that I am calling in my cellForRowAtIndexPath method is only getting sent when the tableview is scrolling. How can I stop this and make it send the notification once the images have downloaded? Here is my code: https://gist.github.com/756302
Thanks
MKDev
as far as I understand your code, the message will trigger the reload of the whole table. That should lead to a refresh of the cells.
Thus, you'll need to check in line 76, if the cell is being drawn because a reload was triggered from the finish-message (and the image is now ready to display) or if you need to start the asynchronous download of the image.
The first thing which comes into my mind to check this is to set a property in reloadTableView:
- (void)reloadTableView
{
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"aaa"];
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"name" object:nil];
NSLog(#"removeobserver");
loadImageFinished = YES;
// if your table has several sections you'll need to adopt the section number
NSIndexSet *indices = [[NSIndexSet alloc] initWithIndex:0];
[self.tableView reloadSections:indices withRowAnimation:UITableViewRowAnimationFade];
[indices release];
}
and then to add in
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
...
if (loadImageFinished) {
...
} else {
[asyncImage loadImageFromURL:[NSURL URLWithString:pathImage]];
}
...
}
Note that there could be other reasons why the table is being reloaded - the view could have been disappeared or unloaded and you might not wish to trigger your asynnchronous loading several times.
Your code should work right, when the connectionDidFinishLoading, you call the NSNotificationCenter to send the notification, there is no post method in cellForRowAtIndexPath