tvOS: Focus not moving correctly

2020-03-30 15:29发布

问题:

I have a UIView with two buttons on it. In the MyView class I have this code:

-(BOOL) canBecomeFocused {
    return YES;
}

-(NSArray<id<UIFocusEnvironment>> *)preferredFocusEnvironments {
    return @[_editButton, _addButton];
}

-(IBAction) editTapped:(id) sender {
    BOOL editing = !tableViewController.editing;
    [_editButton setTitle:editing ? @"Done" : @"Edit" forState:UIControlStateNormal];
    _addButton.hidden = !editing;
    [tableViewController setEditing:editing animated:YES];

}

The basic idea is that the user can move the focus to the edit button, which can then make the Add button appear.

The problem started because every time I tapped the edit button, focus would shift to the table view. I would actually like it to move to the Add button. I also want it so that when editing it deactivated, the edit button keeps the focus. but again it's shifting down to the table view.

So I tried the above code. This works in that focus can move to the view and on to the button. But once it's there, I cannot get it to move anywhere else.

Everything I've read says just override preferredFocusEnvironments but so far I've not been able to get this to work. Focus keeps going to a button then refusing to move anywhere else.

Any ideas?

回答1:

If anybody is facing this issue, Just check if you are getting the following debug message printed in the console.

WARNING: Calling updateFocusIfNeeded while a focus update is in progress. This call will be ignored.

I had the following code :

// MARK: - Focus Environment

var viewToBeFocused: UIView?

func updateFocus() {
    setNeedsFocusUpdate()
    updateFocusIfNeeded()
}

override var preferredFocusEnvironments: [UIFocusEnvironment] {
    if let viewToBeFocused = self.viewToBeFocused {
        self.viewToBeFocused = nil
        return [viewToBeFocused]
    }
    return super.preferredFocusEnvironments
}

I was calling the updateFocus() method multiple times while viewToBeFocused was either nil or some other view. Debugging the focus issues mainly between transition is really difficult. You should have patience.

Important to note: This depends on your use case, but if you want to update the focus right after a viewcontroller transition (backward navigation), You might have to set the following in viewDidLoad:

restoresFocusAfterTransition = false // default is true

If this is true, the view controller will have the tendancy to focus the last focused view even if we force the focus update by calling updateFocusIfNeeded(). In this case , since a focus update is already in process, you will get the warning as mentioned before at the top of this answer.

Debug focus issue

Use the following link to debug the focus issues: https://developer.apple.com/documentation/uikit/focus_interactions/debugging_focus_issues_in_your_app

Enable the focus debugger first under Edit scheme > Arguments passed on launch:

-UIFocusLoggingEnabled YES

This will log all the attempts made by the focus engine to update the focus. This is really helpful.



回答2:

You can override the preferredFocusEnviromnets with the following logic:

-(NSArray<id<UIFocusEnvironment>> *)preferredFocusEnvironments {
    if (condition) {
        return @[_editButton];
    }
    else {
        return @[_addButton];
    }
}

After setting it, you can call

[_myView setNeedsFocusUpdate];
[_myView updateFocusIfNeeded];

The condition could be BOOL condition = tableViewController.editing; or sg like that.

If that now works, you can call it with a delay (0.1 sec or so).



标签: focus tvos