Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iPhone flip right button (like iTunes)

I'm trying to flip between two views. That's easy, the code is below, but I also want to simultaneously flip the button used to perform the flip.

You can see this behavior in the iPod application when you're playing a track; tapping the flip button flips between the cover art and the track listing, but it flips the button at the same time.

This is a page on the navigation controller, and the button I want to flip is the rightBarButtonItem.

Here's the code I have so far. This flips the view, but not the rightBarButton.

[UIView setAnimationBeginsFromCurrentState: YES];
[UIView setAnimationDuration: 0.5f];
[UIView setAnimationCurve: UIViewAnimationCurveEaseInOut];
showingBackside = !showingBackside;
if (showingBackside) {
    [UIView setAnimationTransition: UIViewAnimationTransitionFlipFromLeft
                           forView: self.view
                             cache: YES];
    [self.view addSubview: backside.view];
    [frontside.view removeFromSuperview];
} else {
    [UIView setAnimationTransition: UIViewAnimationTransitionFlipFromRight
                           forView: self.view
                             cache: YES];
    [self.view addSubview: frontside.view];
    [backside.view removeFromSuperview];
}
// flip image, too
NSString *newImage = showingBackside ? @"backside.png" : @"frontside.png";
[(self.navigationItem.rightBarButtonItem) setImage: [UIImage imageNamed: newImage]];
[UIView commitAnimations];

(The image flipping code here may not compile; I added it after to try to explain what I was trying to do.)

Where I'm running into trouble is I want to change the rightmost button in the navigation controller so it flips simultaneously.

How do I do this? What view do I animate, and do I do it as part of the same animation block or as a separate one? Any tips would be appreciated, I definitely don't have a good handle on animation yet.

like image 260
Steven Fisher Avatar asked Jul 17 '09 00:07

Steven Fisher


3 Answers

There's some discussion here, but the solution is not so elegant.

First of all, since UIBarButtonItem is not a descendant of UIView, you probably cannot use UIKit animations directly on the UIBarButtonItem. However, you can try setting a customView and animating that. You can use the same animation block.

like image 180
Can Berk Güder Avatar answered Oct 18 '22 01:10

Can Berk Güder


Okay, here's what I actually did to fix this:

I was already using a custom title view. Instead of using rightBarButtonItem, I made my custom view wider.

I created an image of both sides of the button, complete with the navigation frame, and embedded them into the application. In my title view, I put:

  • A UIView that will be my replacement for the right control (call it rightControl), positioned appropriately.
  • A button over the UIView that responds to UIControlEventTouchUpInside and triggers my flipSide:.

At runtime I create a UIImageView for each state. I putboth UIImageViews in rightControl, but hide the one that isn't default. I switch the hidden flags around in flipSide: in a dedicated animation block.

Insanely weird. But it works.

like image 45
Steven Fisher Avatar answered Oct 18 '22 00:10

Steven Fisher


Just use a custom UIView for the right navigation button that contains two buttons to flip between.

You can use a straight forward approach of creating a custom UIView that is displayed as the right navigation button item. This UIView should contain the two UIButtons you want to flip between. Remember that UIButtons are UIViews too so they can be flipped using the same transitions that a normal UI view can be flipped with and of course they can be tapped! Here is some sample code that works:

Note: I use a convenience function to create buttons as a custom category of UIViewController (note: you can add this same code to create a custom category for UIView too, just copy the same lines and replace UIViewController with UIView) - If you want to use it too just create a custom category by including this code below, alternately you can create the UIButtons as you normally would.

// create custom category for UIViewController to allow common button creation routine, add to .m or .mm file or add to a .h file and #import that .h file
        @interface UIViewController (ButtonAndSelector)
        - (UIButton *)createUIButtonWithImage:(UIImage *)image forState:(UIControlState)state withSelector:(SEL)selector usingFrame:(CGRect)buttonImageFrame;
        @end

        @implementation UIViewController (ButtonAndSelector)
        - (UIButton *)createUIButtonWithImage:(UIImage *)buttonImage forState:(UIControlState)state withSelector:(SEL)selector usingFrame:(CGRect)buttonImageFrame
        {
            UIButton *button = [[UIButton alloc]  initWithFrame:buttonImageFrame];
            [button setBackgroundImage:buttonImage forState:state];
            [button addTarget:self action:selector forControlEvents:UIControlEventTouchUpInside];
            [button setShowsTouchWhenHighlighted:YES];
            return button;
        }
        @end

// add this to your .h file:
        @property (strong, nonatomic) UIView *coverListView;
        @property (strong, nonatomic) UIButton *listButton;
        @property (strong, nonatomic) UIButton *coverButton;

        - (void)animateCoverListButtonFlip;

// add this to your .m or .mm file to synthesize the variables:
        @synthesize coverListView;
        @synthesize listButton;
        @synthesize coverButton;

// add this to your .m or .mm file in the viewDidLoad:

        // setup right button bar (flips between list icon and coverart image)
        self.coverListView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 32, 30)];
        self.coverListView.backgroundColor = [UIColor clearColor];
        self.coverListView.opaque = NO;

        self.listButton = [self createUIButtonWithImage:[UIImage imageNamed:@"navbar_icon_tracklisting"] forState:UIControlStateNormal withSelector:@selector(showHideQueue) usingFrame:CGRectMake(0, 0, 32, 30)];
        self.listButton.backgroundColor = [UIColor clearColor];
        self.listButton.showsTouchWhenHighlighted = NO;

        self.coverButton = [self createUIButtonWithImage:[UIImage imageNamed:@"default_coverart_small"] forState:UIControlStateNormal withSelector:@selector(showHideQueue) usingFrame:CGRectMake(0, 0, 32, 30)];
        [self.coverListView addSubview:self.coverButton]; // show coverButton by default
            self.coverButton.showsTouchWhenHighlighted = NO;

        UIBarButtonItem *barButtonItem = [[UIBarButtonItem alloc] initWithCustomView:self.coverListView];
        [self.navigationItem setRightBarButtonItem:barButtonItem];


// add this to viewDidAppear if you want to flip the button when the screen appears like the build in iPod app does
        [self animateCoverListButtonFlip];

// add this routine to flip the right navigation bar custom view / buttons
        - (void)animateCoverListButtonFlip
        {
            [UIView beginAnimations:nil context:NULL];
            [UIView setAnimationDuration:0.75];    
            [UIView setAnimationTransition:([self.listButton superview] ? UIViewAnimationTransitionFlipFromLeft : UIViewAnimationTransitionFlipFromRight) forView:self.coverListView cache:YES];

            if ([self.listButton superview]) {
                [self.listButton removeFromSuperview];
                [self.coverListView addSubview:self.coverButton];
            } else {
                [self.coverButton removeFromSuperview];
                [self.coverListView addSubview:self.listButton];
            }
            [UIView commitAnimations];
        }

// when the playing album cover changes, remember to update the coverButton:
        UIImage *artworkImage; // set this to the current playing album image
        [self.coverButton setImage:artworkImage forState:UIControlStateNormal]; 

// don't forget to call the animateCoverListButtonFlip in the button click handler (shown above as showHideQueue) that shows and hides the cover/queue(list of album tracks0 - something like this:

        - (void)showHideQueue
        {    
            [self animateCoverListButtonFlip];

            /* replace the code below that is commented out here with your own code that transitions between your cover view and your list view of album tracks, this code shows my transition and references views that are not part of this example/answer, but you don't need those - you'll have your own cover view (musicPlayerView) and list view (musicQueueView) to flip between.
            [UIView beginAnimations:nil context:NULL];
            [UIView setAnimationDuration:0.75];
            [UIView setAnimationTransition:([musicQueueView superview] ? UIViewAnimationTransitionFlipFromLeft : UIViewAnimationTransitionFlipFromRight) forView:self.contentView cache:YES];

            if ([musicQueueView superview]) { // if music queue is displayed
                [musicQueueView removeFromSuperview];
                [self.contentView addSubview:musicPlayerView];
            } else {
                [musicPlayerView removeFromSuperview];
                [self.contentView addSubview:musicQueueView];
                [[musicQueueView queueTableView] reloadData];
            }
            [UIView commitAnimations];*/
        }
like image 37
Richie Hyatt Avatar answered Oct 18 '22 02:10

Richie Hyatt