So I'm writing my first tvOS App (Objective C) and am having some fun with the "Focus Engine". My app is a 2 page app with a Tab Bar controller, on the main page I have a few UIButtons. On app startup if I hide the tab bar, the buttons look like I am wanting them to with them all deselected, when I swipe down one of the UIButtons obviously gets focus, and I can swipe between my various buttons, and after a specified amount of inactivity time I want it to go back to them all being unfocussed.
I start (and reset) a NSTimer when each UIButton gets focus and my intention is to remove the UIButton focus after say 10 seconds (there is a good reason for this, and it makes sense in my app / ui).
I've tried issuing a "UIButton resignFirstResponder" I've also tried to move focus back to the hidden TabBar, I even tried "preferredFocusEnvironments" but I cannot get the button highlight to come away. I also tried cycling though the buttons setting them all to "userInteractionEnabled = NO" then back again but the button retains focus. I have log lines showing the timer starting and it triggering my un-focus method when it expires, but no matter what I put in there I can't seem to get the focus to disappear.
Any ideas on how to drop the focus from a UIButton, I think part of the problem is I don't want to move it to somewhere else. I want to remove all button focus which I guess is an unusual thing to do.
Thanks in advance.
Plasma
I discovered a way to do it, its a bit primitive but it works and achieves the desired effect.
When the idle timer expires I create a UIButton (Custom Type) at 0,0 that is 1px high and the width of the screen. I then tell the view it needs a focus update, and to update the focus. This takes the focus from any of the main buttons and up to my 1px high button along the top of the screen.
[focusButton removeFromSuperview];
CGRect frame = CGRectMake(0,0,(self.view.frame.size.width),1);
focusButton = [UIButton buttonWithType:UIButtonTypeCustom];
focusButton.frame = frame;
focusButton.tag = 99;
[self.view addSubview:focusButton];
[self.view setNeedsFocusUpdate];
[self.view updateFocusIfNeeded];
I then use 'didUpdateFocusInContext' to know when my 1px button has been given focus and set the button to disabled.
if(context.nextFocusedView.tag == 99){
NSLog(#"Focus Button Has Focus");
focusButton.enabled = NO;
}
This leaves the focus on that button which allows someone to swipe down to get to the main buttons, or up to get to the Tab Bar, once they swipe off it the 1px button is no longer selectable because is not enabled! I had to use Custom button type because system button type showed a white line over the top of the screen and tainted my labels.
Plasma
Related
I have a menu in my app, with clickable buttons using CCMenuItemImage. When you press one of the buttons, for example buy button it spawns anther image on top of everything, a confirmation screen(do you really want to buy this item). This screen is placed on z:100 just to be sure it is on top of everything.
The problem is the buttons on the menu below(buy, back, next(all CCMenuItemImage)) are still clickable. I had the idea to just use [button setIsEnabled:NO]; but this doesn't seem to work unless the CCMenuItemImage has a disabledImage set, but some of my buttons (next, previous) use the disabledImage and it looks silly to make the buttons disabled when this confirmation screens shows up.
Is there a way to just disable all the touches to the buttons below and only allow the confirm screen to take touches?
Set the enabled property of the CCMenu to NO. If that doesn't work without disabled images simply set the CCMenu visible property to NO. This also disables the menu reacting to touches.
I've encountered a problem where my button should remain "pressed down" while it shows popover called from it. Popover is selector for some filter and filter is shown on button itself. When I tap on it and it shows popover it becomes deselected no matter what.
I think I have to redefine it's behavior on touch event and make it respond not to standart touch up inside. Then I wondered what are other events responsible for? But I couldn't find events list in iOS library and in StackOverflow are only questions about incorrect behavior of touch up inside or touch down.
So what's the difference betweeen touch events?
touch cancel - when you touch button but move your finger away and
it remains deselected?
touch down - right on tap.
touch down repeat ??
touch drag enter ??
touch drag exit ??
touch drag inside ??
touch drag outside ??
touch up inside - when you tap and release button remaining in it's
bounds . It changes UIButtons state to Normal.
touch up outside - when you tap and release button leaving it's
bounds ?
other IBActions are not sent by UIButton, right?
Also how those events change UIButton's appearance? Like highlighted or selected?
I'd appreciate a link on good article about IBActions, because I couldn't find it.
From Apple's doc for UIControlEvents:
UIControlEventTouchCancel
A system event canceling the current touches for the control.
UIControlEventTouchDown
A touch-down event in the control.
UIControlEventTouchDownRepeat
A repeated touch-down event in the control; for this event the value of the UITouch tapCount method is greater than one.
UIControlEventTouchDragEnter
An event where a finger is dragged into the bounds of the control.
UIControlEventTouchDragExit
An event where a finger is dragged from within a control to outside its bounds.
UIControlEventTouchDragInside
An event where a finger is dragged inside the bounds of the control.
UIControlEventTouchDragOutside
An event where a finger is dragged just outside the bounds of the control.
UIControlEventTouchUpInside
A touch-up event in the control where the finger is inside the bounds of the control.
UIControlEventTouchUpOutside
A touch-up event in the control where the finger is outside the bounds of the control.
Listed in, what I would consider, order of common use/likelihood of occurrence for a normal button:
UIControlEventTouchDown: The user tapped the button. This fires on the finger/stylus making contact.
UIControlEventTouchUpInside: The user tapped the button. This fires on the finger/stylus contact pulled back away from the screen.
Useful for sliders and drag events like moving a component around. The below are in order of occurrence:
UIControlEventTouchDragInside: Triggered as the finger drags into the button area.
UIControlEventTouchDragExit: Triggered during a drag motion. It is called only once, as the users finger/stylus leaves the bounds of the button.
UIControlEventTouchDragOutside: Triggered during a drag motion, after 'UIControlEventTouchDragExit', and is called continuously, as long as the original touch continues.
UIControlEventTouchUpOutside: This is simply the finger/stylus being lifted BUT only if the finger/stylus is no longer within the bounds of the button. The important thing (and probably obviously) to call out is that the touch had to have been within the button at some point to associate this event with the button.
Note: My understanding is that the above can be helpful for:
Sliders: as you might expect the touch may have been intentional but because of the quick swipe action, their finger movement may be sloppy and lift up outside of the slider area.
Moving components around, as when you push things around a screen you want the movement to happen when the finger/stylus touches the border of the component/object.
Other events:
UIControlEventTouchCancel: Something out of the user's control is cancelling their touch action. Think of this as something "going wrong" on the phone side of things.
UIControlEventTouchDownRepeat: Want to detect when your user is mad and tapping a button furiously? Want to detect if they're still in Windows mode and are trying to "double click"? Or maybe you designed a button to do something different if they tap twice. This event helps with all of those!
References:
SO 1: Dif between UIControlEventTouchDragOutside and UIControlEventTouchDragExit
SO 2: What is UIControlEventTouchCancel?
I created custom navigation buttons like this:
UIButton * button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setImage:[UIImage imageNamed:#"some.png"] forState:UIControlStateNormal];
....
[[current navigationItem] setLeftBarButtonItem:[[UIBarButtonItem alloc] initWithCustomView:button]];
Where current is UIViewController * type.
All works fine and button created, but it's clickable area outside the button, very close to the middle of the navigation bar. Is it possible to limit clickable area?
I believe thats a "feature" of iOS. THe Navigation Buttons on left and right are smaller than the minimum touch area allowed in iOS. As a result the actual hit zone is much larger than the physical NavigationButton. Including just under the bar, and like you're noticing to the left and right of the button. Its to allow quick touches without having "look" where you're touching. Its one of the key reasons iPhones are more natural to use than most android phones in the early days.
My best guess is that the button is set to center the image and not scale it, so the frame of the button is way too big.
button.frame=CGRectMake(x,y,w,h)
Set the frame to what you want the clickable area to be.
I have initially thought about subclassing the UIBarButtonItem and override -touchInside:.
This does not work though, since UIBarButtonItem is not a subclass of UIView.
What you are trying to achieve is therefore not possible without overriding some private API.
I have a scrollview in my app, in the scrollview there is a lot of buttons without any space between them... When I run the app, I can't scroll because I "of course" have to touch a button first, and ehen I try to scroll, the button that I touched gets highlighted, and when I release.. The button is pressed! So I can't reach the buttons that is further down in the scrollview!
All button has the setting "Touch up inside"..
I guess it is kinda easy to fix, but I don't know how! :P
/Noob
Setting the property canCancelContentTouches on the UIScrollView to YES should allow it to cancel the touch event already sent to the button once it detects a scroll. That should fix your problem.
You can do what ksoderstrom said or you can auto scroll using this method for your scrolview
[self.scrollView scrollRectToVisible:textField.frame animated:YES];
textField can be a UIButton as well. This method will just move the scrollView to whatever component you specify.
Hoep it helps.
I had the same problem and i found out that it's really hard to test it in the simulator. When the code run on the actual device, the scroll view was working as it was supposed to...
I've seen a couple of apps that show a transparent view on top of the current ui while the keyboard is present and if clicked it hides the keyboard. I looked around the web and couldnt find a solution for this problem.
Simply add a UIButton, custom type, the size of your screen and add it to your view when your text field (or other entry) takes focus. Make sure your edit view is brought to the front of its superview at the point you add the button (to ensure the edit view still responds to touch).
Add a target to the button which dismisses the keyboard ([myTextfield resignFirstResponder]) and removes the button.
Also make sure to remove the button when the textField dismisses normally.