Overlay View with Subview, don't know calling VC - iphone

I need a view (infoView) to be displayed as an overlay on top of another view. As this infoView should be callable from every view of the app(e.g. introView), I'd like the code to be in the infoViews VC and just call its methods when an action at the currentView (introView) happens. I can't use push and pop, as I need to change the background color (infoView) and especially the alpha of the calling view (introView), so right now I do it with insertSubview.
My Code by now:
introVC .h
- (IBAction) openInf:(id)sender;
IBOutlet InfoVC *infoScreenVC;
introVC .m
- (IBAction) openInf:(id)sender {
[infoScreenVC openInfoMethod];}
infoVC .h
- (IBAction) closeInfoPressed;
- (void) openInfoMethod;
- (void) closeInfoMethod;
infoVC .m
- (IBAction) closeInfoPressed {
[self closeInfoPressed];}
- (void) closeInfoMethod {
[self.view removeFromSuperview];
[self.xx.view setAlpha:1.0f];}
- (void) openInfoMethod {
self.view.backgroundColor = [UIColor clearColor];
[self.xx.view setAlpha:0.2f];
[((MyAppAppDelegate *)[UIApplication sharedApplication].delegate).window
insertSubview: self.infoScreenVC.view aboveSubview: self.xx.view];}
When I push the button to show the infoView, my NSLogs tell me the method was called, but I can see the Subview wasn't added. I have absolutely no clue what to insert where right now it says xx in my code, as a VC reference from intro doesn't show me the screen.
If I put that code in introVC an modify it, it does show the infoView, calls the correct method to close, but again can't close (when I'm in introVC). I can't figure out how to tell my app who was the calling VC to get back there.
At some point, when all the code was in introVC I managed to even remove the Subview, but couldn't set the Alpha of introVC back to one.
I do struggle with that since two days.. -.- Or is there maybe an easier solution even?
Thank you very much!
//Edit after sergios answer:
intro.m
- (IBAction) openInf:(id)sender {
introViewController *introVC;
[infoScreenVC openInfoMethod:];}
info.h
- (void) openInfoMethod:(introViewController *introVC);
info.m
- (void) openInfoMethod:(introViewController *introVC) { //error occurs here
self.view.backgroundColor = [UIColor clearColor];
[self.introVC.view setAlpha:0.2f];
[((MyAppAppDelegate *)[UIApplication sharedApplication].delegate).window
insertSubview: self.infoScreenVC.view aboveSubview: self.introVC.view];}
and the occurring error says
Expected ')' before 'introVC'
I'm not sure how to pass the VC reference properly.
Thank you for your help!!
//EDIT Working Code:
As it works now, I'd like to sum things up:
- I give the calling VC (introVC) to openInfoMethod on the Action openInf like [infoVC openInfoMethod:introVC].
In openInfoMethod I "save" the calling VC in a local variable of type introVC (?) and add the overlay etc.
When the Action of the infoViewController named closeInfoPressed occurs, it calls infoViewController's method closeInfoMethod like self closeInfoMethod:introVC.
In that method I remove self.view from Superview and set introVC.view's Alpha to 1 like introVC.view setAlpha:1.0f
So the codesnippets are
intro.h
IBOutlet InfoscreenViewController *infoScreenVC;
#property (nonatomic, retain) IBOutlet InfoscreenViewController *infoScreenVC;
- (IBAction) openInf:(id)sender;
intro.m
#synthesize infoScreenVC;
- (IBAction) openInf:(id)sender {
UIViewController *introVC = self;
[infoScreenVC openInfoMethod:introVC];
}
info.h:
- (void) openInfoMethod:(UIViewController *)rootVC;
- (void) closeInfoMethod:(UIViewController *)callingVC;
info.m
- (void) closeInfoMethod:(UIViewController *)callingVC;{
[self.view removeFromSuperview];
[callingVC.view setAlpha:1.0f];
}
- (IBAction) closeInfoPressed{
[self closeInfoMethod:introVC];
[self.view removeFromSuperview];
}

If your problem is "figure out how to tell my app who was the calling VC to get back there", why don't you add a parameter to openInfo selector, like here:
info.h
- (void) openInfoMethod:(introViewController *)introVC;
info.m
- (void) openInfoMethod:(introViewController *)introVC {
<your implementation here>
}
would this work for you?
EDIT: your code from intro.m has got a small problem,
- (IBAction) openInf:(id)sender {
introViewController *introVC;
[infoScreenVC openInfoMethod:];
}
indeed, you are not initializing your introVC variable, so that when you pass it into -openInfoMethod: it will have some weird value and cause a crash.
As far as I can grasp from your code, intro.m should be the implementation file for your introViewController, therefore you can simply call:
[infoScreenVC openInfoMethod:self];
but please, before doing this, confirm that self is actually your introViewController.

This should be ilke this
(void) openInfoMethod:(introViewController *)introvc you are passing parameters in a wrong way.

If I understand your question correctly, your infoView should be a subclass of UIView and instantiated from any of your view controllers using:
InfoView *infoView = [[InfoView alloc] initWithFrame:CGRectMake(originX,originY,width,height)];
Then you simply add it as a subview of your view controllers view:
[self.view addSubView:infoView];
[infoView release]; // It's safe to release it here as your view controller's view is retaining it
And when you are done with it, simply call
[infoView removeFromSuperview];
As an aside, you could create some simple methods inside infoView that include introducing animation when the view is presented or removed. Here's an example for fade in and out which assume you set the alpha to zero initially when you create the view:
- (void)fadeIn {
[UIView animateWithDuration:1.0f animations:^{self.alpha = 1.0f}];
}
And fade out
- (void)fadeOut {
[UIView animateWithDuration:1.0f animations:^{self.alpha = 0f}
completion:^(BOOL finished){self removeFromSuperView}];
}

Related

UIActionSheet code crashes when moved from UIViewController file to separate class file

I have searched and searched the board(s) and am not able to figure this out. It has got to be something simple and right in front of me.
I am trying clean up my code and make it more reusable. I was taking some UIActionSheet code that works from a UIViewController and making its own object file. Works fine, until I add UIActionSheetDelegate methods.
When a button is pressed, instead of firing the actionSheetCancel method, it crashes with no stack trace. Every time.
My code is below. Any help would be appreciated. My guess has been it is because I am not using the xcode storyboard tool to connect things together, but I would think this is legal.
egcTestSheet.h:
#import <UIKit/UIKit.h>
#interface egcTestSheet : NSObject <UIActionSheetDelegate> {
}
- (void) showSheet:(UITabBar *) tabBar
displayTitle:(NSString *) name;
#end
egcTestSheet.m
#import "egcTestSheet.h"
#implementation egcTestSheet
-(void) showSheet:(UITabBar *)tabBar displayTitle:(NSString *)name{
UIActionSheet *menu = [[UIActionSheet alloc] initWithTitle:name
delegate:self
cancelButtonTitle:#"Done"
destructiveButtonTitle:#"Cancel"otherButtonTitles:nil];
[menu showFromTabBar:tabBar];
[menu setBounds:CGRectMake(0,0,320, 700)];
}
// actionsheet delegate protocol item
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex: (NSInteger)buttonIndex{
NSLog(#"button index = %d", buttonIndex);
}
- (void)actionSheetCancel:(UIActionSheet *)actionSheet{
NSLog(#"in action canceled method");
}
#end
call code from a UIViewController object:
egcTestSheet *sheet = [[egcTestSheet alloc] init];
[sheet showSheet:self.tabBarController.tabBar displayTitle:#"new test"];
Your action sheet is probably being released as it is dismissed (are you using ARC?). This means when it tries to call it's delegate to inform said delegate of its dismissal/selection, it is trying to call self. Self is a dangling pointer by this time, because it has been released.
In the view controller that is presenting/calling this action sheet, set a property to keep a reference to the action sheet. Set the property to nil on dismissal of the action sheet.

motion callbacks never called

I'm trying to make a shake events.
I tried:
1) How do I detect when someone shakes an iPhone? (posts of Kendall, and Eran)
2) motionBegan: Not Working
but nothig helps.
My View becomes first responder, but motionBegan/motionEnded never called.
Is there some additiol settings must be done, or i'm missing somethig? My iOS SDK is 4.3.
I have a class of UIView:
#import "ShakeView.h"
#implementation ShakeView
- (BOOL)canBecomeFirstResponder {
return YES;
}
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event {
NSLog (#"123");
if ( event.subtype == UIEventSubtypeMotionShake ) {
NSLog(#"Shake!");
}
if ([super respondsToSelector:#selector(motionEnded:withEvent:)]) {
[super motionEnded:motion withEvent:event];
}
}
#end
In my ViewController's xib class of View is ShakeView.
my ViewController pushed:
Wheel *secondViewController = [[Wheel alloc] initWithNibName:#"Wheel" bundle:nil];
[self.navigationController pushViewController:secondViewController animated:YES];
[secondViewController release];
In my ViewController:
- (void) viewDidAppear:(BOOL)animated
{
[self.view becomeFirstResponder];
[super viewWillAppear:animated];
NSLog(#"%d", [self.view isFirstResponder]);
}
- (void) viewWillDisappear:(BOOL)animated
{
[self.view resignFirstResponder];
[super viewWillDisappear:animated];
}
It logs "1", so it IS first responder. But it logs nothing else.
I spend a half day on this few lines of code, and I have no more ideas. Do anyone knows how to solve it?
Thanks.
This is much too late to help SentineL, but I was having the same problem and I like his question because it is clear that he has all the relevant code in place -- except one crucial line, in the application delegate's didFinishLaunching:
[self.window makeKeyAndVisible];
This is very hard to debug, because even without this line, everything else will be fine. Your gestures will work, your controls will respond, you will be able to make your view first responder (as SentineL checked) -- but your subclassed window or view or view controller will never receive the motion events.
Which doesn't make sense to me. Why would makeKeyAndVisible affect the accelerometer but not gestures? Hopefully some more experienced user can answer that.
P.S. If you use this code as an example, I would recommend that you omit the super respondsToSelector conditional. Of course it responds to the selector; you're overriding it.

Open a view on image Click in cover flow

I am using cover flow library in my project.My cover flow consist of many images.What I want to do is when I click on that image another View Controller should gets open.
Please tell me how to open another view on that image click.
Any help will be highly appreciated.
I had the same problem yesterday. I had to change something in the framework.
Add these two methods in the interface
#interface AFOpenFlowView : UIView
- (AFItemView *)selectedCoverView;
- (UIScrollView *)scrollView;
Add the implementations of these two methods inside of the .m file
#implementation AFOpenFlowView
- (AFItemView *)selectedCoverView {
return selectedCoverView;
}
- (UIScrollView *)scrollView {
return scrollView;
}
Set a UITapGestureRecognizer in the view controller where you're using the AFOpenFlowView
- (void)viewDidLoad {
[super viewDidLoad];
UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(screenTapped:)];
[[self view] addGestureRecognizer:tapRecognizer];
[tapRecognizer release];
}
At the end implement the method to handle the tap on the screen
- (void)screenTapped:(UITapGestureRecognizer *)tap {
CGPoint point = [tap locationInView:[af scrollView]];
if (CGRectContainsPoint([[af selectedCoverView] frame], point)) {
// Write here the code to open your view
// Use [af selectedCoverView].number to get the index of the selected cover
NSLog(#"selected cover view: %d", [af selectedCoverView].number);
}
}
Hope it's going to save you some time! ;)
Please try other FlowCover this is very easy to use...
Thanks

Delegate not being called

I've a viewcontroller "ResultsViewController" with a button called emailbutton. when this button is pressed, i want a function to be called from another view called "Illusions_AppViewController" (both these viewcontrollers are not linked).
Therefore i defined a protocol in the "ResultsViewController.h":
#protocol ResultsViewDelegate <NSObject>
#optional
- (void) resultspage;
#end
#interface ResultsViewController : UIViewController
{
id<ResultsViewDelegate> mydelegate;
UIButton *emailButton;
}
#property(nonatomic,retain) IBOutlet UIButton *emailButton;
#property (nonatomic,assign) id<ResultsViewDelegate> mydelegate;
#end
In the ResultsViewController.m :
-(IBAction)emailButtonPressed:(id)sender
{
NSLog(#"entered emailbuttonpressed");// the app enters this method and gets hanged
if ([mydelegate respondsToSelector:#selector(resultspage)]) {
NSLog(#"entered respondstoselector");// this is never displayed in the log-showing that the delegates doesnt respond to selector
[mydelegate resultspage];
}
}
In my other view, "Illusions_AppViewController.m":
- (void)resultspage{
NSLog(#"Entered results page");
ResultsPageController *resultspagecontroller = [[ResultsPageController alloc] initWithNibName:#"ResultsPageController" bundle:nil];
resultspagecontroller.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentModalViewController:resultspagecontroller animated:YES];
}
Would appreciate if anyone can help me with this. I've no clue of why the delegate is not called. the app gets hanged as soon as i press the emailbutton. Thanks!
The implementation/use of delegates is wrong. Please refer to this tutorial.
Hope this helps.
Thanks,
Madhup
or is there any other way to get this done. i just need the results page function to be called whenever the email button is pressed. i tried using this way:
ResultsViewController.m
-(IBAction)emailButtonPressed:(id)sender
{
NSLog(#"entered emailbuttonpressed");
illusions_AppViewController *illusionsview = [[illusions_AppViewController alloc]init];
[illusionsview performSelector:#selector(resultspage)];
}
Now the results page function gets called, but the resultspagecontroller that it needs to display as a modalviewcontroller never appears.the app hangs, and no errors in the console either.
To answer your second question, you are on the right track. Simply create an instance of your Illusions_AppViewController and call the illusionsView method in it instead using:
- (IBAction)emailButtonPressed {
illusions_AppViewController *illusionsview = [[illusions_AppViewController alloc]init];
[illusionsview resultspage];
[illusionsview release];
}

Storing UITextField contents before view pops

I am sure this is in the Apple documentation or must have been answered somewhere on this forum, since it seems so basic, but I could not find it nor a particularly elegant solution myself.
What I have is a UIViewController that pushes an editing view on its navigation stack. The editing view has a bunch of UITextFields in it. If one of them is being editing when the back button is touched, the original view's ViewWillAppear method is called before either the UITextField delegate methods of textFieldShouldEndEditing or textFieldDidEndEditing, or the IB linked action textFieldEditingEnded method are called.
Here is some code that I hope will make it clearer:
In the UIViewController:
- (void) viewWillAppear: (BOOL) animated {
[super viewWillAppear: animated];
NSLog( #"Entering view will appear for master view" );
nameLabelField.text = objectToEdit.name;
}
- (IBAction) editMyObject: (id) sender {
NSLog( #"Editing the object" );
EditViewController *evc = [[EditViewController alloc] initWithNibName: #"EditTableView" bundle: nil];
evc.editedObject = objectToEdit;
[self.navigationController pushViewController: evc animated: YES];
[evc release];
}
In the EditViewController <UITextFieldDelegate>:
- (void) viewWillAppear: (BOOL) animated {
[super viewWillAppear: animated];
nameField.text = editedObject.name;
}
- (void) viewWillDisappear: (BOOL) animated {
[super viewWillDisappear: animated];
NSLog( #"In viewWillDisappear" );
if( [self.navigationController.viewControllers indexOfObject: self] == NSNotFound ) {
NSLog( #"-- We are not in controller stack... the back button has been pushed" );
}
}
- (BOOL) textFieldShouldEndEditing: (UITextField *) textField {
NSLog( #"In textFieldShouldEndEditing" );
// Store text field value here???
// editedObject.name = nameField.text;
return YES;
}
- (void) textFieldDidEndEditing: (UITextField *) textField {
NSLog( #"In textFieldDidEndEditing" );
// Store text field value here???
// editedObject.name = nameField.text;
}
- (IBAction) textFieldEditingEnded: (id) sender {
NSLog( #"In textFieldEditingEnded" );
// Store text field value here???
// editedObject.name = nameField.text;
}
The log ends up with:
[...] Entering view will appear for master view
[...] Editing the object
[...] In viewWillDisappear
[...] -- We are not in controller stack... the back button has been pushed
[...] Entering view will appear for master view
[...] In textFieldShouldEndEditing
[...] In textFieldEditingEnded
[...] In textFieldDidEndEditing
I want to set self.editedObject.name = nameField.text before the label gets set in viewWillAppear for the UIViewController.
I thought about in the viewWillDisappear method for the EditViewController checking to see if any of my text fields are currently the first responder and if so getting their text and storing it, but this seems like such a kludge that will be a pain to maintain if I add or change text fields.
I can also implement the textFieldEditingChanged IB linked action to set the text in the edited object after every keystroke but this is also quite a bit of overhead since I have to figure out which text field I am in every keystroke (remember I only showed name but there are a whole bunch of them).
All I need is for the editing to be ended or to know the editing will be ended before viewWillAppear is called in the UIViewController so the nameFieldLabel is properly set.
OK, I figured out a simple solution after a lot of web-surfing, forum reading, and manual reading. It was, as I suspected, very simple, only one line of code added. In the viewWillDisappear method of the EditViewContorller I simply added:
[self.view.window endEditing: YES];
Now textFieldShouldEndEditing, textFieldEditingEnded, and textFieldDidEndEditing all get fired off before the viewWillAppear of the master view does.
So now the viewWillDisappear method looks like:
- (void) viewWillDisappear: (BOOL) animated {
[super viewWillDisappear: animated];
NSLog( #"In viewWillDisappear" );
// Force any text fields that might be being edited to end so the text is stored
[self.view.window endEditing: YES];
}
And the methods already in place to handle the 'Return' on the keyboard also handle the 'Back' button on the Navigation controller.
Thank you Aaron and Jeff for your assistance and helping me think this through.
Why not just create your own Back button with that logic in its action method?
I would think that from a UX perspective, you should display an alert to determine if the user wants to cancel the edit action they were in the middle of before exiting the current view.
By alerting the user, you can see if they hit the button by accident or if they did decide to leave the view, take the appropriate action.
// add this to the field(s) to be edited, selector will be called as the changes
// are being made... still difficult to handle a cancel, but should work
[objectToEdit addTarget:self action:#selector(updateNameField:)
forControlEvents:UIControlEventEditingChanged];
additional code here...
// the method called to update object from parent view
- (void)updateNameField:(id)sender {
<OBJECT TO UPDATE>.text = ((UITextField *)sender).text;
}