I have a UITableView with an editButtonItem in the navigation bar. I wanted to have a tap sound play whenever the user taps the editButtonItem. Right now, I'm using the following method to play the tap sound when edit button is tapped
- (void)setEditing:(BOOL)editing animated:(BOOL)animated {
//Code to play the tap sound file
[super setEditing:editing animated:animated];}
But the problem I have is that the tap sound also plays when user swipes a tableviewcell & the delete button shows up, which is not something I want. So, my question is, is there a better way to detect when the editButtonItem is tapped?
The below code will play a sound ONLY when the edit button is tapped. When you tap Done it will not play a sound. Also, when you swipe a cell, the sound should not play.
- (void)willTransitionToState:(UITableViewCellStateMask)state
{
if (state == UITableViewCellStateShowingDeleteConfirmationMask) {
swipedToDelete = YES; // BOOL ivar
}
}
- (void)setEditing:(BOOL)editing animated:(BOOL)animated
{
[super setEditing:editing animated:animated];
if (editing && !swipedToDelete)
{
// Play sound
}
if (swipedToDelete) {
swipedToDelete = NO;
}
}
Related
I've just had an Apple TV app rejected because of
'In addition, the Menu button on the Siri Remote does not behave as expected in your app.
Specifically, when the user launches the app and taps the Menu button on the Siri Remote, the app does not exit to the Apple TV Home screen.'
I'm looking this up and from what I can tell this should be the automatic behaviour of pressing the menu button when on the initial view controller. However I have a navigation controller with a root view controller, instantiated automatically via the storyboard with no methods overridden and nothing happens when I press the menu button on this view controller.
Can someone tell me if I'm missing something or if there's a way of implementing this manually?
I'm thinking I could just intercept the menu button press and call exit(0), but that doesn't seem like a graceful way of exiting.
I just had an app rejected for this reason too. In my case the problem was overriding the press<Phase>d:withEvent group of methods without calling the super implementation.
So I changed this:
-(void)pressesBegan:(NSSet*)presses withEvent:(UIPressesEvent *)event {
// my code
}
To this:
-(BOOL)ignoreMenu:(NSSet*)presses {
return ((UIPress *)[presses anyObject]).type == UIPressTypeMenu;
}
-(void)pressesBegan:(NSSet*)presses withEvent:(UIPressesEvent *)event {
if ([self ignoreMenu:presses]) return [super pressesBegan:presses withEvent:event];
// my code
}
And the menu button works again. What's confusing is that the Home button continues to work whether you call the super or not.
My complete working code as of tvOS 9.1 (compiled under Objective-C++)
bool AppRespondedToBack = false;
-(void)pressesBegan:(NSSet*)presses withEvent:(UIPressesEvent *)event
{
UIPress *UP = (UIPress *)presses.anyObject;
if ( UP && UP.type == UIPressTypeMenu )
{
//OnBack should be where you handle the back operation in your app
AppRespondedToBack = OnBack();
if ( !AppRespondedToBack )
// Let AppleTV return to the home screen
[super pressesBegan:presses withEvent:event];
}
else
[super pressesBegan:presses withEvent:event];
}
-(void)pressesEnded:(NSSet*)presses withEvent:(UIPressesEvent *)event
{
UIPress *UP = (UIPress *)presses.anyObject;
if ( UP && UP.type == UIPressTypeMenu )
{
if ( !AppRespondedToBack )
// Let AppleTV return to the home screen
[super pressesEnded:presses withEvent:event];
}
else
[super pressesEnded:presses withEvent:event];
}
In a more generic way, the Menu button should take you to the home screen only in some conditions, first one would be when you start the app and click the Menu button, and later on in your app if you are at the 'root view' of your app.
If you display something on the screen, like a popover/dialog which is not controlled by the standard sdk but manualyl by yourself (ie adding a UIView as popover), then the Menu button should just act as a 'cancel/go back' like it would do on the navigation controller.
-(void)pressesBegan/Ended:(NSSet*)presses withEvent:(UIPressesEvent *)event {
if( presses.anyObject.type == UIPressTypeMenu) {
if ( !somePopoverDisplayed) {
// Let the sdk do its thing with the menu button
[super pressesBegan:presses withEvent:event];
} else {
// otherwise handle the menu button yourself ...
}
return;
}
// handle other buttons
}
Here is the snipped of code that ended up working for me:
-(void)pressesEnded:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event {
if( presses.anyObject.type == UIPressTypeMenu) {
if (scene.view.paused == YES) {
// This will return to the Apple TV Menu
} else {
// This allows your code to run without exiting the app
[self pauseScene];
[super pressesBegan:presses withEvent:event];
}
return;
}
}
So I ended up begrudgingly calling exit(0) like so
- (void)pressesBegan:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event
{
[super pressesBegan:presses withEvent:event];
if (presses.anyObject.type == UIPressTypeMenu)
{
exit(0);
}
}
It's not quite as neat as when it works automatically; you end up with a blurry white view for about half a second instead of the more graceful fade out animation. It does however work and I can confirm that I made it through Apple's review process doing it this way.
What sorted it out for me was just removing the gesture recogniser from your view (for your Menu button) when you don't need it anymore.
Then when, you have a situation where you want the Menu button to for example, go back to a previous screen, then just add your gesture recogniser again.
That way the Menu button works the way it should, without you having to call exit() or force your app to quit some other way.
I have implemented SidebarDemo project from Appcode and then modified Storyboard with Login screen, now when I start my application Login Screen come which is correct and I dont want Pan Gesture on Login screen and I am trying to remove it from code below
- (void)viewDidLoad
{
[super viewDidLoad];
[self.navigationController.view removeGestureRecognizer:self.revealViewController.panGestureRecognizer];
}
- (void) viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
for (UIGestureRecognizer *recognizer in self.navigationController.view.gestureRecognizers) {
[self.navigationController.view removeGestureRecognizer:recognizer];
}
self.revealViewController.panGestureRecognizer.cancelsTouchesInView = NO;
// NSArray* gestureRecognizers = [self.navigationController.navigationBar gestureRecognizers];
// for (UIGestureRecognizer *gestureRecognizer in gestureRecognizers) {
// if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) {
// gestureRecognizer.enabled = YES;
//
// break;
// }
// }
//[self.revealViewController.panGestureRecognizer removeTarget:self action:#selector(revealToggle:)];
}
But Pan Gesture is still swiping on Login but when I go to internal screen and comes on Login Screen so it get remove, but why isnt it removing from the first time of application start
My Storyboard Image as below
As I understood, your login screen shouldn't be the front view of SWRevealViewController, cause you don't need a sidebar in it. Create a modal segue from your login view controller to the reveal view controller and perform it when user has logged in successfully. Delete the segue from reveal view controller to login's navigation controller, but create one from reveal to survey choice (don't forget to set it's identifier to sw_front and embed survey choice controller in navigation controller). Create segues from sidebar's logout button to login's navigation view controller and perform it when user wants to logout.
To be more clear, I add photo of my own app, that has similar thing.
http://i.stack.imgur.com/f3nWe.png
I have an app with a camera. The user presses a button and the view changes to the camera view.
In the cameraView, I put the pickerControl in the viewDidLoad.
When the view appears, the camera opens and allows the user to take a picture. When done, the user can choose to keep the photo and if he does, the camera view dismisses and in that moment, I can see the picture I've taken in the image viws I created but the camera keeps opening up.
I think it's because I have my pickerControl in my viewDidLoad and every time the camera dismisses, because of that, it repeatedly keeps opening the camera. Is there any way around this?
Here is my cameraViewController that loads when the user selects the camera option
- (void)viewDidLoad
{
[super viewDidLoad];
}
// When the view appears, the camera will turn on
-(void)viewDidAppear:(BOOL)animated
{
// Initialize the picker control
UIImagePickerController *pickerControl = [[UIImagePickerController alloc] init];
// If all's good, start up the camera
if ((pickerControl != nil)&&(picHolder == nil))
{
pickerControl.sourceType = UIImagePickerControllerSourceTypeCamera;
pickerControl.delegate = self;
pickerControl.allowsEditing = true;
}
// Camera turns on
[self presentViewController:pickerControl animated:true completion:nil];
}
Im not sure how to prevent the view from loading every time when that is what opens the camera in the first place.
Thank You
Add a BOOL ivar to your class. Some pseudocode below
YourController {
BOOL didShow;
}
-(void)viewDidAppear:(BOOL)animated {
if (!didShow) {
// present the UIImagePickerController
}
didShow = YES;
}
Usually after the viewController is pushed, I want to do certain things. In add phone feature, for example, I would open edit business and set the focus to the phone field.
If after viewController is pushed users press back button too quickly the app crash.
What's the standard way to do so?
This is the code:
+(BGBusinessEditViewController *) pushNewEditViewControllerWithBizandReturnValue: (Business *)biz withNavController :(UINavigationController *) nav andSelectPhone:(BOOL) selectPhoneAfterward
{
BGBusinessEditViewController * editBusiness = [[BGBusinessEditViewController alloc]init];
//[editBusiness view];//load the stuff first
[nav vPushViewController:editBusiness animated:YES andPerformBlock:^{
if (biz) {
editBusiness.biz=biz; //viewDidload must be called first before setting bizs
}
if (selectPhoneAfterward)
{
[editBusiness selectPhone];
}
}];
return editBusiness;
}
-(void) selectPhone
{
NSIndexPath * ipth =[NSIndexPath indexPathForItem:BGBusinessEditTextPhoneNumber inSection:0];
[self.tableView selectRowAtIndexPath: ipth animated:NO scrollPosition:UITableViewScrollPositionTop];
[self tableView:self.tableView didSelectRowAtIndexPath:ipth];
}
Basically I created a category in nav View Controller that will run code only when the navigation controller already reach - (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated;
Well, Hide the back button until viewDidAppear, and then unhide it.
Is there any way to detect a single tap vs. a scrolling gesture on a UIWebView?
I have a UIWebView, that contains rich text that many times, scrolls, if there is a lot of text content. I need to add a new feature that will allow the user to tap the UIWebView to get different content.
The problem is, my solution for this was to place a clear custom button on top of the UIWebView, which handles the tap but kills the scrolling feature. How do the cool kids do this type of thing?
Thanks
I solved this with a gesture recognizer. This eliminates the need for the UIButton overlay altogether.
//Handle taps on the UIWebView
self.singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(**tapDetected:**)];
singleTap.numberOfTapsRequired = 1;
singleTap.delegate = self;
[self.readAboutItView addGestureRecognizer:singleTap];
//Set up the event handler
- (IBAction)**tapDetected:**(UIGestureRecognizer *)sender {
//Do something with the content
[self webViewTouched:self];
}
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{
return YES;
}
-(BOOL) gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{
return YES;
}