In an iOS run on iOS 6.1 (emulated) and 6.1.3 (physical device) application we show an UIActionSheet from a view with the following code:
UIActionSheet *actionCreateNewComment = [[UIActionSheet alloc] initWithTitle:CLocalised(#"EditExistingComment") delegate:self cancelButtonTitle:CLocalised(#"No") destructiveButtonTitle:nil otherButtonTitles: CLocalised(#"Yes"), nil];
[actionCreateNewComment setActionSheetStyle:UIActionSheetStyleBlackOpaque];
[actionCreateNewComment setTag:ActionSheetTagNewComment];
[actionCreateNewComment showFromToolbar:self.navigationController.toolbar];
[actionCreateNewComment release];
The View sets the toolbar with:
UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithCustomView:control];
[self setToolbarItems:[NSArray arrayWithObject:item]];
Where control is an UISegmentedControl.
The code for handling the button actions are:
-(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex{
bool shouldAddNewComment = buttonIndex == [actionSheet cancelButtonIndex];
[self navigateToCommentScreen:shouldAddNewComment];
}
Every time this action sheet is shown the tool bar will go "blank". Not only for this view but also for the other views.
Here is an example of a work flow:
Note that if I navigate from Instr to Comment without the UIActionSheet, but otherwise the same code, the problem will not appear.
The problem here is that in the "Instr" view the toolbar is empty.
If I pop two more views to return to "List" its toolbar will be empty as well:
Even if I then navigate back to WO and Instr, by allocing and init new forms, and then pushing them, the toolbars will still be empty.
There is another navigation option from the "List" View that shows a "Summary" view. Depending on the data this view will show with or without buttons in the toolbar:
Both "Summary Button" and "Summary empty" are intended views. "Summary hidden" is shown after the UIActionSheet have been shown before navigating between Inst and Comment.
But if I navigate to a "Summary" view that is shown as "Summary Empty" in the picture (intended, due to the data) then the toolbar will start working everywhere again. Or at least until I show the UIActionSheet from the Instr view again.
There are some, in my opinion, strange things about this:
If I navigate to a view where the toolbar is empty, which hides the toolbar, see pic: "SummaryEmpty", then the toolbar will show as intended in the other views.
We use the same code to show an action sheet in other views of the application without any problem
If I run the application on an emulated iOS 5.1 or emulated iOS 5.0 the problem does not appear
Have I missed something when it comes to dismissing the action sheet or how to show it?
Please let me know if you want more information.
Update:
If I forcibly call [self setToolbarItems:nil] after the action sheet button event and then update it with the same items as before the Tool bar will show up as intended.
This does not feel as the right way to do it.
Update 2013-05-28:
Thanks to #LOP_Luke I found out that if I do not navigate to the "Comment" view from -(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex but just returned the tool bar will start working again.
So, can there be some kind of problem when I navigate to another view when then clickedButtonAtIndex is still on the call stack?
Update 2013-05-29:
If I add a method:
-(void)commentScreenYes{
[self vanigateToCommentScreen:YES];
}
And change the button code to:
-(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex{
bool shouldAddNewComment = buttonIndex == [actionSheet cancelButtonIndex];
if(shouldAddNewComment){
[self performSelectorOnMainThread:#selector(commentScreenYes) withObject:nil waitUntilDone:NO];
return;
}
[self navigateToCommentScreen:shouldAddNewComment];
}
Then it will work for the cancel button, but not for the yes button. The cancel button will also make the toolbar work again after it have been "broken" by the yes button. If I pipe both buttons through this flow (by adding a new method) they will both work.
And still, if I run it at iOs 5.1 it will work no matter which flow I choose.
The – setToolbarItems method is a UIViewController method specific to each child view controller of your navigation controller. Assuming [self navigateToCommentScreen:shouldAddNewComment] pushes a new view controller onto the navigation stack you will have to set the toolbar items for the new view controller too as a separate call, regardless of what the action sheet is doing. For example,
-(void) navigateToCommentScreen:(bool) shouldAddComment{
CommentViewController* viewController = [[CommentViewController alloc] init];
[self.navigationController pushViewController:viewController animated:YES];
[viewController setToolbarItems:self.toolbarItems];
}
Otherwise the new view controller will have no toolbar items and the toolbar will be blank.
Edit
I created a navigation controller with a root view controller that has a toolbar with a UISegmented control. I pushed a new view controller onto the navigation stack via a UIActionSheet delegate method and then popped it back. The toolbar was exactly how it should be on the root view controller (the segmented control faded back in as expected). You must be doing something more complicated with your controller with regards to setting the toolbar items that is causing them to disappear. Without seeing your viewController's source methods it's hard to tell what the problem is. Make sure that you are not setting your toolbar items to nil or resetting them with an empty array somehow.
Related
I have a UIViewController on the More... tab. In viewDidLoad, I set toolbarHidden to NO, and the toolbar appears. However, if I select another tab from More..., then when I return to my original UIViewController, the toolbar is hidden (toolbarHidden is YES). I've checked to be sure it's the same view controller object.
My workaround is to set toolBarHidden to NO in viewWillAppear.
Is this documented behavior that I'm missing or is it a bug?
UPDATE
Here is some fairly trivial sample code. It turns on the toolbar in viewDidLoad and offers a button to toggle the toolbar on and off.
// Test_VC.m
#import "Test_VC.h"
#implementation Test_VC
- (void)viewDidLoad {
[super viewDidLoad];
// for testing to turn the toolbar on and off
UIBarButtonItem *sampleButton = [[UIBarButtonItem alloc]
initWithTitle:#"Toggle TB"
style:UIBarButtonItemStylePlain
target:self action:#selector(toggleToolbar:)];
self.navigationItem.rightBarButtonItem = sampleButton;
// the toolbar should re-appear whenver this view controller is selected
self.navigationController.toolbarHidden = NO;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// if on More..., this line will keep toolbar visible
//[self.navigationController setToolbarHidden:NO animated:NO];
}
- (void)toggleToolbar:(UIBarButtonItem *)sender
{
[self.navigationController setToolbarHidden:!self.navigationController.toolbarHidden animated:YES];
}
#end
To test:
Create a project with numerous tabs, each of which is an instance of this view controller, Test_VC. Have enough tabs so that at least two of these controllers are on the More tab.
Run the app.
Go to the More tab.
Select a "Test_VC" on More (I refer to this as "Test_1"). Notice that the toolbar appears.
Select another Test_VC from More. (I refer to this as "Test_2"). Notice that the toolbar also appears.
Touch "Toggle TB". Notice that the toolbar goes away on Test_2.
Touch More.
Reselect the first Test VC ("Test_1"). Notice that the toolbar is no longer there.
Repeat these tests using Main tab view controllers. Notice that there is no interactions with any others.
In step 4, the toolbar for Test_1 was present. In step 6, the Test_2 toolbar is removed. However, in step 8, the Test_1 toolbar is gone, too, but no change was made to the Test_1 VC.
This demo turns the toolbar on and off via the Toggle TB button. In my app, some of my view controllers simply hide the toolbar in viewDidLoad and some don't. This demo code could be modified to make two view controller versions: some that show the toolbar in viewDidLoad and some that hide the toolbar in viewDidLoad (no need for the Toggle button).
If these view controllers are main tabs (step 9), then each operates independently of the others, as expected.
What I have found: Toolbar visibility on all view controllers launched from More is set by the most recent More view controller that executes viewDidLoad. Thus, viewDidLoad is strange for More tab view controllers.
It's as if there's only one toolbar managed by More. I do not understand this behavior.
I have an actionsheet that is created from an UIBarButtonItem.
The bar button item programmaticly added when a view controller that is in a tab bar controller that is in a nav controller is show
- navigation controller
-tab bar controller
- view controller (bar button item created in viewdidload and shown in viewwillappear)
The actionsheet loads and displays correctly, the problem is to do with how it is dismissed. It dismisses correctly if i tap anywhere within the view but not when I tap on the navigation bar and this means that i can tap the UIBarButtonItem multiple times and actionsheets are created and overlayed.
I know I could do some logic to see if the actionsheet is being displayed and not recreate it and I could also add some logic to viewwilldisappear to manually remove the actionsheet but was wondering why it isn't working out of the box
I had the same problem with a UIActionSheet being shown from a UIBarButtonItem where the sheet wasn't being dismissed when tapping the back button in UINavigationController.
I implemented the solution described by #updog
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
if ([actionSheet isVisible]) {
[actionSheet dismissWithClickedButtonIndex:0 animated:YES];
}
}
The delegate isn't called when dismissWithClickedButtonIndex is executed, so the index doesn't matter.
I ended up adding some logic to the viewWillDisappear function to hide the actionsheet if it is showing.
I also had to add some other code to the bar button click action so that if tapped once the actionsheet is displayed, another actionsheet isn't overlayed.
Currently using Xcode 4.2 and I have two view controllers (1 and 2). I have a number of textfields in viewcontroller1 that need to be filled in before the user is able to click the "Next" button which then goes to viewcontroller2. I have got alertdialogs that popup if the user hasn't filled in all the textfields.
I have used the storyboard to segue the button click which works fine, except if the textfields are empty, my alertdialog pops up but the view controller still changes to number 2.
How do i make it so that only if my if/else statements are met, does the next button go to the next view controller.
I am using a navigation controller to control the view controllers.
I tried to put the following code into the if/else statement but it didn't work:
UIViewController *secondViewController = [[SecondViewControllerClass alloc] initWithNibName:#"<name of xib>" bundle:nil];
[self presentModalViewController:secondViewController animated:YES];
Now there was a few things I was unsure about when trying to find out how to use this method. Do i need to import the SecondViewController.m at the top of the firstviewcontroller.m?
NSString has a helpful property called length, which will return nil if a textfield contains no text. If you need to check, call:
if (!myTextField.text.length) {
//no text in the box
}
Simple enough, since you have already set up the alert boxes to pop up if something is wrong with the textbox input, make sure the alert box show/init code is before the code that changes the view and do this:
if(//something is wrong with the textbox input)
{
UIAlertView* alert = [[UIAlertView alloc] initWith...
[alert show];
//Add a return! If the method is not IBAction or void, just return nil
return;
}
Voila!
What does this error indicate:
"Popovers cannot be presented from a view which does not have a window."
the thing that saved my life:
if (self.view.window != nil)
[popoverController presentPopoverFromRect:CGRectMake(44, yCoord, 111, 111) inView:self.view permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
by adding if condition it doesn´t crash anymore. I don´t really get it because the presentPopoverFromRect function is ALWAYS called. There is no situation where window would be nil but anyway it did the trick.
edit: I have this code in viewDidAppear.
Nevertheless in most cases it's enough to move presentPopoverFromRect to viewDidAppear or didMoveToWindow but in my case for some reason the if condition was necessary.
the view you're adding the popover to has to already have been added to a window with the "addSubview:" method.
Try waiting until
- (void) didMoveToWindow
is called for the view and then load the popover
I got this problem.
I had a UITabBarController as the detail view, and I set the barButtonItem as the leftBarButtonItem on all three navigation controllers in the tab bar.
vcChart.navigationItem.leftBarButtonItem = barButtonItem;
vcAnalysis.navigationItem.leftBarButtonItem = barButtonItem;
vcTechnicals.navigationItem.leftBarButtonItem = barButtonItem;
Turns out only the last one added is valid, and the previous two would throw the exception when tapped on.
To fix it, I only set the leftBarButtonItem for the visible view controller, and just switched the barButtonItem to the visible view controller every time the user switched tabs.
Just encountered this issue. Turned out that the inView: parameter was using an IBOutlet that wasn't connected in IB. Thus, an attempt was made to launch the popover in nil. That doesn't work.
So, make sure you are using a valid view.
There are many ways to get to this error. Basically you need to wait to call the presentPopover command until your calling view is added to a window. I did it this way.
- (void)viewDidAppear:(BOOL)animated
{
[self methodThatDisplaysPopOver];
}
My presentPopoverFromRect call is inside my methodThatDisplaysPopOver function.
You could protect every presentPopover call like MobiMaciek suggests with this.
if (self.view.window != nil)
[popoverController presentPopoverFromRect:CGRectMake(10, 10, 100, 100) inView:self.view permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
However, I think it would be better to understand when self.view.window gets assigned and make sure that you present you popover after the view has a window.
I received the same error message when assigning the same UIBarButtonItem to multiple navigation items as did Lewis. My example was slightly more complicated as I was using a UISplitViewController.
In my RootViewController I have an array of arrays to accomplish multiple sections within my table. Each time that the user clicks a row in the table, a new "detail" view controller is placed in the right pane of my splitViewController. Prior to setting the leftBarButtonItem = nil, I would receive a segfault after 3-4 clicks of the "Menu" button with the same error as a111. I updated my code to actually retrieve the previous detail view controller and set the leftBarButtonItem item to nil.
allData is my NSMutableArray that contains several other NSMutableArrays as objects.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Retrieve the new detail view controller
UIViewController *detailViewController = [[self.allData objectAtIndex:indexPath.section] objectAtIndex:indexPath.row];
// Add the detail view controller to a navigation controller and set the bar style
UINavigationController *detailNavigationController = [[UINavigationController alloc] initWithRootViewController:detailViewController];
detailNavigationController.navigationBar.barStyle = [[NSUserDefaults standardUserDefaults] integerForKey:#"UIBarStyle"];
// Retrieve previous detail view controller and remove the leftBarButtonItem
UINavigationController *previousDetailNavigationController = [splitViewController.viewControllers objectAtIndex:1];
UIViewController *previousDetailViewController = [[previousDetailNavigationController viewControllers] lastObject];
previousDetailViewController.navigationItem.leftBarButtonItem = nil;
// Update the split view controller's view controllers array.
NSArray *viewControllers = [[NSArray alloc] initWithObjects:self.navigationController, detailNavigationController, nil];
splitViewController.viewControllers = viewControllers;
[detailNavigationController release];
[viewControllers release];
// Dismiss the popover if it's present.
if (popoverController != nil) {
[popoverController dismissPopoverAnimated:YES];
}
// This sets the left bar to nil when in landscape and equal to "Menu" when in portrait.
// We need to remove rootPopoverButtonItem from the previous viewController...
detailViewController.navigationItem.leftBarButtonItem = rootPopoverButtonItem;
}
The error message was slightly deceiving at first but the answers above helped me out. I wonder why I could click the "Menu" button up to 3-4 different times before the segfault... I'll investigate further.
This error also occurred when the inView: Parameter is incorrect - to test try self.view
yes, you are right but still we can add subview from parent class in it. so it can be represented from a view which have a window:
[popoverController.contentViewController.view addSubview:mySubView];
I had the same error message as the OP, in a very similar situation to that reported by TPoschel, except I had a split view controller with an embedded tab bar controller in the detail pane, and a navigation controller within this. The bar button item is added as the navigation bar leftBarButtonItem.
Only on iOS5.0 (not 5.1) does it seem to require you invalidate the bar button item on the tab bar you are leaving by setting it to nil. Before then adding the bar button to the navigation bar on the tab you are going to.
If I don't do that, from debugging my own code, the window property of the bar button item stays set to nil, and causes the exception, on returning to a screen you'd previously been to. I'm guessing as a side effect of setting the leftBarButtonItem in the navigation item, it goes off and sets the frame. But it doesn't seem to bother unless the button is different from what is currently set there. Hence, the need to set it to nil when leaving a tab, even though it is technically the same button that's being passed around.
I would upvote TPoschel's answer, except SO won't let me.
I had a problem like this. Received this message when clicking a customized UIBarButton item that invoked a selector method with did performSeque.
The problem was my segue was still attached to the UIBarButton item. It should have been attached to the main view of of the view controller. Changed this and worked fine.
P.S., all this got started because I wanted to add and "info" button to my UIToolBar. This isn't one in the system provided list and should be.
There will be a view from which you asks to display your popover.The reason for this error is because you didn't made this view as a subview of the window.
[self.view addSubview:displayPopOverVC];
where displayPopOverVC is the view controller from which the popOver appears
i had the same problem, after adding PresentPopOver in viewDidAppear this was solved
- (void) viewDidAppear:(BOOL)animated{
CGRect popoverRect = screenBounds;
popoverRect.size.width = MIN(popoverRect.size.width,0) ;
popoverRect.origin.x = screenBounds.origin.x;
[popoverController
presentPopoverFromRect:popoverRect
inView:self.view
permittedArrowDirections:UIPopoverArrowDirectionAny
animated:YES];
}
this was happening as inView:self.view should be called after viewDidLoad as suggested by #hey68You and MobiMaciek..
I replaced
[actionSheet showFromBarButtonItem:self.navigationController.navigationItem.leftBarButtonItem animated:YES];
with
[actionSheet showInView:self.view];
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