I'm building an app where the first view has a menu panel, and I want this panel to stick around for the life of the app. The only places the user can "go" are reachable via buttons on this panel (a UICollectionView). In case it matters, this app is landscape-only, and iOS 6-only.
In order to make this work I created a custom segue, which removes everything from the view except for the menu panel, then adds the new view controller's view as a subview, sets the new view's frame to the bounds of the superview, and sends the new view to the back (so it's behind the menu panel). I call viewWill/DidDisappear from prepareForSegue, because otherwise they don't get called.
It may sound kludgy (it does to me), but it works fine except for one thing - the new view comes up from the bottom. It looks funny.
I then tried adding my own animation block - I initially locate the view off to the left, then animate it into place. I send it to the back in the completion block for the animation. This seems perfectly logical, and the frame values are all what they should be. But this one is worse - the view comes in from the lower left corner.
Can anyone suggest a way to make this work? Here's my current perform method:
- (void)perform {
MainMenuViewController *sourceVC = (MainMenuViewController *)self.sourceViewController;
UIViewController *destinationVC = (UIViewController *)self.destinationViewController;
for (UIView *subview in [sourceVC.mainView subviews]) {
// don't remove the menu panel or the tab
if (![subview isKindOfClass:[UICollectionView class]] && [subview.gestureRecognizers count] == 0) {
[subview removeFromSuperview];
}
}
[sourceVC.mainView addSubview:destinationVC.view];
CGRect finalFrame = sourceVC.mainView.bounds;
CGRect frame = finalFrame;
frame.origin.x = finalFrame.origin.x - finalFrame.size.width;
destinationVC.view.frame = frame;
[UIView animateWithDuration:0.5 animations:^{
destinationVC.view.frame = finalFrame;
} completion:^(BOOL finished) {
// make sure it ends up behind the main menu panel
[sourceVC.mainView sendSubviewToBack:destinationVC.view];
}];
}
It turned out to be a simple error - I needed to set destinationVC's frame before calling addSubview. Setting it afterwards was triggering the unwanted animation.
Related
I want to add a button that show/hides the popover, similarly to the one of the DropBox app.
(In both landscape & portrait)
I have tried many solutions, but at this stage I don't even want to muddy the water with my attempts. If you've done this, or know how to do this, please send me in the right direction!
Thanks!
it appears it's quite simple.
Set some object to be delegate of splitViewController. In my case (I create all viewcontrollers programatically) that was appdelegate.
UISplitViewController* splitViewController = [[UISplitViewController alloc] init];
[splitViewController setViewControllers:#[navigationViewController1, navigationViewController2]];
splitViewController.delegate = self;
Implement delegate method to hide master in portrait orientation:
- (BOOL)splitViewController:(UISplitViewController *)svc shouldHideViewController:(UIViewController *)vc inOrientation:(UIInterfaceOrientation)orientation {
return UIInterfaceOrientationIsPortrait(orientation);
}
Actually add barButtonItem:
-(void)splitViewController:(UISplitViewController *)svc
willHideViewController:(UIViewController *)aViewController
withBarButtonItem:(UIBarButtonItem *)barButtonItem
forPopoverController:(UIPopoverController *)pc {
UINavigationController* slaveNavigationViewController = svc.viewControllers[1];
UIViewController* slaveViewController = slaveNavigationViewController.viewControllers[0];
[barButtonItem setTitle:#"Your master title"];
slaveViewController.navigationItem.leftBarButtonItem = barButtonItem;
}
In this method, you get barButtonItem which you customize and add to slaveViewController.
And last one, remove the button in landscape orientation:
- (void)splitViewController:(UISplitViewController *)svc willShowViewController:(UIViewController *)aViewController invalidatingBarButtonItem:(UIBarButtonItem *)barButtonItem {
UINavigationController* slaveNavigationViewController = svc.viewControllers[1];
UIViewController* slaveViewController = slaveNavigationViewController.viewControllers[0];
[barButtonItem setTitle:#"Drops"];
slaveViewController.navigationItem.leftBarButtonItem = nil;
}
That's it.
There's a simpler, undocumented way to do it. For an existing UIButton:
[button addTarget: theSplitViewController action: #selector(toggleMasterVisible:) forControlEvents:UIControlEventTouchUpInside];
This target/action are the same as for the barButtonItem sent in the willHideViewController function.
I integrate the iCarousel app with single view application.But when I add the tab bar controller and place this iCarousel code in one tab bar Item viewcontroller.But it does not work(Items are displayed but not scrolled).What is the problem here.
I created iCarousel as below:
iCarousel *categorySubView = [[iCarousel alloc]initWithFrame:CGRectMake(0,200, 300, 125)];
categorySubView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
categorySubView.delegate = self;
categorySubView.dataSource = self;
categorySubView.type=iCarouselTypeRotary;
[self.view addSubview:categorySubView];
I am using the following delegae and data source methods:
-(NSUInteger)numberOfItemsInCarousel:(iCarousel *)carousel
{
return 5;
}
- (UIView *) carousel:(iCarousel *)carousel viewForItemAtIndex:(NSUInteger)index reusingView:(UIView *)view{
UIView *sampleView=[[UIView alloc]initWithFrame:CGRectMake(0, 0, 250, 300)];
sampleView.backgroundColor=[UIColor whiteColor];
UILabel *labelis=[[UILabel alloc]initWithFrame:CGRectMake(10, 10, 100, 20)];
labelis.backgroundColor=[UIColor clearColor];
labelis.text=#"8Apr-14Apr";
[sampleView addsubView:labelis];
return sampleView;
}
Please suggest me.
Thanks inadvance
I notice that your carousel view is much smaller than the size of the items inside it (it's only 125 points high).
iCarousel can draw outside of its bounds, but it cannot detect touch events outside of its bounds, so that might be why you are having trouble scrolling.
A good way to debug this is to set the carousel.clipsToBounds = YES, that way what it draws will match what is touchable. Another option is to set the carousel.backgroundColor so you can see what part of it is touchable on screen.
Another thing to check is that the view that you've placed the carousel inside has userInteractionEnabled set to YES.
I use an instance of UITextField in which the text is normally aligned to the right, but switches to left alignment when being edited. This is done by calling setTextAlignment: on the editingDidBegin event. Since the update to iOS 6 this behaves strangely: The text alignment is changed correctly from right to left, but the cursor remains at the far right of the text field until some input is performed.
Does anybody know how to restore the expected behaviour so that the cursor moves as well when the alignment is changed?
To give some context: I use the text field to show a value with a unit. The unit is removed during editing and then displayed again after the user hits enter.
Method called on event editingDidBegin:
- (IBAction)textEditingDidBegin:(UITextField *)sender
{
[sender setTextAlignment:NSTextAlignmentLeft];
[sender setText:[NSString stringWithFormat:#"%.0f", width]];
}
Method called on event editingDidEnd:
- (IBAction)textEditingDidEnd:(id)sender
{
[sender setTextAlignment:UITextAlignmentRight];
[sender setText:[NSString stringWithFormat:#"%.0f m", width]];
}
Try resigning the textView as first responder, then make it first responder right after that.
textView.textAlignment = NSTextAlignmentCenter;
[textView resignFirstResponder];
[textView becomeFirstResponder];
-(BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
textField.textAlignment = NSTextAlignmentLeft ;
return YES ;
}
Change the textAlignment before editing did begin. The best place I know to do this is in the UITextFieldDelegate method textFieldShouldBeginEditing.
I want to display a MPMoviePlayerViewController in full screen mode, but when the fullscreen button of the movieplayercontroller view is beeing pressed, first the MPMoviePlayerWillEnterFullscreenNotification gets called, as expacted, but than the MPMoviePlayerPlaybackDidFinishNotification is also beeing sent. As a reason it says MPMovieFinishReasonPlaybackEnded and i don't know, what i'm doing wrong. (In addition, i use iOS 6.0 and XCode 4.5.1)
My expactations are, that only the MPMoviePlayerWillEnterFullscreenNotification is beeing called.
Short explanation to the code below:
The MovieplayerViewController's view is beeing displayed in a tiny subview in my content view. When tapping the fullscreen-button, it first gets displayed as fullscreen but than also calls the exit button and stops playing (no crashes, nothing else).
MPMoviePlayerViewController *playerViewController = [[MPMoviePlayerViewController alloc] initWithContentURL:url];
[playerViewController.moviePlayer setControlStyle:MPMovieControlStyleEmbedded];
[playerViewController.moviePlayer setScalingMode:MPMovieScalingModeFill];
CGRect rect = videoView.frame;
rect.origin = CGPointZero;
[playerViewController.view setFrame:rect];
[playerViewController.moviePlayer prepareToPlay];
//movie this is my contents subview, where i add the viewcontroller's view as a subbview
[self.videoView addSubview:playerViewController.view];
[self.videoView setHidden:NO];
playerViewController.moviePlayer.useApplicationAudioSession = NO;
[playerViewController.moviePlayer play];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayerDidFinishNotification:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:playerViewController.moviePlayer];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayerWillEnterFullscreenNotification:)
name:MPMoviePlayerWillEnterFullscreenNotification
object:playerViewController.moviePlayer];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayerWillExitFullscreenNotification:)
name:MPMoviePlayerWillExitFullscreenNotification
object:playerViewController.moviePlayer];
//i store the movieplayer in a property, so i can use it for further operations
self.myPlayer = playerViewController;
[playerViewController release];
And thats it!
When the resize (or fullscreen) button is being pressed, the moviePlayerDidFinishNotification: method also is being called
- (void)moviePlayerDidFinishNotification:(NSNotification*) aNotification {
int reason = [[[aNotification userInfo] valueForKey:MPMoviePlayerPlaybackDidFinishReasonUserInfoKey] intValue];
if (reason == MPMovieFinishReasonPlaybackEnded) {
//movie finished playin
//in debug mode, it stops right at the NSLog
NSLog(#"");
}
else if (reason == MPMovieFinishReasonUserExited) {
//user hit the done button
}
else if (reason == MPMovieFinishReasonPlaybackError) {
//error
}
.. }
Is there something i do wrong or is there probably a change since iOS 6.0?
Ok, seems to be that there are some problems in the MPMoviePlayerViewController. What helped is to simply us the MPMoviePlayerController only.
For future reference the reason that your player showed in a small window was because you were setting:
[playerViewController.moviePlayer setControlStyle:MPMovieControlStyleEmbedded];
[playerViewController.moviePlayer setScalingMode:MPMovieScalingModeFill];
CGRect rect = videoView.frame;
rect.origin = CGPointZero;
[playerViewController.view setFrame:rect];
[playerViewController.moviePlayer prepareToPlay];
//movie this is my contents subview, where i add the viewcontroller's view as a subbview
[self.videoView addSubview:playerViewController.view];
[self.videoView setHidden:NO];
When you use an MPMoviePlayerViewController it creates it's own view controller. These calls are not necessary and will only create bizarre behavior. That's why the MPMoviePlayerController worked properly because it's designed to work inside another view controller.
I have a winforms app with a main form (fMain) and two child forms (fLogin and fAdmin). fLogin is displayed using this code which is in a button click event handler for a button on the main form:
// show login form; pass the main form in as an argument
fLogin formLogin = new fLogin(this);
formLogin.StartPosition = FormStartPosition.CenterParent;
formLogin.ShowDialog(this);
In the constructor for fLogin, I assign the main form to a private member level variable.
// fLogin
fMain _mainForm;
// fLogin constructor
public fLogin(fMain mainForm)
{
InitializeComponent();
_mainForm = mainForm;
}
As you might imagine, fLogin is a small form with textboxes for a username and password and a couple of buttons. When my users enter their credentials and click the OK button, fLogin will validate the information with a server and if the information is good, fLogin will disappear and fAdmin will be displayed. Currently, I'm displaying fAdmin like this:
// hide formLogin right away
this.Hide()
// show admin form
fAdmin formAdmin = new fAdmin();
formAdmin.StartPosition = FormStartPosition.CenterParent;
formAdmin.Show(_mainForm); // pass main form as owner of admin form
// close formLogin
this.Close();
I can't set formAdmin.Parent = _mainForm and get the dialog to magically center itself. So I'm passing _mainForm to formAdmin.Show() as the owner of formAdmin but that doesn't seem to help with regard to getting formAdmin centered. Is there an easy way to cause formAdmin to be displayed at the center of the main form?
I think you need to restructure how you are doing this just a bit, instead of displaying fAdmin from within fLogin, close fLogin and then open fAdmin from fMain. If this doesn't work you can manually center if by calculating the point for the upper left corner of fAdmin and set this point as fAdmin's Location. I've had to do this in the past when I've encountered similar issues. To calculate the upper left corner for fAdmin so that it will be centered on fMain, use the following:
Point p = new Point(0, 0);
p.Y = (fMain.Height / 2) - (fAdmin.Height / 2);
p.X = (fMain.Width / 2) - (fAdmin.Width / 2);
fAdmin.Location = p;