How to customize iRate classes for "Rate this app" ios - ios

I don't want to use the uialertview for the popup, that gives the user a chance to rate the app on ios. I want to use a customized popup, but this is not showing up. Besides using the iRate classes from the internet, I also create a xib, that contains the popup, that I want to appear and I changed in .h from :NSObject to :UIViewController. I commented all the code for the uialertview and in the method promptForRating, that will be triggered, I make the uiview from the xib visible, but apparently the uiview is nil.
- (void)promptForRating
{
rateView.hidden = NO;
}
Does anybody have a suggestion about making this popup show up?

I think I get it now.. if you want to display a view, it has to be embedded in a view controller. Or in another view that is already embedded.
What you can do is
Access the sharedApplication of the UIApplication
Get all the UIWindows of that UIApplication (in reversed order, because your myView should be on top)
Select the UIWindow that is the default
Add your myView as a subview of the UIWindow
At least this is what SVProgressHUD is doing.
Here is some sample code
if(!myView.superview){
NSEnumerator *frontToBackWindows = [[[UIApplication sharedApplication]windows]reverseObjectEnumerator];
for (UIWindow *window in frontToBackWindows)
if (window.windowLevel == UIWindowLevelNormal) {
[window addSubview:myView];
break;
}
}
The first line is to ensure that your view is not visible atm (maybe unnecessary in your context). To dismiss the view, remove it from its superview.

Related

IBAction error in subview

I have two class:
MeuPrimeiroViewController.h/.m
MeuSegundoViewController.h/.m
I have this code:
MeuPrimeiroViewController.h
- (IBAction)botao:(id)sender;
MeuPrimeiroViewController.m
#import "MeuPrimeiroViewController.h"
#import "MeuSegundoViewController.h"
- (IBAction)botao:(id)sender{
MeuSegundoViewController *segundo = [[MeuSegundoViewController alloc] init];
UIWindow *window = [[UIApplication sharedApplication] keyWindow];
UIView *view = segundo.view;
[window addSubview:view];
}
This command works great, but in the 'SegundoViewController' I have this code:
MeuSegundoViewController.h
- (IBAction)botaoback:(id)sender;
MeuSegundoViewController.m
- (IBAction)botaoback:(id)sender{
NSLog(#"Back messange");
}
But the console log don't return any messanges, and the simulator returns me to the main.m file, why?
When you do:
[window addSubview:view];
The view belonging to MeuSegundoViewController is retained by its new superview (the window), but the view controller instance segundo isn't - and it gets destroyed. So, when you press the button you get an exception because the segundo instance can't be called.
I doubt you really want to be adding the view as a subview of the window. It would be much better to be adding it as a subview of the MeuPrimeiroViewController view, or to have a navigation controller and push both of the view controllers into it. If you use the navigation controller then it will retain the view controllers (and prevent the crash). If you use MeuPrimeiroViewController then call:
[self addChildViewController:segundo];
if you continue to use the window then you need something to retain the view controller (and there is no good obvious choice).

UIViewController on top of UINavigationBar

I am trying to add custom UIViewController on top of everything but not covering full screen (basically popover), like this:
- (void) displayPopoverController: (UIViewController*) content;
{
[self addChildViewController:content];
content.view.frame = [self frameForContentController];
[self.view addSubview:content.view];
[content didMoveToParentViewController:self];
}
Everything works, but unfortunately it is underneath the navigation bar. So I decided to add UIViewController to the navigation controller like this:
- (void) displayPopoverController: (UIViewController*) content;
{
[self.navigationController addChildViewController:content];
content.view.frame = [self frameForContentController];
[self.navigationController.view addSubview:content.view];
[content didMoveToParentViewController:self.navigationController];
}
It worked, but there are 2 problems:
1) viewWillAppear is not called when I add popover (only viewDidLoad is called)
2) If I change orientation, my popover receives notification and adjusts to new orientation, but UIViewController behind it does not. It will only update its view after I remove popover.
Is there any way to fix 1 and 2? Maybe there is better approach(I don't want to use UIPopoverController with custom UIPopoverBackgroundView)?
IMO you should make a custom transition and present UIViewController modally.
You can get help on Custom UIViewController transition here : http://www.doubleencore.com/2013/09/ios-7-custom-transitions/
I am trying to add custom UIViewController on top of everything but not covering full screen
If you can confine yourself to iOS 7, your problems are over. You can use presentViewController: and a custom transition to do exactly what you are trying to do. This, in my view, is the most important new feature of iOS 7: you can present a view controller's view only partially covering the main interface.
See my book; for the particular example code from the book, see https://github.com/mattneub/Programming-iOS-Book-Examples/blob/master/bk2ch06p304customPresentedAnimation2/ch19p620customPresentedAnimation2/ViewController2.m
Plus I've now posted a single project at https://github.com/mattneub/custom-alert-view-iOS7. It shows how to make a view controller presented view that only partially covers the interface, plus it demonstrates that device rotation works correctly for all visible views (i.e. what's in front and what's visible behind).

Adding another view controller's view as subview

I am trying to get a popup effect and want to design the popup view in another view controller so i can use the xib to do it.
When i used the presentViewController or pushViewController and set the background to transparent, i end up seeing the Window's background color.
I tried this code to add subview to the navigation controller's view so that i can have the Info view cover the entire screen with a transparent background. I also have tab bar to cover up as well.
InfoVC *vc = [[InfoVC alloc] initWithNibName:#"InfoVC" bundle:nil];
[self.navigationController.view addSubview:vc.view];
My problem is inside my InfoVC when i try to dismiss it, the app will crash with some EXC_BAD_ACCESS message:
[self.view removeFromSuperview];
EDIT:
I found a way to stop it crashing but setting the InfoVC as a property in the MainVC. I think the reason for crash is when i call "self.view" in the action inside the InfoVC, it doesn't know that self is the InfoVC inside MainVC.
InfoVC *vc = [[InfoVC alloc] initWithNibName:#"InfoVC" bundle:nil];
[self.navigationController.view addSubview:vc.view];
No no no no. Never never do that.
There is an elaborate dance that you must traverse in order to put a view controller's view inside another view controller's view (or remove it afterwards) if it doesn't come with built-in facilities for doing this (the way a UISplitViewController does, or the way a navigation controller manages the views of the view controllers that are pushed and popped within it).
Read up on customer container controllers. One of the examples from my book is here:
https://github.com/mattneub/Programming-iOS-Book-Examples/blob/master/ch19p556containerController/p476containerController/ViewController.m
Shouldn't you be using the following to remove the view from its superview?
[vc.view removeFromSuperview];
You can never have a UIView remove it's subviews, the subviews themselves must remove themselves from it's superview. You can easily loop through subviews and have them removed like so
for (UIView *view in vc.view.subviews) {
[view removeFromSuperview];
}
Docs for reference:
http://developer.apple.com/library/ios/#documentation/uikit/reference/uiview_class/uiview/uiview.html
After a "modally" presented view controller has appeared the views under the now presented view controller will be removed; this saves memory, and eases rendering. In your case, though, you also end up seeing the window behind the "modally" presented view.
The natural, and seemingly logical, next step is to simply take one view controller's view and cram it into another. However, as you have discovered, this is problematic. With the newly inserted view safely retained by the view hierarchy it is safe, but the new view controller is not so lucky, it is quickly deallocated. So when this new view tries to contact its controller you will get an EXC_BAD_ACCESS and crash. One workaround, again as you have found, is to simply have the original view controller keep a strong reference to the new view controller. And this can work... badly. There's still a good chance you will get an UIViewControllerHierarchyInconsistencyException.
Of course if you simply want to add a small view you create in IB you don't need to use a view controller as the "File's Owner" and there are many examples of creating an instance of a view from a xib file.
The more interesting question here is, "How would/does apple do it?" Apple consistently says that a view controller is the correct controller for an encapsulated unit of work. For example, their TWTweetComposeViewController, you present it, and it seems to float. How?
The first way of accomplishing this that comes to my mind is to have a clear background that isn't clear. That is, create an image of the screen before the presented view controller appears and set that as the background before the presenting view is removed. So for example(Explanation to follow):
QuickSheetViewController.xib
QuickSheetViewController.h
#import <UIKit/UIKit.h>
#interface QuickSheetViewController : UIViewController
- (IBAction)dismissButtonPressed:(id)sender;
#end
QuickSheetViewController.m
#import "QuickSheetViewController.h"
#import <QuartzCore/QuartzCore.h>
#implementation QuickSheetViewController {
UIImage *_backgroundImage;
}
-(void)renderAndSaveBackgroundImageFromVC:(UIViewController *)vc{
UIGraphicsBeginImageContext(vc.view.bounds.size);
[vc.view.layer renderInContext:UIGraphicsGetCurrentContext()];
_backgroundImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
// save an image of the current view, and set our background to clear so we can see the slide-in.
[self renderAndSaveBackgroundImageFromVC:self.presentingViewController];
self.view.backgroundColor = [UIColor clearColor];
}
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
// Time to use our saved background image.
self.view.backgroundColor = [UIColor colorWithPatternImage:_backgroundImage];
}
-(void)viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
// Set our background to clear so we can see the slide-out.
self.view.backgroundColor = [UIColor clearColor];
}
- (IBAction)dismissButtonPressed:(id)sender {
[self dismissViewControllerAnimated:YES completion:nil];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#end
The majority of this example hinges upon the renderAndSaveBackgroundImageFromVC: method. In which, we create a graphics context render the view we are about to cover into it, and then create a UIImage to later (in viewDidAppear) use as a background.
Now simply use it like:
QuickSheetViewController *newVC = [[QuickSheetViewController alloc] initWithNibName:nil bundle:nil];
[self presentViewController:newVC animated:YES completion:nil];
You will see through the background just long enough for the animation to happen, then we use our saved image to hide the removal of the presenting view.

Changing between Views in iOS

I am making my first iOS application, it is for the iPad. It is a memorization game. It has cover page with a couple of options and depending on the option you choose it sends you different page/view. Throughout the application, the user will be traveling through different pages/views. The entire interface for the application will be custom made, so i want have the navigation bars or anything. I am using xCode 3.2.5. I have created the views in the interface builder. And I have attached the cover page to the app, so after the splash page it appears.
How do I go about switching between views?
Thanks for any help you can give me.
Edit 1:
Here is some code that I think is pertinent
This is the AppDelegate.m file, I left out the methods I did not edit
#synthesize coverController=_coverController;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
cover *aCoverController = [[cover alloc] initWithNibName:#"cover" bundle:nil];
self.coverController = aCoverController;
// Or, instead of the line above:
// [self setcover:aCoverController];
[aCoverController release];
self.window.rootViewController = self.coverController;
[self.window makeKeyAndVisible];
return YES;
}
- (void)dealloc {
[managedObjectContext_ release];
[managedObjectModel_ release];
[persistentStoreCoordinator_ release];
[_coverController release];
[window release];
[super dealloc];
}
Ok. 1stly can you be a little more clearer about what you want.
From what I got was, you are not looking to navigate in/out of controllers, you just have few views prepared for your RootViewController, and then you want to switch between them.
Navigation controller is used when you have a sequential flow of views, as in moving from view1 'leads to' view2, and so on. eg- a contactsBook-->contactDetails-->editContact--> so on ..
But it feels, in your case, the views/pages are separate and have no connection whatsoever, so there wont be any sequential flow, but a random flow of say view1-->view5-->view2--> ..
If that is the case, if you have already build the views, you just need to connect each of them with their parentController(coverController in your case).
Simplest way would be - lets say you have 3 views, view1 view2 view3, each having 1 or more buttons to switch b/w views.
1 way would be to have a reference of the coverController, in each of the views. There are more elegant methods possible, but this 1 will be the easiest to understand and implement.
So, in view1.h(add these) :
import "cover.h"
#class cover;
#interface view1 : UIView {
cover *coverController;
}
#property(nonatomic, assign)cover *coverController;
#end
And in cover.h, add
import "view1.h"
#class view1;
#interface cover : UIViewController{
IBOutlet view1 *firstView;
}
#property(nonatomic, retain) IBOutlet view1 *firstView;
#end
Finally in cover.m, add
#implementation cover
#synthesize view1;
and in 'viewDidLoad' method in cover.m, add 2 lines
self.view1.frame = CGRectMake(0,0,768,1024); //set whatever frame you want
self.view1.coverController = self; //concept of reference-paring
And done.
in the view1ButtonPressed method of view1 -
-(IBAction)view1ButtonPressed{
// remove the current view from the superview
[self removeFromSuperView];
//go to superView, to load anotherview
[coverController view1ButtonWasPressed];
}
in cover.m :
-(void)view1ButtonWasPressed{
//after doing the same process for view2
[self.view addSubview:view2];
}
If you have made the correct connections, in you nib files, you ll achieve what you set out to do.
Concept is simple, what we are doing is - on click on the button, we remove the current view from superview, go to the super view itself(which is the controller's view only), and add as a subview some other view of our choice.
There is only 1 controller, and many views, and we are switching in b/w those views.
You should use a navigation controller, it's the simplest way of structuring an app with multiple views. There's nothing that says you have to show the navigation bar and you can create custom buttons which push and pop views on and off of the stack.
I've been playing with different ways of doing this and it's just not worth the effort. I strongly recommend the navigation controller.
This tutorial helped me get my head round it, but try googling to find what works best for you.

How do I hook into the action method for an iPad popover toolbar button?

I am using the split view template to create a simple split view that has, of course, a popover in Portrait mode. I'm using the default code generated by template that adds/removes the toolbar item and sets the popover controller and removes it. These two methods are splitViewController:willShowViewController:... and splitViewController:willHideViewController:...
I'm trying to figure out how to make the popover disappear if the user taps on the toolbar button while the popover is displayed. You can make the popover disappear without selecting an item if you tap anywhere outside the popover, but I would also like to make it disappear if the user taps the button again.
Where I'm stuck is this: there doesn't seem to be an obvious, easy way to hook into the action for the toolbar button. I can tell, using the debugger, that the action that's being called on the button is showMasterInPopover. And I am new to working with selectors programmatically, I admit.
Can I somehow write an action and set it on the toolbar item without overriding the action that's already there? e.g. add an action that calls the one that's there now? Or would I have to write an action that shows/hides the popover myself (behavior that's being done behind the scenes presumably by the split view controller now???).
Or am I missing an easy way to add this behavior to this button without changing the existing behavior that's being set up for me?
Thank you!
So it turns out that you can make the popover dismiss when clicking on the barButtonItem by implementing the SplitViewController willPresentViewController method as follows:
- (void) splitViewController:(UISplitViewController *)svc
popoverController: (UIPopoverController *)pc
willPresentViewController: (UIViewController *)aViewController
{
if (pc != nil) {
[pc dismissPopoverAnimated:YES];
}
}
So, the barButtonItem will have the UISplitViewController as the target and showMasterInPopover: as the action. I can't find it in the documentation, so I'm a bit worried it's not okay to call it, but I got it to work by changing the target to self (the view controller) and the action to a custom method, like this:
- (void)showMasterInPopover:(id)sender {
// ...insert custom stuff here...
[splitViewController showMasterInPopover:sender];
}
Don't have the rep to make a real comment. :-(
#Jann - I'm pretty sure what Elizabeth wants to do is pretty standard. For example, the Notes application that ships pre-loaded on the iPad closes and opens the popover when you press the toolbar button in the top left corner.
Below is my solution. It starts out similar to greenisus' solution, by hooking the UISplitViewController's toolbar button event handler. I use a flag in my controller to track whether the popover is open or not. Finally, to handle the case where the user opens the popover, then closes it by clicking outside the popover, I implement the UIPopoverControllerDelegate protocol.
First, the controller interface:
#interface LaunchScene : NSObject <UISplitViewControllerDelegate, UIPopoverControllerDelegate>
{
UISplitViewController* _splitViewController; //Shows list UITableView on the left, and details on the right
UIToolbar* _toolbar; //Toolbar for the button that will show the popover, when in portrait orientation
SEL _svcAction; //The action from the toolbar
id _svcTarget; //The target object from the toolbar
UIPopoverController* _popover; //The popover that might need to be dismissed
BOOL _popoverShowing; //Whether the popover is currently showing or not
}
-(void) svcToolbarClicked: (id)sender;
I use _svcAction and _svcTarget to addess greenisus' worries that he might not be calling the right function.
Below is my implementation. For brevity, I have omitted the code that instantiates the UISplitViewController and the subviews. All the show/hide related code is shown.
//the master view controller will be hidden so hook the popover
- (void)splitViewController:(UISplitViewController*)svc willHideViewController:(UIViewController *)aViewController withBarButtonItem:(UIBarButtonItem*)barButtonItem forPopoverController:(UIPopoverController*)pc
{
_popoverShowing = FALSE;
if(_toolbar == nil)
{
//set title of master button
barButtonItem.title = #"Title goes here";
//Impose my selector in between the SVController, and the SVController's default implementation
_svcTarget = barButtonItem.target;
_svcAction = barButtonItem.action;
barButtonItem.target = self;
barButtonItem.action = #selector(svcToolbarClicked:);
//create a toolbar
_toolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, 1024, 44)];
[_toolbar setItems:[NSArray arrayWithObject:barButtonItem] animated:YES];
}
//add the toolbar to the details view (the second controller in the splitViewControllers array)
UIViewController* temp = [_splitViewController.viewControllers objectAtIndex:1];
[temp.view addSubview:_toolbar];
}
Here is my function, that responds to the toolbar click. This handles the case where the user taps and re-taps the toolbar button.
-(void) svcToolbarClicked: (id)sender
{
if(_popoverShowing)
{
[_popover dismissPopoverAnimated:TRUE];
}
else
{
//Perform the default SVController implementation
[_svcTarget performSelector:_svcAction];
}
//Toggle the flag
_popoverShowing = !_popoverShowing;
}
Some functions from UISplitViewControllerDelegate
//the master view (non-popover) will be shown again (meaning it is going to landscape orientation)
- (void)splitViewController:(UISplitViewController*)svc willShowViewController:(UIViewController *)aViewController invalidatingBarButtonItem:(UIBarButtonItem *)button
{
//remove the toolbar
[_toolbar removeFromSuperview];
}
// the master view controller will be displayed in a popover (i.e. the button has been pressed, and the popover is about to be displayed.
//Unfortunately triggers when the popover is ALREADY displayed.
- (void)splitViewController:(UISplitViewController*)svc popoverController:(UIPopoverController*)pc willPresentViewController:(UIViewController *)aViewController
{
_popover = pc; //Grab the popover object
_popover.delegate = self;
}
The above code is sufficient for most cases. However, if the user opens the popover, then dismisses by clicking elsewhere on the screen, the _popoverShowing boolean will contain an incorrect value, which will force the user to tap the toolbar button twice to re-open the popover. To fix this, implement the UIPopoverControllerDelegate method, like the snippet below.
//UIPopoverControllerDelegate method
- (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController
{
_popoverShowing = FALSE;
_popover = nil;
}
This took me forever to figure out, digging through the docs and (I think) most of the UISplitViewController questions on StackOverflow. I hope somebody finds it useful. If so, I covet reputation points. ;-)
Maybe you all just complicate it too much or I have read something very different than you guys wanted to do... but perhaps, this is what you were all trying to figure out so hardish:
-(void)togglePopOverController {
if ([popOverController isPopoverVisible]) {
[popOverController dismissPopoverAnimated:YES];
} else {
[popOverController presentPopoverFromBarButtonItem:bbiOpenPopOver permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
}
Elisabeth writes:
You can make the popover disappear without selecting an item if you tap anywhere outside the popover, but I would also like to make it disappear if the user taps the button again.
First of all, let me say that none of what I am about to say is to be taken personally -- it is not meant that way. It all comes from years of designing programming interfaces and studying the Apple Human Interface Guidelines (as well as having a Graphic Designer who is contstantly trying to teach me the right way to do things). It is meant as an opposing viewpoint and not as a rant.
What you are suggesting is a problem UI-wise for me, and will be an issue that causes trouble when Apple reviews the app. You are never supposed to have a known-UI-object perform a function that it does not perform normally (For instance: a button never shows and then releases a view/object/window. Toggles do this).
For instance, a magnifying glass on the navbar means Search (as defined by Apple). They have in the past, and will continue in the future to, refuse apps that use this for zooming the interface. For example: Apple Rejects ConvertBot or The Odyssey: Trail of Tears (search the page for it). The language in the rejection is always the same (bold marking what they would cite for your usage):
“… uses standard iPhone/iPod screen images in a non-standard way, potentially resulting in user confusion. Changing the behavior of standard iPhone graphics, actions, and images, or simulating failures of those graphics, actions, or images is a violation of the iPhone Developer Program agreement which requires applications to abide by the Human Interface Guidelines.”
Also, if you really want this feature, ask yourself: "Why?". If it is because you, yourself, like it, then I would really skip it. Most users would be confused by this behavior and would not actually use it because they would not know it was an option to use. Apple spent the last 3 years training iPhoneOS users how to use their OS and interface elements. The last thing you, as a programmer or designer, want to do is spend time trying to train a user on how to use your app. They will generally remove your app from their device and move to another similar app instead of forcing themselves to learn your way of doing things.
Just my $.02

Resources