14

I am implementing custom code to handle a click on the Menu button on the Siri Remote. How can I force focus to change to my custom menu when pressing the menu button?

  • This question addresses a common tvOS focus issue [just go through]: https://stackoverflow.com/questions/40837449/tvos-focus-not-moving-correctly/52251007#52251007 – abhimuralidharan Sep 10 '18 at 10:43

6 Answers6

23

For ios 10 you should use preferredFocusEnvironments instead of preferredFocusedView .

In below example if you want to focus on button then see below code.

@IBOutlet weak var button: UIButton!

override var preferredFocusEnvironments: [UIFocusEnvironment] {
    return [button]
}

override func viewDidLoad() {
    super.viewDidLoad()

    setNeedsFocusUpdate()
    updateFocusIfNeeded()
}
Nike Kov
  • 12,630
  • 8
  • 75
  • 122
vikas prajapati
  • 1,868
  • 2
  • 18
  • 26
19

Finally figured it out myself. You have to override the preferredFocusedView property of your UIView or UIViewController.

In Swift it works like this:

func myClickHandler() {
    someCondition = true
    self.setNeedsFocusUpdate()
    self.updateFocusIfNeeded()
    someCondition = false
}

override weak var preferredFocusedView: UIView? {
    if someCondition {
        return theViewYouWant
    } else {
        return defaultView
    }
}

I can't quite remember how to override getters in Objective-C so if someone want to post that I'll edit the answer.

Fernando Echeverria
  • 7,706
  • 4
  • 17
  • 13
Slayter
  • 1,172
  • 1
  • 13
  • 26
  • Thank you. I was considering doing it like this, but it seems soooooo messy to put all these "someConditions" all over the place. Would be so much easier if you could just setPreferredFocusedView... – Simen Øian Gjermundsen Sep 24 '15 at 21:14
  • But, wait. How does this work when I want to change the focus to another viewcontroller? – Simen Øian Gjermundsen Sep 24 '15 at 21:16
  • 2
    I agree. Hopefully they'll add it. Also to avoid all the `someCondition`s, I added a `viewToFocus` `UIView` property to my viewController. Then in the getter, I check if that view is not nil and return it. Otherwise return the default view. – Slayter Sep 24 '15 at 22:27
  • 1
    In regards to your viewController question, if the viewControllers view is apart of the parent viewController's hierarchy (I assume this is what you mean) then return the view of the viewController in your parent viewController's `preferredFocusedView` getter. – Slayter Sep 24 '15 at 22:28
16

Here is another implementation based on Slayters answer above. Its slightly more elegant I think than using the conditional booleans.

Put this in your viewcontroller

var viewToFocus: UIView? = nil {
    didSet {
        if viewToFocus != nil {
            self.setNeedsFocusUpdate();
            self.updateFocusIfNeeded();
        }
    }
}

override weak var preferredFocusedView: UIView? {
    if viewToFocus != nil {
        return viewToFocus;
    } else {
        return super.preferredFocusedView;
    }
}

Then to use it in your code

viewToFocus = myUIView;
Brandon Gill
  • 161
  • 1
  • 4
6

here is the objective C

- (UIView *)preferredFocusedView
{
    if (someCondition) {
      // this is if your menu is a tableview
        NSIndexPath *ip = [NSIndexPath indexPathForRow:2 inSection:0];
        UITableViewCell * cell = [self.categoryTableView cellForRowAtIndexPath:ip];

        return cell;
    }

    return self.view.preferredFocusedView;

}

in your viewDidLoad or view did appear do something like this:

    UIFocusGuide *focusGuide = [[UIFocusGuide alloc]init];
    focusGuide.preferredFocusedView = [self preferredFocusedView];
    [self.view addLayoutGuide:focusGuide];

if you want to do it when it first launches

Jenel Ejercito Myers
  • 2,553
  • 2
  • 16
  • 24
  • I am getting nill for the cell and i am using collectionview instead of tableview! Any idea why it is nil? – IamDev Nov 25 '16 at 08:50
1

Here's a nice little Swift 2 copy / paste snippet:

var myPreferredFocusedView: UIView?
override var preferredFocusedView: UIView? {
    return myPreferredFocusedView
}
func updateFocus(to view: UIView) {
    myPreferredFocusedView = napDoneView
    setNeedsFocusUpdate()
    updateFocusIfNeeded()
}

Use it like this:

updateFocus(to: someAwesomeView)
Wiingaard
  • 4,150
  • 4
  • 35
  • 67
0

@elu5ion 's answer, but in objective-c first declare:

@property (nonatomic) UIView *preferredView;

Set these methods:

-(void)setPreferredView:(UIView *)preferredView{
      if (preferredView != nil) {
         _preferredView = nil;
         UIFocusGuide *focusGuide = [[UIFocusGuide alloc]init];
         [self.view addLayoutGuide:focusGuide];
         focusGuide.preferredFocusedView = [self preferredFocusedView];
         [self setNeedsFocusUpdate];
         [self updateFocusIfNeeded];
    }
    _preferredView = preferredView;
 }


 - (UIView *)preferredFocusedView {
     if (_preferredView) {
          return _preferredView;
     }
     return self.view.preferredFocusedView;
}
Jenel Ejercito Myers
  • 2,553
  • 2
  • 16
  • 24