custom UIPickerView - limit user to spinning one wheel at a time

跟風遠走 提交于 2019-12-25 08:31:45

问题


I have a custom UIPickerView with three components that are dependent on one another (i.e., the second one shows values depending on what has been selected in the first one and the third is dependent on the first and second). I am getting the values that are shown in the UIPickerView out of an NSDictionary.

Everything works nicely, except, when I spin two of the components at the same time, the app sometimes crashes (no time to reload data). This is what my pickerView:didSelectRow:inComponent looks like:

- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component 
{
    NSLog(@"Selecting row %d component %d", row, component);

    // When A is changed, we need to reload B and C
    if (component == 0) {

        [pickerView reloadComponent:1];
        [pickerView selectRow:0 inComponent:1 animated:YES];

        // need to reload the C after reloading B
        [self pickerView:pickerView didSelectRow:0 inComponent:1];

    }
    else if (component == 1) {
        [pickerView reloadComponent:2];
        [pickerView selectRow:0 inComponent:2 animated:YES];
    }
    [self updateSelection];
}

Is there a way to prevent the user from spinning more than one component of the picker at a time to prevent a crash?

Thanks!


回答1:


Good holy Jesus you call didSelectRow:component: recursively!

I know that the way you handle parameters prevents it from going more than two levels deep, but still, don't do that. Ever.

There's no way to prevent the user from spinning more than one component at a time. It is the joy of multitouch and iOS to set everything in motion and watch it all settle down into a consistent state. And because the spinner components take time to settle, the user can set them all atwitter using just one finger. You must learn to write your code accordingly.

In this case, you want to delete all calls to didSelectRow:component: from within itself - it is to be called by the system only. You're on the right track with your use of reloadComponent:, it's just that you're not reloading enough of them:

-(void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
    NSLog(@"Selecting row %d component %d", row, component);

    [self updateSelection];

    // When A is changed, we need to reload B and C
    if (component == 0) {
        [pickerView reloadComponent:1];
        [pickerView reloadComponent:2];
    } else if (component == 1) {
        [pickerView reloadComponent:2];
    }
}

I don't know what your updateSelection does - presumably it sets the data model based on the value of pickerView. This is fine - but it needs to happen at the top of your method, so that when whichever of your titleForRow or viewForRow is called, it has the proper data to choose from. Also, from within any of those three (update,titleFor, viewFor) do not assert values into the picker! Just read from it.

I think this is a good starting point for you, but you will have to tweak things a little here and there as you get closer to your goal. I think you will find that the key to Pickers is that they only assert didSelectRow:component: when one of the component spinner things settles down on a value, and they're really good about continuing to spin if you reload them. Give this a shot and see if you can make some progress, send word back if you get stuck.




回答2:


Spinning two wheels at a time means you have multi-touch enabled, right? So, a possibility, may be to just disable multi-touch and limit the user to touching and affecting only one wheel in the UIPickerView.

Here's a link that might help.



来源:https://stackoverflow.com/questions/10198413/custom-uipickerview-limit-user-to-spinning-one-wheel-at-a-time

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!