4

I would like to put the undocumented trash can animation in my program. The call method is:

+ (void)animateToolbarItemIndex:(unsigned)index duration:(double)duration target:(id)target didFinishSelector:(SEL)selector;

Can anyone figure out what I should plug in for:

  • index
  • duration
  • target
  • selector ?

My trials are not working resulting in the error:

2011-11-15 16:05:20.639 CNiPhone[973:707] +[UIToolbar animateToolbarItemIndex:duration:target:didFinishSelector:]: unrecognized selector sent to class 0x3f019c08
2011-11-15 16:05:20.641 CNiPhone[973:707] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+[UIToolbar animateToolbarItemIndex:duration:target:didFinishSelector:]: unrecognized selector sent to class 0x3f019c08'

Here is the relevant code:

@interface UIToolbar (privateMethods2)

+ (void)animateToolbarItemIndex:(unsigned)index duration:(double)duration target:(id)target didFinishSelector:(SEL)selector;

@end

    [UIToolbar animateToolbarItemIndex:0 duration:0.5 target:trashToolbarButton didFinishSelector:@selector(animateTrashStep2)];
    [UIToolbar commitAnimations];

- (void) animateTrashStep2 {
}
DShah
  • 9,768
  • 11
  • 71
  • 127
T.J.
  • 3,942
  • 2
  • 32
  • 40
  • This is because you don't want to be in the App Store? – David Dunham Nov 16 '11 at 00:22
  • Yes, I understand this is method is not documented. Apple's approval is not an issue of me. – T.J. Nov 16 '11 at 01:39
  • I'm sure the is someone on stack/overflow who can post an animation and images that solve this problem. – T.J. Jan 27 '12 at 15:34
  • Bounty Comments: The question is widely applicable to a large audience. A detailed canonical answer is required to address all the concerns. I see that this question has be viewed over a 100 times. I would like someone to post a trash can animation and images similar to Apple's implementation that can be used with confidence in Apps intended for the App Store. – T.J. Feb 03 '12 at 15:28
  • Week of Bounty is over and some good ideas have been posted, but still no complete working solution. I've up voted all the answers because they each provide some clues to help to anyone wanting to continue with this. The system will award half the bounty to the most up voted answer. It would be misleading of me to accept any one answer at this point. When I get this worked out I'll post my final solution. – T.J. Feb 03 '12 at 15:33

6 Answers6

3

You need to call it on the toolbar connected to your IBOutlet as opposed to the class. E.g.:

[self.myToolbar /*(possibly just myToolbar)*/ animateToolbarItemIndex:0 duration:0.5 target:trashToolbarButton didFinishSelector:@selector(animateTrashStep2)];
jrtc27
  • 8,496
  • 3
  • 36
  • 68
  • I tried that. This is part of an nav view controller so the statement becomes: [self.navigationController.toolbar animateToolbarItemIndex:0 duration:0 target:self.trashToolbarButton didFinishSelector:@selector(animateTrashStep2)]; It won't compile giving an error: Receiver type 'UIToolbar' for instance message does not declare a method with selector 'animateToolbarItemIndex:duration:target:didFinishSelector:' – T.J. Nov 16 '11 at 01:40
  • Sounds like your undocumented method is not documented correctly. In other words, if neither the class (as you defined it in the question) nor the instance respond, this is not the correct selector. – David Dunham Nov 16 '11 at 18:47
  • That's too bad. It is a nice animation. If anyone has written code and images for something similar please post it! – T.J. Nov 16 '11 at 22:02
3

You dont need to do any undocumented stuff for this, just create a custom UIButton. Download the UIKit Artwork Extractor and you'll find the frames for the trash can animation, as well as the UIBarButtonItem background.

John Estropia
  • 17,460
  • 4
  • 46
  • 50
  • Can I use this artwork in a project I plan to submit to the app store? Do I need to credit Apple or anyone of the images? – T.J. Jan 31 '12 at 19:40
  • I'm afraid you have the correct concern here. There are a lot of apps out there that use a few of the built-in images (you can get the images through screenshots after all), but in your case it's a whole animation you're using so this will be all up to your app's reviewer. You did say that Apple's approval is not an issue though... – John Estropia Feb 01 '12 at 00:13
  • I did have that in the original question, but raised the requirement to App store approved when I put a bounty on the question because I think that answer will have wide appeal. – T.J. Feb 01 '12 at 01:40
  • Either way, it's still the safest and elegant method you can use (unless you want to draw your own image frames). The other options pointed out here (as of this time of writing) will just get you into more trouble with Apple's reviewers. – John Estropia Feb 02 '12 at 00:24
  • After using the artwork extractor I was able to get it to work referencing http://www.grokkingcocoa.com/a-simple-way-to-animate-a-u.html. – T.J. Feb 05 '12 at 23:52
  • That's how I would do it too. Good luck with the app store! – John Estropia Feb 06 '12 at 03:54
1

You will probably find the answer here: https://stackoverflow.com/a/5101910/796103

Community
  • 1
  • 1
Christian Schnorr
  • 10,768
  • 8
  • 48
  • 83
  • I'm looking for a more complete answer imitating the suckEffect and the trash can lid opening and closing. – T.J. Jan 27 '12 at 16:36
  • The trash can itself is not a real UIView animation, it's rather a set of images combined to simulate a nice animation. – Christian Schnorr Jan 27 '12 at 21:55
1

It's probably because your target is set to trashButtonItem. The target is the object that the didFinishSelector will be sent to. Try setting the target to self. Also, according to http://iphonedevwiki.net/index.php/UIToolbar this is not a class method so you will need to replace the [UIToolbar with the actual toolbar object.

In your didFinishSelector callback I guess you call the method again and the trashcan will close.

Good luck.

Daddy
  • 9,045
  • 7
  • 69
  • 98
1

This 'undocumented' method is documented here: http://iphonedevwiki.net/index.php/UIToolbar

It's documented as being an instance method and not a class method, which explains the error message you're receiving in the exception.

@jrtc27 has answered the question correctly, in that this should be sent to the UIToolbar instance instead. From your reply to the comments, it seems that you have not changed your class category to assist the compiler. Try the following instead:

@interface UIToolbar (privateMethods2)
- (void)animateToolbarItemIndex:(unsigned)index duration:(double)duration target:(id)target didFinishSelector:(SEL)selector;
@end

And then use:

[self.navigationController.toolbar animateToolbarItemIndex:0 duration:0 target:self.trashToolbarButton didFinishSelector:@selector(animateTrashStep2)];
ikuramedia
  • 6,038
  • 3
  • 28
  • 31
  • I did as you said and it runs without errors, but there is no animation and the selector is not called. This is my statement: [self.navigationController.toolbar animateToolbarItemIndex:4 duration:2 target:self didFinishSelector:@selector(animateTrashStep2)]; Also, I don't know you mean by "it seems that you have not changed your class category to assist the compiler". How do I do that? – T.J. Jan 31 '12 at 19:21
  • (privateMethods2) is a 'category' on the UIToolbar class. It allows you to extend existing classes with new methods.in this case the method already exists, but the compiler doesn't know about it, so it won't compile. The first code fragment I posted is the 'fix'. I'm not sure why it's not animating, maybe the index is incorrect? – ikuramedia Feb 01 '12 at 04:25
  • I used NSLog to spit out the indexes of all the buttons so I'm sure I got that right. Is there possibly a library I need to include? Have your been able to get it to animate? – T.J. Feb 01 '12 at 17:41
1

I think if you know how to do the suckEffect, then you can do a little bit hacking with the toolbar.

Basically, all the official controls are a subclass of UIView, hence you can find out the view hierarchy of the UIToolBar instance.

If you don't know how to find out the subview hierarchy of a given view, you can use a PRIVATE API - (void)recursiveDescription from UIView. Remember to use it in DEBUG configuration.

Why should we bother the view hierarchy?

The answer is, to hide certain view, or to add a subview as we want.

What's next

  1. Find the origin UIBarButtonItem view of your trash can
  2. Before the suckEffect start, hide it, add a new trash can view which can do the animation of open/close/shaking. This moment I think you need to ask it to do open animation.
  3. Then let the suckEffect fly...
  4. After the suckEffect ended, ask your view to do the close animation.
  5. After the close animation is finished, remove your view, and reshow the original trash can view.

Possibility?

I haven't done it before, but I think it's a possible solution because creating an trash can view with open/close/shaking animation is easy.

Risk?

Anyway, this solution is like some kind of hacking without touching the private api, the risk is on your own.

Good luck.

Tonny Xu
  • 2,162
  • 2
  • 16
  • 20