I am a novice Ios developer and this a my first project which is ipad specific.I am having some issues with UIPopOverControl class implementation. In my project i have a View controller subclass and In that view i have several buttons . What I need to do is after pressing a button show a Popover with UIPopOvercontrol class.The data shown in the popover would be different for tapping different button and all the data would be presented in UITableView style. I have been able to show one button and one popOver using one UIViewController and UITableViewController subclass and loading data from a nib file. But how can I perform my desired task??
Thanks in advance
In your application, not need to use multiple UIPopoverViewController, you can also do this by using single UIPopoverViewController.
simple create new Class of UIPopoverViewController;
and also create UITableView in UIPopoverViewController.
In your application you have multiple UIButton, just give tag of each buttons and pass your data base on tag of button, and display this data on UITableView.
iOS purposely restricts having only one Popover visible at a time. The API is intrinsically designed to prevent having multiple open at the same time. You will need to consider an alternative approach that satisfies your requirements.
I had made the requirement done here.
Check this out.
It will help you for sure.Code for showing 2 popViewController at the same time and different data in both
You can set a variable in your AppDelegate to check which button is pressed?
Then, In viewWillAppear of your Controller, take the reference of that variable and check which button is pressed?
Then reload the data as per requirement in cellForRowAtIndexPath.
Hope this helps
AppDelegate.h
#interface AppDelegate : UIResponder
#property int buttonPressed; // Set this on click of any button
#end
YourController.h
int buttonPressed;
YourController.m
(void) viewWillAppear:(BOOL)animated
{
AppDelegate *app = (AppDelegate *) [[UIApplication sharedApplication] delegate];
buttonPressed = app.buttonPressed;
}
(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (buttonPressed == 1) { // do this}
else if (buttonPressed == 1) { // do this}
else // do this
}
Related
I am trying to learn iOS development but have stalled a bit so I hope that there is some kind soul here who might be able to help me in the right direction.
Let's say I have a UITableViewController that displays a number of items, consisting of a title and subtitle ( Subtitle style of a Tableview Cell). Items.m/h only consist of two properties, title and subtitle and a init method to set the properties. In my app delegate i create some default items and pass them/set them to my tableViewController's property tvc.items, which is a NSMutableArray. What do I need to do / what components do I need, to be able to add more items and then display them in my tableViewController?
I started with the following:
Added a new view controller in the storyboard
Embeddade the viewController in a Navigation Controller
Added a Bar Button Item at my Table View Controller with an identifier of add
Ctrl + drag from BarButtonItem (add) to my new view controller selected modal segue
Created a new class AddNewItemViewController
Entered this as the class under the Identity Inspector for the new view controller
I then added two Bar Button Items, Cancel and Done (with cancel and done as identifiers) in the storyboard for the new View Controller
This was followed by me adding two UITextFields, one for the Title and one for the Subtitle
Ctrl + drag from these outlets into AddNewItemViewController.m, between #interface AddNewItemViewController () ... here ...#end (so they become Private? Should I drag it here or to AddNewItemViewController.h ?, What is the standard way for doing similar outlets?).
In AddNewItemViewController I added two properties, NSString's (nonatomic, copy) * title and *subtitle which I thought would keep the input data from an intended user.
So, after this I now want do two things, and it is here as it becomes difficult (for me at least):
Making so that by clicking on Cancel, one return to the Table View controller, ie a dismissed the modal .
Adding the data within the text fields to that NSMutableArray which is the datasource by clicking Done.
So what is required of me to do the last two steps?
Where should I ctrl + drag from the Cancel and Done (so there will be actions)? I guess they must be submitted to AddNewItemViewController.m, but what must be done to dismiss the modal (by clicking on the 'Cancel') and what should be called at or performed when clicking on 'Done'?
Which or what class (es) must know about the other class?
Last but not least, what should I send in the prepareForSegue call (which I guess I will need to have to use to send the input data back to the table view controller)?
Where to start and what methods should i learn about in order to achieve my mission?
Best Regards,
Rookie
much quesetions :)
I will beginn with the close action.
Have a look at the AppleDocumentation, dismissViewController with sender self (your AddViewController).
To store your data from AddViewController to your TableViewController, it's a better way to use delegation.
AddViewController.h
#protocol AddViewControllerDelegate;
#interface AddViewController : UIViewController
#property (nonatomic, weak) id<AddViewControllerDelegate>delegate;
#end
#protocol AddViewControllerDelegate <NSObject>
- (void) addViewControllerDidFinishTakingData:(AddViewController *)addViewController withTitle:(NSString *)title andSubtitle:(NSString *)subTitle;
#end
AddViewController.m
- (IBAction)done:(id)sender
{
NSString *title = ...;
NSString *subtitle = .. .;
[self.delegate addViewControllerDidFinishTakingData:self withTitle:title andSubtitle:subtitle];
}
TableViewController.m
#interface TableViewController ()<AddViewControllerDelegate>
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"yourIdentifier"])
{
AddViewController *addViewController = (AddViewController *)segue.destinationViewController;
addViewController.delegate = self;
}
}
Last but not least to implement your new delegate-method
- (void)addViewControllerDidFinishTakingData:(AddViewController *)addViewController withTitle:(NSString *)title andSubtitle:(NSString *)subTitle
{
// handle your data here (store to array)
// reload your table
}
Better way, to create a Class (Model) for every entry.
The simplest thing to do would be to assign tvc.items to the destinationViewController's property during prepareForSegue.
You are correct in thinking that the Cancel and Done buttons belong to the AddNewItemViewController.
In the action for Done, you could add the new item to the items array you passed in during prepareForSegue, then in the presenting view controller (the one you launched the modal from), during viewDidAppear just reload the table. It'll be called when the modal disappears.
Still fairly new to iOS. I've managed to write a basic app to display a list/table of documents. I've included:
cell.accessoryType = UITableViewCellAccessoryDetailButton;
which display a blue i within a circle button which I guess can be used to perform some sort of action.
What I'd like to do now is, upon click, to display a subsequent screen with information about the document, buttons, add, delete functions, date, file size etc...
Is this done via segue or some other method?
Being a novice I am not sure what is/are the next step(s). If I know what steps I must take in order to get to next scree(s) I can search the net for example of how to do any given step.
Thank you for your help
The accessoryButton triggers it's own delegate method, distinct from the row selection, called:
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
Add that method to your delegate, and then do a vc transition. There are several ways to do that transition, most of the common ones are discussed here...
First, welcome to the iOS developing community!
In order to do this, I would use a segue to a detail view that you can design. When you select a row in your table using didSelectRowAtIndexPath, you would set an #property to the object in your array that was selected: self.selectedObject = self.tableviewarray objectAtIndex:indexPath.row; Then in the prepareForSegue method you can get the destination view controller and do destinationViewController.myObject = self.selectedObject; Now the detail view knows what object to display info for!
You'll need to implement the delegate method
-tableView:(UITableView*) didSelectRowAtIndexPath:(NSIndexPath*)
and handle the row tap in that callback accordingly.
An example would be like this:
-tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath {
YourObject *theModelForRow = [_itemList objectAtIndex:indexPath.row];
YourViewController *someNewViewController = [YourViewController viewControllerWithModel:theModelForRow];
[self.navigationController pushViewController:someNewViewController animated:YES];
}
This question already has answers here:
Passing data between view controllers
(45 answers)
Closed 8 years ago.
I have two view controllers.
First one is Custom view controller that loads the images from asset library.
Second view controller shows the full size of selected image with cancel & Delete button
I have used the below code for delete the selected image from custom view controller.
customviewcontroller.m
-(void)deleteItemsFromDataSourceAtIndexPaths:(NSArray *)itemPaths
{
//here i want to control the delete option when cancel pressed
NSMutableIndexSet *indexSet = [NSMutableIndexSet indexSet];
for (NSIndexPath *itemPath in itemPaths) {
[indexSet addIndex:itemPath.row];
}
[self.selectedAssets removeObjectsAtIndexes:indexSet];
}
/* call the delete function*/
- (void) collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
NSArray *selectedItemsIndexPaths = [self.collectionview1 indexPathsForSelectedItems];
[self deleteItemsFromDataSourceAtIndexPaths:selectedItemsIndexPaths];
[self.collectionview1 deleteItemsAtIndexPaths:selectedItemsIndexPaths];
}
This working fine for delete the selected image from custom view controller.
but It works also cancel. Now, I want to control deletion on cancel.
kindly help me to solve this.
I have already tried using button tag for identify which button was pressed. but can't control in custom vc
secondview.m
- (IBAction)CancelPhoto:(id)sender{
[Cancel setTag:1]; //set tag value at cancel
}
There are several ways to pass date between view controllers. I'm giving you a very simple solution as per your requirements:
Assuming you have all your images in a mutable array in first view controller.
NSMutableAray *imagesArray;
Make a property images array of NSMutableArray type in second view controller.
#property(nonatomic, strong) NSMutableAray *imagesArray;
assign your array to property while pushing/presenting view
secondController.imagesArray = imagesArray;
On delete event remove that image from array.
[self.imagesArray removeObjectAtIndex:selectedIndex];
dismiss/pop your second view where ever you want and refresh your first view controller in viewWillAppear of viewDidAppear method.
As you have passed reference of your main images array, both classes (view controllers) share same array through pointer and a change in array from either side will be reflected in both screens
There are 3 ways (in my opinion):
Delegate
Notification
In case: you are using database, just remove image url and reload data
I am currently building my view in the viewDidLoad method, it adds various buttons that links through to another view. The issue I am having is that when a user clicks on a button and goes through to the other view they can purchase an IAP, then when the user clicks on the back button I would like the view to 'refresh' to show that this purchase has now become active.
How do I refresh the view?
Thanks in advance
any view can be explicitly refreshed by calling setNeedsDisplay on that view.
Further you should not mix up the terms UIViewController with UIView.
I asume you dont have a refresh problem, that you would only have in self programmed custom views. I excpect that the data of the related views was not updated.
You have a few options. Either store whether the purchase was made and then run the method that checks if a purchase was made in the viewWillAppear method of the view you are wishing to change
Or...
Setup a delegate callback that changes the button when a change is made on the purchase page (http://mobile.tutsplus.com/tutorials/iphone/ios-sdk-custom-delegates/)
Or...
Manipluate the previous view directly by accessing it from the navigationController stack ([[self.navigationController viewControllers]objectAtIndex:YOURVIEW])
build view in viewDidLoad so you add controls only once, but refresh in viewWillShow. Keep in mind, viewWillShow will refresh it right after the build is done by viewDidLoad. So keep values that define your controls appearance on the 1st viewController, say, in delegate mutable array
e.g. create and initiate an NSMutableArray in your AppDelegate.h and .m
in .h interface
NSMutableArray *yourArray;
add property
#property (retain, nonatomic) NSMutableArray *yourArray;
in .m
#synthesyze yourArray;
initiate it in .m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
yourArray=[[NSMutableArray alloc]init];
//add initial objects to it as many as you have controls
}
in the 1st viewController
#import "AppDelegate.h"
-(void)viewWillShow:(BOOL)animated{
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
//pull objects from array and apply to your controls, say you have a string as a 1st obj
NSString *tmpStr=[appDelegate.yourArray objectAtIndex:0];//use it some where, say button's title
//etc
}
you will change those values in the second viewController according to users choices
#import "AppDelegate.h"
somewhere in 2nd viewController code update values in yourArray say on a
-(void)viewWillDisappear:(BOOL)animated{
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
//run a loop and update all objects
[appDelegate.yourArray replaceObjectAtIndex:i withObject:newObj];
}
and when you go back to 1st viewController, viewWillShow will refresh them from your delegate array.
I am working on an iOS app that uses a very common Core Data based tableview to display items and when one it selected, it shows a more detailed view, much like the Contacts app. The detail view itself is a programmatically generated grouped table with a custom (nib-defined) view for a header that has a picture and a name. Some of the cells in the table are custom cells that have a label name and a textbox value. In "edit" mode, the editable table cells (and the name in the header) have .clearButtonMode set to UITextFieldViewModeAlways to show that they are editable.
I am currently using the same view controller to display the detailed information, edit the information, and add a new record to the original list.
When a new item is being added, the view controller is created modally with a custom init overload that sets a flag in the view controller to indicate that it is adding the record. This allows it to start in edit mode and if edit mode is left, the model view is dropped away. The right menubar button is the usual Edit/Done, and the left one is a cancel button. When an existing item is being edited, the left button (normal back button) is replaced with a cancel button.
I am starting to have second thoughts as to whether or not having one view controller handle three different modes is the way to go. There are few issues that I am not sure how to handle.
1) How do I tell if edit mode is left by hitting "Done"? Is there an action for it? If cancel is hit, the action either dismisses itself (add mode) or restores the previous values leaves edit mode. I suppose I could put a check in my setEditing override to handle it, but it seems that there should be a better way.
2) When edit mode is entered and I set the editable text fields to UITextFieldViewModeAlways, is there a way to animate the appearance of the 'X' buttons so that they fade in with the editing indicators on the regular cells?
Are there easy solutions to these problems or is my 3-in-1 view controller a bad idea? It doesn't seem right to remake the same view for different modes, but having multiple modes for a view controller seems to be a bit of a hassle.
jorj
I like the 3-in-1 approach and use it all the time. There are lots of advantages: one xib, one view controller, one simple protocol between the list and detail view controllers. Yes, there are a few more checks like if (self.editing) ... but I like that better than more view controllers and xibs.
To help with adding I expose a BOOL that the delegate can set.
#property (nonatomic) BOOL adding;
1) The built-in editButtonItem does not allow you to intercept it before setEditing:animated: This is problematic when you are doing data validation after Done is tapped. For that reason I rarely use editButtonItem and use my own Edit, Done, and Cancel buttons with their own action methods. See below.
2) For this I like UITableView's reloadSections:withRowAnimation. It might work in your case.
- (void)edit:(id)sender
{
self.editing = YES;
}
- (void)done:(id)sender
{
// data validation here
if (everythingChecksOut)
{
//save here
} else {
return; //something didn't validate
}
//if control reaches here all is good
//let the delegate know what happened...
if (self.adding) {
[self.delegate didFinishAddingWithData:self.yourData];
} else {
[self.delegate didFinishEditingWithData:self.yourData];
}
self.adding = NO;
self.editing = NO;
}
- (void)cancel:(id)sender
{
[self.view endEditing:YES]; //in theory, forces the view that is editing to resign first responder
//in practise I find it doesn't work with the YES parameter and I have to use my own flag
// roll back any changes here
self.editing = NO;
if (self.adding) //let the delegate know we cancelled the add...
{
[self.delegate didCancelAdd];
}
}
- (void)setEditing:(BOOL)editing animated:(BOOL)animated
{
[super setEditing:editing animated:animated];
//set your nav bar title
[self.tableview.editing = editing]; //you may or may not require this
[self.tableview reloadSections... withRowAnimation:yourChoice];
if (editing)
{
//install your Done and Cancel buttons
} else {
//remove Cancel and put the Edit button back
}
}
Then in viewDidLoad...
- (void)viewDidLoad
{
[super viewDidLoad];
//whatever else you do
if (self.adding)
{
self.editing = YES;
}
}
I haven't fully understood the questions you have raised, but here are some thoughts on structure which are probably more useful in the first instance...
It seems you are doing too much with a single UITableViewController and inevitably you will end up with lots of if statements and confusing code. I'd break it down into two separate UITableViewControllers, one to handle the main view (and any subsequent editing mode you require) and then another to handle the detail view. Either or both of these could then use nibs as you require.
Using two controllers like this will allow you to simply push the second detailViewController onto a navigation stack, rather than presenting it modally which doesn't seem like the obvious thing to do in this instance.
However, if you would prefer it to be presented modally, you could write a protocol for the detailView which sends messages in the event of 'Cancel', 'Edit' or 'Done' buttons being pushed. The first viewController could then implement the protocol and receive these events.
I hope that helps...