Search code examples
objective-cuitableviewstoryboardtvos

Leave tableView on row selection


I am trying to make an TableView inside of a ViewController working as a picker.

Its a simple Table View with o e textlabel.

My Problem is, that i cant leave the tableview on go on to the next textfield.

I have tried it with this code:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{


    [_textfield becomeFirstResponder];

}

but that only open the keyboard and after i make the input i am back in the tableview.

What must i do to leave the tableview when i select a row?

Image from the storyboard. enter image description here


Solution

  • Objective-C

    You need to keep track of and update the preferredFocusView of you UITableViewCell subclass depending on whether the cell has been selected and what the UIFocusHeadingis.

    The first thing you should do is add a property on your UITableViewCell subclass to keep track of the current subview you'd like to have focused. For example:

    @property (nonatomic, strong) UIView *currentPreferredFocusedSubview;
    

    Then in your view controller in your didSelectRowAtIndexPath you should set that to the text field you would like focused and then request the focus engine to update:

    - (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
    {
        TableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
        [cell setSelected:NO animated:YES];
        cell.currentPreferredFocusedSubview = cell.textField;
        [cell setNeedsFocusUpdate];
    }
    

    Now in your UITableViewCell subclass you need to return your preferred focus view and change how the focus engine updates by overriding preferredFocusedView and shouldUpdateFocusInContext:

    - (UIView *)preferredFocusedView
    {
        return self.currentPreferredFocusedSubview;
    }
    
    - (BOOL)shouldUpdateFocusInContext:(UIFocusUpdateContext *)context
    {
        if (self.currentPreferredFocusedSubview == self.textField && context.focusHeading == UIFocusHeadingRight)
        {
            self.currentPreferredFocusedSubview = self.textField2;
        }
        else if (self.currentPreferredFocusedSubview == self.textField2 && context.focusHeading == UIFocusHeadingRight)
        {
            self.currentPreferredFocusedSubview = self.textField3;
        }
        else if (self.currentPreferredFocusedSubview == self.textField3 && context.focusHeading == UIFocusHeadingRight)
        {
            self.currentPreferredFocusedSubview = self.textField3;
        }
        else if (self.currentPreferredFocusedSubview == self.textField3 && context.focusHeading == UIFocusHeadingLeft)
        {
            self.currentPreferredFocusedSubview = self.textField2;
        }
        else if (self.currentPreferredFocusedSubview == self.textField2 && context.focusHeading == UIFocusHeadingLeft)
        {
            self.currentPreferredFocusedSubview = self.textField;
        }
        else if (self.currentPreferredFocusedSubview == self.textField && context.focusHeading == UIFocusHeadingLeft)
        {
            self.currentPreferredFocusedSubview = self.textField;
        }
        else
        {
            self.currentPreferredFocusedSubview = nil;
        }
        return true;
    }
    

    Here we just update the preferredFocusedView based on the direction the focus engine is going. If going up or down, the next row will become focused because we're returning nil. If left or right, the appropriate text fields. This is somewhat clunky but this is the tvOS 9 way of programmatically updating the focus view.

    Swift

    var currentPreferredFocusedSubview: UITextField?
        
    override var preferredFocusedView: UIView? {
        get{
            return self.currentPreferredFocusedSubview
        }
    }
    
    override func shouldUpdateFocusInContext(context: UIFocusUpdateContext) -> Bool {
        switch (self.currentPreferredFocusedSubview, context.focusHeading) {
        case (self.textField?, UIFocusHeading.Right):
            self.currentPreferredFocusedSubview = self.textField2
        case (self.textField2?, UIFocusHeading.Right):
            self.currentPreferredFocusedSubview = self.textField3
        case (self.textField3?, UIFocusHeading.Right):
            self.currentPreferredFocusedSubview = self.textField3
        case (self.textField3?, UIFocusHeading.Left):
            self.currentPreferredFocusedSubview = self.textField2
        case (self.textField2?, UIFocusHeading.Left):
            self.currentPreferredFocusedSubview = self.textField
        case (self.textField?, UIFocusHeading.Left):
            self.currentPreferredFocusedSubview = self.textField
        default:
            self.currentPreferredFocusedSubview = nil
        }
        return true
    }