What is the most appropriate method for reloading my view controller?
To expand upon the scenario, I have a UITableView having populated cells within a View Controller.
I create new cells by transitioning to a new "Create Cell" view controller, however when I call the dismissViewControllerAnimated function, the new cell does not appear.
I cannot use a segue as the initial view controller is a component of a tab bar view controller, so the tab bar disappears if I segue from the "Create Cell" view controller.
Then how can I reload the view, upon a successful dismissal of the "Create Cell" view controller?
Thanks in advance.
Code, in question, that needs refreshing (Implemented the non-working notification method):
#interface MyListings ()
#property (weak, nonatomic) IBOutlet UIButton *createListingButton;
#property (weak, nonatomic) IBOutlet UITableView *tableView;
#property (strong, nonatomic) ListingModel *listItem;
#property (strong, nonatomic) UserModel *usr;
#end
#implementation MyListings
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(newCellCreated:)
name:#"newCellCreated"
object:nil];
self.listItem = [[ListingModel alloc] init];
self.usr = [[UserModel alloc]init];
NSDate *currentDateTime = [NSDate date];
FIRUser *user = [FIRAuth auth].currentUser;
if ([self.usr getDataForUser:user.email])
{
if ([self.listItem getDataForUser:[NSString stringWithFormat:#"%d", self.usr.user_id]])
{
NSLog(#"Got listings");
};
}
titles = self.listItem.title;
currentBids = self.listItem.starting_bid;
stillAvailables = self.listItem.timer;
listingIDs = self.listItem.listing_id;
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];
[dateFormatter setDateFormat:#"YYYY/MM/dd"];
for(int idx = 0; idx < [self.listItem.listing_id count]; idx++)
{
NSDate *d1 = [dateFormatter dateFromString:self.listItem.timer[idx]];
if([d1 compare:currentDateTime] == NSOrderedDescending)
{
stillAvailables[idx] = #"Expired";
}
else
{
stillAvailables[idx] = #"Available";
}
}
_createListingButton.layer.cornerRadius = 8;
_createListingButton.layer.borderWidth = 1.5f;
_createListingButton.layer.borderColor = [UIColor whiteColor].CGColor;
[_createListingButton addTarget:self action:#selector(createListingButtonHighlightBorder) forControlEvents:UIControlEventTouchDown];
[_createListingButton addTarget:self action:#selector(createListingButtonUnhighlightBorder) forControlEvents:UIControlEventTouchUpInside];
[_createListingButton addTarget:self action:#selector(createListingButtonUnhighlightBorder) forControlEvents:UIControlEventTouchDragExit];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
- (UIStatusBarStyle)preferredStatusBarStyle
{
return UIStatusBarStyleLightContent;
}
- (void) newCellCreated:(NSNotification *) notification
{
if ([[notification name] isEqualToString:#"newCellCreated"])
[self.tableView reloadData];
}
- (void)createListingButtonHighlightBorder
{
_createListingButton.layer.borderColor = [UIColor colorWithRed:0.61 green:0.00 blue:0.02 alpha:1.0].CGColor;
}
- (void)createListingButtonUnhighlightBorder
{
_createListingButton.layer.borderColor = [UIColor whiteColor].CGColor;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return titles.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
MyListingsTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"MyListingsTableViewCell"];
[cell updateCellWithTitle:[titles objectAtIndex:indexPath.row] currentBid:[currentBids objectAtIndex:indexPath.row] stillAvailable:[stillAvailables objectAtIndex:indexPath.row] listingID:[listingIDs objectAtIndex:indexPath.row]];
cell.backgroundColor = [UIColor clearColor];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self performSegueWithIdentifier:#"editListing" sender:self];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"editListing"])
{
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
EditListing *destController = segue.destinationViewController;
destController.listId = self.listItem.listing_id[indexPath.row];
}
}
You can have notification or delegate methods.
As you didn't post any piece of code, replace the names as your convenience.
I'll give you a short example using notification.
In your TableViewController:
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: "newCellCreated"), object: nil, queue: nil) { (notification) in
self.tableView.reloadData()
}
}
In your CreateCellViewController:
func closeView() {
self.dismiss(animated: true) {
NotificationCenter.default.post(NSNotification.Name(rawValue: "newCellCreated"))
}
}
EDIT - Objective C version
In your TableViewController:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(newCellCreated:)
name:#"newCellCreated"
object:nil];
}
- (void) newCellCreated:(NSNotification *) notification
{
if ([[notification name] isEqualToString:#"newCellCreated"])
[self.tableView reloadData];
}
In your CreateCellViewController:
-(void) closeView {
[self dismissViewControllerAnimated:NO completion:^{
[[NSNotificationCenter defaultCenter]
postNotificationName:#"newCellCreated"
object:self];
}];
}
Related
I have a problem with connecting a modal segue with a view controller.
In my storyboard, I have a uicollectionview controller connecting a modal segue to a table view embedded in a uiviewcontroller.
The table view contains "filters" to filter the cells in my collection view.
So far I have been able to load the view controller when the user clicks on a button in an action sheet, which opens when the user clicks a bar button item called "more"
PICTURES
My collection view:
The UIActionSheet:
My Filters View Controller
So the problem I am having is when I click the "filters" button in the action sheet, it loads the filters view controller, and when I press the "cancel" button, I am able to close the view controller from my collection view. However, when I press the "Done" button, my collection view disappears.
My Code
MainViewController.m (Collection view)
-(void)openActionSheet {
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:#"What else would like to do?"
delegate:self
cancelButtonTitle:#"Cancel"
destructiveButtonTitle:nil
otherButtonTitles:#"About Backpack", #"Filters", nil];
[actionSheet showInView:self.view];
}
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
NSString *buttonTitle = [actionSheet buttonTitleAtIndex:buttonIndex];
if ([buttonTitle isEqualToString:#"Filters"]) {
[self showFilters];
}
}
#pragma mark UISearchBarDelegate
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
[self applyFilters:[NSSet setWithObject:searchBar.text]];
[searchBar resignFirstResponder];
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
[searchBar resignFirstResponder];
}
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
if (![searchText length]) {
self.dataSource = self.originalDataSource;
self.imageData = self.originalImageData;
[self.collectionView reloadData];
}
}
#pragma mark FiltersViewControllerProtocol
// "Done" button
- (void)filtersSelected:(NSSet *)filters {
[self hideFilters];
[self applyFilters:filters];
}
//"Cancel" button
- (void)filterSelectionCancelled {
[self hideFilters];
}
#pragma mark private
- (void)showFilters {
if (!self.fvc) {
self.fvc = [self.storyboard instantiateViewControllerWithIdentifier:#"filters"];
self.fvc.delegate = self;
_fvc.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentViewController:_fvc animated:YES completion:nil];
}
}
-(void)hideFilters {
[_fvc dismissViewControllerAnimated:YES completion:nil];
}
- (void)applyFilters:(NSSet *)filters {
NSMutableArray *newData = [NSMutableArray array];
NSMutableArray *newItems = [NSMutableArray array];
for (NSString *s in _dataSource) {
for (NSString *filter in filters) {
if ([s rangeOfString:filter options:NSCaseInsensitiveSearch].location != NSNotFound) {
[newData addObject:s];
break;
}
}
}
for(NSInteger i = 0; i < newData.count; i++) {
NSInteger loc = [self locationOfItemGivenName:newData[i]];
backpackIcons *item = _backpackItems[loc];
[newItems addObject:item.image_url];
}
self.dataSource = newData;
self.imageData = newItems;
[self.collectionView reloadData];
}
- (NSInteger)locationOfItemGivenName:(NSString *)name {
NSInteger found = -1;
for(NSInteger i = 0; i < _backpackItems.count; i++) {
backpackIcons *item = _backpackItems[i];
if([item.name isEqualToString:name]) {
found = i;
}
}
return found;
}
FiltersViewController.h (filters table view)
#import <UIKit/UIKit.h>
#protocol FiltersViewControllerProtocol <NSObject>
- (void)filtersSelected:(NSSet *)filters;
- (void)filterSelectionCancelled;
#end
#interface FiltersViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
#property (nonatomic, weak) id<FiltersViewControllerProtocol> delegate;
#end
FiltersViewController.m
#import "FiltersViewController.h"
#interface FiltersViewController ()
#property (nonatomic, strong) NSMutableSet *selectedRowObjects;
//#property (nonatomic, strong) NSArray *filters;
#end
#implementation FiltersViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.selectedRowObjects = [NSMutableSet setWithCapacity:10];
}
- (IBAction)filtersSelected:(id)sender {
[self.delegate filtersSelected:self.selectedRowObjects];
}
- (IBAction)cancelFilterSelection:(id)sender {
[self.delegate filterSelectionCancelled];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 10;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"filter" forIndexPath:indexPath];
cell.textLabel.text = [NSString stringWithFormat:#"%u", indexPath.row];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
NSString *obj = cell.textLabel.text;
if (cell.accessoryType == UITableViewCellAccessoryCheckmark) {
cell.accessoryType = UITableViewCellAccessoryNone;
[self.selectedRowObjects removeObject:obj];
}
else {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
[self.selectedRowObjects addObject:obj];
}
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
#end
Another problem I have having is that the filters table view is not loading my cell labels as well.
I appreciate all help. Thanks to anyone who can!
Im making a program where im practicing UIPopoverController's for iPad
in the first popover i have a tableView with some cells , what i want to do is to call a new view with a textfield so i can add new cells with the textfield text .
The problem i have is that when i dismiss the second view the tableView is not updated . I can't call reloadData because the first view don't call "viewWillAppear" ou any other .
In the iphone simulator it works well because iphone don't use uiPopoverController but in iPad i have to dismiss the first popover and the view only reloads when i enter the second time.
I know by reading some posts that its possible to use notification center to make it happen but i don't know how
My code is this
-first view , the tableView
BNRAssetTypeViewController.h
#import <Foundation/Foundation.h>
#class BNRItem;
#interface BNRAssetTypeViewController : UITableViewController
#property (nonatomic,strong) BNRItem *item;
#property (nonatomic, copy) void (^dismissBlock)(void);
#end
BNRAssetTypeViewController.m
#import "BNRAssetTypeViewController.h"
#import "BNRItem.h"
#import "BNRItemStore.h"
#import "BNRDetailViewController.h"
#import "AddNewAssetedTypeViewController.h"
#implementation BNRAssetTypeViewController
-(instancetype)init
{
//Chamar o designated initializer
self = [super initWithStyle:UITableViewStylePlain];
if (self) {
//Titulo
UINavigationItem *navItem = self.navigationItem;
navItem.title=#"New Asseted Type";
//Criar um novo bar button que faz novo item do lado direito
UIBarButtonItem *bbi =[[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemAdd
target:self action:#selector(addNewAssetedType)];
//meter do lado direito
navItem.rightBarButtonItem=bbi;
}
return self;
}
-(instancetype)initWithStyle:(UITableViewStyle)style
{
return [self init];
}
-(void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"ViewDidLoad");
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"UITableViewCell"];
}
-(void)viewWillAppear:(BOOL)animated
{
NSLog(#"ViewwillApear");
[self.tableView reloadData];
}
-(void)viewDidAppear:(BOOL)animated{
NSLog(#"ViewDidApear");
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [[[BNRItemStore sharedStore]allAssetTypes]count];
}
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"UITableViewCell" forIndexPath:indexPath];
NSArray *allAssetTypes = [[BNRItemStore sharedStore]allAssetTypes];
NSManagedObject *assetType = allAssetTypes[indexPath.row];
// Use key-value coding to get the asset type's label
NSString *assetLabel = [assetType valueForKey:#"label"];
cell.textLabel.text = assetLabel;
// Checkmark the one that is currently selected
if (assetType == self.item.assetType) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
} else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
cell.accessoryType=UITableViewCellAccessoryCheckmark;
NSArray *allAssets = [[BNRItemStore sharedStore]allAssetTypes];
NSManagedObject *assetType = allAssets[indexPath.row];
self.item.assetType=assetType;
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) {
self.dismissBlock();
} else {
[self.navigationController popViewControllerAnimated:YES];
}
}
-(void)addNewAssetedType{
AddNewAssetedTypeViewController *anatvc = [[AddNewAssetedTypeViewController alloc]init];
UINavigationController *navController = [[UINavigationController alloc]initWithRootViewController:anatvc];
navController.modalPresentationStyle=UIModalPresentationCurrentContext;
[self.navigationController presentViewController:navController animated:YES completion:nil];
}
-The second View
AddNewAssetedTypeViewController.h
#import <UIKit/UIKit.h>
#interface AddNewAssetedTypeViewController : UIViewController <UITextFieldDelegate>
#property (nonatomic,copy) void (^dismissBlock)(void);
#end
AddNewAssetedTypeViewController.m
#import "AddNewAssetedTypeViewController.h"
#import "BNRItemStore.h"
#import "BNRAssetTypeViewController.h"
#interface AddNewAssetedTypeViewController ()
#property (weak, nonatomic) IBOutlet UITextField *textField;
#end
#implementation AddNewAssetedTypeViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
UIBarButtonItem *doneItem = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemDone
target:self
action:#selector(save:)];
self.navigationItem.rightBarButtonItem=doneItem;
UIBarButtonItem *cancelItem = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemCancel
target:self action:#selector(cancel:)];
self.navigationItem.leftBarButtonItem=cancelItem;
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
-(void) viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[self.view endEditing:YES];
[[BNRItemStore sharedStore] createAssetType:self.textField.text];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)cancel:(id)sender
{
[self.presentingViewController dismissViewControllerAnimated:YES
completion:nil];
}
-(void)save:(id)sender
{
[self.presentingViewController dismissViewControllerAnimated:YES
completion:nil];
}
#end
Olá!
You can fire a notification using NSNotificationCenter when something is added in the popover. First, register the first view controller to observe for that notification. In the first VC retain a reference to the observer you'll register later on:
#implementation BNRAssetTypeViewController {
id _observer;
}
In viewWillAppear:
_observer = [[NSNotificationCenter defaultCenter] addObserverForName:#"somethingAddedNotification"
object:nil
queue:nil
usingBlock:^(NSNotification *notification)
{
[self.tableView reloadData];
}];
In viewWillDisappear:
- (void)viewWillDisappear:(BOOL)animated {
[[NSNotificationCenter defaultCenter] removeObserver:_observer];
}
Then in the method save: in the second view controller:
[[NSNotificationCenter defaultCenter] postNotificationName:#"somethingAddedNotification" object:nil];
Disclaimer: untested code. Let me know how it goes.
I have a simple notes app where I have just 2 view controllers:
table view controller - to list all the notes.
view controller - to create new notes.
In the table view controller I have a segue from a cell back to the creation page where a user can edit the note in this specific cell.
But my problem is that when I'm preforming editing to a certain cell(note) I'm creating a new note with the content of what I edited...
So instead of passing the note content in the prepareForSegue method I need to pass the note object...
How can I do that?
this are my classes:
NMNote: (correctly just containing a property of *content, will add more behaviour later)
#import <Foundation/Foundation.h>
#interface NMNote : NSObject
#property (strong, nonatomic) NSString *content;
#end
NMCreateNotesViewController.h:
#import <UIKit/UIKit.h>
#import "NMNote.h"
#interface NMCreateNotesViewController : UIViewController
#property (strong, nonatomic) NMNote *note;
#property (weak, nonatomic) IBOutlet UITextView *textField;
#property (strong, nonatomic) NSString *passedInString;
#end
NMCreateNotesViewController.m:
#import "NMCreateNotesViewController.h"
#import "NMNotesListViewController.h"
#interface NMCreateNotesViewController () <UITextViewDelegate>
#property (weak, nonatomic) IBOutlet UIBarButtonItem *saveButton;
#end
#implementation NMCreateNotesViewController
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// listen for keyboard hide/show notifications so we can properly adjust the table's height
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:nil];
}
#pragma mark - Notifications
- (void)adjustViewForKeyboardReveal:(BOOL)showKeyboard notificationInfo:(NSDictionary *)notificationInfo
{
// the keyboard is showing so ƒ the table's height
CGRect keyboardRect = [[notificationInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
NSTimeInterval animationDuration =
[[notificationInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
CGRect frame = self.textField.frame;
// the keyboard rect's width and height are reversed in landscape
NSInteger adjustDelta = UIInterfaceOrientationIsPortrait(self.interfaceOrientation) ? CGRectGetHeight(keyboardRect) : CGRectGetWidth(keyboardRect);
if (showKeyboard)
frame.size.height -= adjustDelta;
else
frame.size.height += adjustDelta;
[UIView beginAnimations:#"ResizeForKeyboard" context:nil];
[UIView setAnimationDuration:animationDuration];
self.textField.frame = frame;
[UIView commitAnimations];
}
- (void)keyboardWillShow:(NSNotification *)aNotification
{
[self adjustViewForKeyboardReveal:YES notificationInfo:[aNotification userInfo]];
}
- (void)keyboardWillHide:(NSNotification *)aNotification
{
[self adjustViewForKeyboardReveal:NO notificationInfo:[aNotification userInfo]];
}
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if (sender != self.saveButton) return;
if (self.textField.text.length > 0) {
self.note = [[NMNote alloc] init];
self.note.content = self.textField.text;
}
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
if (self.passedInString != nil) {
self.textField.text = self.passedInString;
}
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
NMNotesListViewController.h:
#import <UIKit/UIKit.h>
#interface NMNotesListViewController : UITableViewController
- (IBAction) unwindToList: (UIStoryboardSegue *) segue;
#end
NMNotesListViewController.m:
#import "NMNotesListViewController.h"
#import "NMCreateNotesViewController.h"
#interface NMNotesListViewController ()
#property (strong, nonatomic) NSMutableArray *notes;
#end
#implementation NMNotesListViewController
- (IBAction) unwindToList: (UIStoryboardSegue *) segue
{
NMCreateNotesViewController *source = [segue sourceViewController];
NMNote *note = source.note;
if (note != nil) {
[self.notes addObject:note];
[self.tableView reloadData];
}
}
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.notes = [[NSMutableArray alloc] init];
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
- (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.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [self.notes count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"NotesPrototypeCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Configure the cell...
NMNote *note = [self.notes objectAtIndex:indexPath.row];
cell.textLabel.text = note.content;
return cell;
}
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(UITableViewCell *)sender
{
if ([[segue identifier] isEqualToString:#"noteSegue"]) {
NMCreateNotesViewController *destination = [segue destinationViewController];
NSInteger indx = [self.tableView indexPathForCell:sender].row;
NMNote *note = self.notes[indx];
destination.passedInString = note.content;
}
}
//#pragma mark - delegate
//
//- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
//{
//
//}
#end
This is the screens flow:
the initiate view is this table view:
Now there is the TextView where you write the note:
Now, after you save a note, you go back to the first screen. and then you can tap on a populated cell and you will segue back to this screen (the one with the TextView) so you can edit it. But instead of editing it, it will create a new one with the edited content. like this:
Please, would appreciate any help here to accomplish my task..
Thanks!
The thing you need to do when you pass the note to the NMCreateNotesViewController, is to differentiate between an edit and an add action so when you came back to the table view, you can either replace the old entry with the new edited one, or add a new entry.
The way I would approach this is to have two segues, one from the + button (I'll call it "addSegue") and one from the table view cell (call it "editSegue"). I would also create a property in the list controller to hold the value of the edited row, or set it to something like -1 to indicate it's a new note. Something like this,
#property (nonatomic) NSInteger editedRow;
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"editSegue"]) {
NMCreateNotesViewController *destination = [segue destinationViewController];
NSInteger indx = [self.tableView indexPathForCell:(UITableViewCell *)sender].row;
self.editedRow = index;
NMNote *note = self.notes[indx];
destination.note = note;
}else if ([segue.identifier isEqualToString:#"addSegue"]) {
self.editedRow = -1;
}
The prepareForSegue method in the NMCreateNotesViewController would be the same as you have in your question. You can get rid of the passedInString property since we're passing in the entire note object instead. In the unwind method in the list controller, you would do this,
- (IBAction) unwindToList: (UIStoryboardSegue *) segue {
NMCreateNotesViewController *source = [segue sourceViewController];
NMNote *note = source.note;
if (note != nil && self.editedRow == -1) {
[self.notes addObject:note];
}else{
[self.notes replaceObjectAtIndex:self.editedRow withObject:note];
}
[self.tableView reloadData];
}
in NMCreateNotesViewController.h:
#property (strong, nonatomic) NMNote *note;
#property BOOL adding;
#property (strong,nonatomic) NSString *originalContent;
Then in your NMNotesListViewController.m prepareForSegue
destination.note=self.notes[indx];
destination.adding=NO; // set adding to yes if you are adding a new note
and in your unwind
- (IBAction) unwindToList: (UIStoryboardSegue *) segue
{
NMCreateNotesViewController *source = [segue sourceViewController];
NMNote *note = source.note;
if (source.adding && note != nil) {
[self.notes addObject:note];
[self.tableView reloadData];
}
}
in NMCreateNotesViewController.m
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// listen for keyboard hide/show notifications so we can properly adjust the table's height
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:nil];
if (self.note != nil)
{
self.originalContent=self.note.content;
self.textField.text=self.note.content;
}
}
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if (sender != self.saveButton)
{
if (self.note != nil)
{
self.note.content=self.originalContent;
}
}
else
{
if (self.note == nil)
{
if (self.textField.text.length > 0) {
self.note = [[NMNote alloc] init];
}
self.note.content = self.textField.text;
}
}
Maybe I didn't ask it right in the title, sorry for this, i'm a beginner so I will explain myself:
I have 2 screens:
1. Create notes - this screen have a view controller, TextView and navigation(with create/cancel).
2. Notes page - this screen have a table view controller and a navigation with a plus button.
(very similar to apple notes app)
I want that in the table view, whenever I click a cell it will take me back to the editable page of this note...
So I added a push segue from the cell to the notes page, and every time I'm clicking on a cell it opens a NEW note page...
So I know i'm missing something here and would really appreciate if you can help me figure it out
This is my table view controller .m file:
#import "NMNotesListViewController.h"
#import "NMCreateNotesViewController.h"
#interface NMNotesListViewController ()
#property (strong, nonatomic) NSMutableArray *notes;
#end
#implementation NMNotesListViewController
- (IBAction) unwindToList: (UIStoryboardSegue *) segue
{
NMCreateNotesViewController *source = [segue sourceViewController];
NMNote *note = source.note;
if (note != nil) {
[self.notes addObject:note];
[self.tableView reloadData];
}
}
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.notes = [[NSMutableArray alloc] init];
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
- (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.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [self.notes count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"NotesPrototypeCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Configure the cell...
NMNote *note = [self.notes objectAtIndex:indexPath.row];
cell.textLabel.text = note.content;
return cell;
}
#end
And this is my view controller (create notes) .m file:
#import "NMCreateNotesViewController.h"
#interface NMCreateNotesViewController ()
#property (weak, nonatomic) IBOutlet UIBarButtonItem *createButton;
#property (weak, nonatomic) IBOutlet UITextView *textField;
#end
#implementation NMCreateNotesViewController
- (void)registerForKeyboardNotifications
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWasShown:) name:UIKeyboardDidShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillBeHidden:) name:UIKeyboardWillHideNotification object:nil];
}
- (void)keyboardWasShown:(NSNotification*)aNotification {
NSDictionary* info = [aNotification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
CGRect bkgndRect = self.textField.superview.frame;
bkgndRect.size.height += kbSize.height;
[self.textField.superview setFrame:bkgndRect];
[self.textField setContentOffset:CGPointMake(0.0, self.textField.frame.origin.y-kbSize.height) animated:YES];
}
- (void) keyboardWillBeHidden: (NSNotification *) aNotification
{
UIEdgeInsets contentInsets = UIEdgeInsetsZero;
self.textField.contentInset = contentInsets;
self.textField.scrollIndicatorInsets = contentInsets;
}
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if (sender != self.createButton) return;
if (self.textField.text.length > 0) {
self.note = [[NMNote alloc] init];
self.note.content = self.textField.text;
}
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
#jeely was close but what you need to do is , create a segue from viewController to viewController.
In the tableView delegate didSelectRowAtIndexPath you would preform the segue:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
[self performSegueWithIdentifier:#"yourSegue" sender:sender];
}
Because you want to pass the note to the next controller you will need to do that in the prepareForSegue method:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Make sure your segue name in storyboard is the same as this line
if ([[segue identifier] isEqualToString:#"yourSegue"])
{
//get the note
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
NMNote *note = [self.notes objectAtIndex:indexPath.row];
//set the note
NMCreateNotesViewController *createVC = (NMCreateNotesViewController*)segue.destinationViewController;
createVC.noteToDisplay = note.content;
}
}
Finally noteToDisplay is just an NSString property that you will set to the textView property once the segue is performed.
In iOS for the iPhone I want to make a control with similar appearance and behavior to the android spinner control when configured to behave like a drop down list box. Specifically when pressed a modal list of text options with radio buttons comes up and when one of them is pressed the list disappears and the control updates to that choice. Example:
So far I have seen a full-screen option using [self presentViewController...] with a custom ViewController but I want a partial screen (like pictured above) solution. Does anyone know how to do this or could point in the right direction.
The native solution to this will be a UIActionSheet which on iPhone will appear from the bottom and be partial screen or on iPad be very similar to the android version.
You can find the documentation here: UIActionSheet
if you didnt want to use the UIActionSheet and you wanted to make it reusable rather than adding a whole bund of UIViews to your current XIB, you could create a custom UIView with whatever interface you would need to populate it and use the interface builder to help make it look ok.
that view could have a message handler that posts the response that you would need to listen for.
then just init and load the view into your subviews and populate it
then post a message from the custom view to the handler you registered
so for your custom view you would have something like this.
#implementation SomeCustomView
+(SomeCustomView*)viewFromNibNamed:(NSString *)nibName{
NSArray *nibContents = [[NSBundle mainBundle] loadNibNamed:nibName owner:self options:NULL];
NSEnumerator *nibEnumerator = [nibContents objectEnumerator];
SomeCustomView *customView = nil;
NSObject* nibItem = nil;
while ((nibItem = [nibEnumerator nextObject]) != nil) {
if ([nibItem isKindOfClass:[AADropDown class]]) {
customView = (SomeCustomView*)nibItem;
break;
}
}
return customView;
}
-(void)someInitializationWith:(NSArray*)repeatableData andNotificationId:(NSString*)noteId{
//set your stuff up for the view here and save the notification id
}
...
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
[[NSNotificationCenter defaultCenter] postNotificationName:Your_Notification_Id object:somevalue];
}
#end
and include other things, like in this case the tableview stuff or any other logic.
then in your viewcontroller you could call it like
__block id observer = [[NSNotificationCenter defaultCenter] addObserverForName:#"customViewAction" object:nil queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification *note) {
//deal with notification here
[[NSNotificationCenter defaultCenter] removeObserver: observer];
}];
SomeCustomView *cv =(SomeCustomView*) [SomeCustomView viewFromNibNamed:#"SomeCustomView"];
[cv someInitializationWith:arrayOptions andNotificationId:#"customViewAction"];
[self.view addSubview:cv];
and in your interface builder you will just need to make sure that the class of the view is set to your class type.
then you can easily reuse this code again whenever a user needs to select something else in the same manner.
Here is a variation on the solution suggested by AtomRiot.
On your view (xib or storyboard) make a button and assign this graphic to it. Don't worry if it appears stretched out in the editor. The code will make it a realizable graphic.
2X version
Then include the following files in your project (copied below):
DDLBHelper.h
DDLBHelper.m
Then in your ViewController's .h file make links to the button:
#property (weak, nonatomic) IBOutlet UIButton *ddlbB;
- (IBAction)ddlbBClick:(id)sender;
In you ViewController's .m file make the following calls:
#synthesize ddlbB, choiceLabel;
DDLBHelper *mDDLBH;
- (void)viewDidLoad {
[super viewDidLoad];
NSArray *strings = [[NSArray alloc] initWithObjects:#"Item 1", #"Item 2", #"Item 3", nil];
mDDLBH = [[DDLBHelper alloc] initWithWithViewController:self button:ddlbB stringArray:strings currentValue:1];
}
- (IBAction)ddlbBClick:(id)sender {
[mDDLBH popupList];
}
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration{
[mDDLBH adjustToRotation];
}
Works just like android.
Here are the files:
DDLBHelper.h
// DDLBHelper.h
// Created by MindSpiker on 9/27/12.
#import <Foundation/Foundation.h>
#protocol DDLBHelperDelegate <NSObject>
#required
- (void) itemSelected: (int)value;
#end
#interface DDLBHelper : UIViewController <UITableViewDelegate, UITableViewDataSource>{
id <DDLBHelperDelegate> delegate;
}
#property (retain) id delegate;
// external interface
- (id) init;
- (id) initWithWithViewController:(UIViewController *)viewController button:(UIButton *)button stringArray:(NSArray *)values currentValue:(int) currentValue;
- (void) popupList;
- (BOOL) isShown;
- (void) adjustToRotation;
- (int) getValue;
- (NSString *)getValueText;
#end
DDLBHelper.m
// DDLBHelper.m
// Created by MindSpiker on 9/27/12.
#import "DDLBHelper.h"
#import <QuartzCore/QuartzCore.h>
#interface DDLBHelper () {
#private
UIViewController *mVC;
UIButton *mButton;
NSArray *mValues;
int mValue;
UITableView *mTV;
UIView *mBackgroundV;
}
#end
#implementation DDLBHelper
#synthesize delegate;
- (id) init {
self = [super init];
mVC = nil;
mButton = nil;
mValues = nil;
mValue = -1;
return self;
}
- (id) initWithWithViewController:(UIViewController *)viewController button:(UIButton *)button stringArray:(NSArray *)values currentValue:(int) currentValue {
self = [super init];
// save pointers
mVC = viewController;
mButton = button;
mValues = values;
mValue = currentValue;
[self setupButton];
return self;
}
- (void) popupList{
if (mBackgroundV == nil){
mBackgroundV = [self setupBackgroundView];
[mVC.view addSubview:mBackgroundV];
}
if (mTV == nil){
mTV = [self setupTableView];
[mVC.view addSubview:mTV];
}
[mTV reloadData];
[mBackgroundV setHidden:NO];
[mTV setHidden:NO];
}
- (BOOL) isShown{
return !mTV.isHidden;
}
- (void) adjustToRotation{
BOOL isShown = [self isShown];
// remove the controls
if (mBackgroundV != nil){
[mBackgroundV removeFromSuperview];
mBackgroundV = nil;
}
if (mTV != nil){
[mTV removeFromSuperview];
mTV = nil;
}
if (isShown){
[self popupList];
}
}
- (int) getValue{
return mValue;
}
- (NSString *) getValueText{
if (mValues != nil && mValue > -1) {
if (mValues.count > mValue){
return [mValues objectAtIndex:mValue];
}
}
return nil;
}
- (void) updateButtonTitle{
NSString *title = [NSString stringWithFormat:#" %#", [self getValueText]];
[mButton setTitle:title forState:UIControlStateNormal];
}
- (void) setupButton {
UIImage *buttonBG = [UIImage imageNamed:#"sis_proceeds_ddlb.png"];
UIEdgeInsets insets = UIEdgeInsetsMake(8, 8, 8, 45);
UIImage *sizableImg = [buttonBG resizableImageWithCapInsets:insets];
[mButton setBackgroundImage:sizableImg forState:UIControlStateNormal];
[mButton setContentHorizontalAlignment:UIControlContentHorizontalAlignmentLeft];
[self updateButtonTitle];
}
- (UIView *) setupBackgroundView{
UIView *v = [[UIView alloc] initWithFrame:mVC.view.bounds];
[[v layer] setOpaque:NO];
[[v layer] setOpacity:0.7f];
[[v layer] setBackgroundColor:[UIColor blackColor].CGColor];
return v;
}
- (UITableView *) setupTableView {
CGRect rect = [self makeTableViewRect];
UITableView *tv = [[UITableView alloc] initWithFrame:rect style:UITableViewStylePlain];
[tv setDelegate:self];
[tv setDataSource:self];
[tv setBackgroundColor:[UIColor whiteColor]];
[[tv layer] setBorderWidth:2];
[[tv layer] setBorderColor:[UIColor lightGrayColor].CGColor];
[[tv layer] setCornerRadius:10];
[mVC.view addSubview:tv];
return tv;
}
- (CGRect) makeTableViewRect {
float l=0.0, t=0.0, w=0.0, h=0.0, maxH=0.0, cellH=0.0, cellsH=0.0;
// get
l = mButton.frame.origin.x;
w = mButton.frame.size.width;
t = mVC.view.bounds.origin.y + 50;
maxH = mVC.view.bounds.size.height - 100;
// get cell height
UITableViewCell *c = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
cellH = c.bounds.size.height;
// see if list will overlow maxH(eight)
cellsH = cellH * mValues.count;
if (cellsH > maxH) {
h = maxH;
} else {
h = cellsH;
}
return CGRectMake(l, t, w, h);
}
#pragma mark - TableView Delegate functions
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1; // this is a one section table
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return mValues.count; // should be called for only one section
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
// try to resuse a cell if possible
static NSString *RESUSE_IDENTIFIER = #"myResuseIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:RESUSE_IDENTIFIER];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:RESUSE_IDENTIFIER];
}
cell.textLabel.text = [mValues objectAtIndex:indexPath.row];
if (mValue == indexPath.row){
cell.accessoryType = UITableViewCellAccessoryCheckmark;
} else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
// save value and hide view
mValue = indexPath.row;
[self updateButtonTitle];
[mBackgroundV setHidden:YES];
[mTV setHidden:YES];
[delegate itemSelected:mValue];
}
#end