当我尝试在第二个组件中设置数据时,UIPickerView selectedRowInComponent:0 总是首先返回零

Posted

技术标签:

【中文标题】当我尝试在第二个组件中设置数据时,UIPickerView selectedRowInComponent:0 总是首先返回零【英文标题】:UIPickerView selectedRowInComponent:0 always return zero first when I try to set data in second component 【发布时间】:2018-02-21 15:15:02 【问题描述】:

我是 ios 编程新手。

最近,我正在尝试将 UIPickerView 作为 UITextfield 中的 inputView。

UIPickerView 中的数据是关于所有 iOS 内置字体的。 所以我想在UIPickerView中做两个组件:第一个是familyType,第二个是那个familyType中的所有字体。

我模拟了this answer 的代码,但遇到了一些我无法解决的问题。欢迎任何帮助!

我的问题在这里:为什么这个函数中的rowOneSelected总是先得到0,即使我提前使用了selectedRowInComponent?

// The number of rows of data
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component

    if(component == 0)
    
        return _fontTypeArray.count;
    
    else
    
        NSInteger rowOneSelected = [_pickerFont selectedRowInComponent:0];
        FontType *temp = _fontTypeArray[rowOneSelected];
        NSLog(@"%ld", (long)rowOneSelected);    // I use this to debug, and there is a main question: why every time it logs 0 first?
        return temp.font.count;
    

我所有的相关代码都在这里:

在 ViewController.h 中:

#import <UIKit/UIKit.h>
#import "MenuLayerTwoPlusThree.h"

@interface ViewController : UIViewController

@property MenuLayerTwoPlusThree *layerTwoPlusThree;

- (void)createLayerTwoPlusThree;

@end

在 ViewController.m 中:

- (void)viewDidLoad 
    [super viewDidLoad];

    [self createLayerTwoPlusThree];


- (void)createLayerTwoPlusThree

    _layerTwoPlusThree = [MenuLayerTwoPlusThree alloc];

    [_layerTwoPlusThree createFontArray];
    [_layerTwoPlusThree createSelectPanel];

在 FontType.h 中:

#ifndef FontType_h
#define FontType_h

#import <Foundation/Foundation.h>

@interface FontType : NSObject

@property NSString *familyName;
@property NSMutableArray *font;

@end

#endif /* FontType_h */

在 FontType.m 中:

#import <Foundation/Foundation.h>
#import "FontType.h"

@implementation FontType

@synthesize familyName;
@synthesize font;

@end

在 MenuLayerTwoPlusThree.h 中:

#ifndef MenuLayerTwoPlusThree_h
#define MenuLayerTwoPlusThree_h

#import <UIKit/UIKit.h>
#import "FontType.h"

@interface MenuLayerTwoPlusThree : NSObject<UITextFieldDelegate, UIPickerViewDataSource, UIPickerViewDelegate>

@property UITextField *textFieldFont;    
@property NSMutableArray *fontTypeArray;
@property UIPickerView *pickerFont;
@property UIBarButtonItem *doneButton;
@property UIBarButtonItem *spaceButton;
@property UIBarButtonItem *cancelButton;
@property UIToolbar *toolBar;
@property NSArray *toolBarItems;
@property NSInteger familyType;
@property NSInteger fontType;
@property NSString *fontName;
- (void)createFontArray;
- (IBAction)pickerViewButtonClicked:(id)sender;

@end

在 MenuLayerTwoPlusThree.m 中

- (void)createFontArray

    _fontTypeArray = [[NSMutableArray alloc]initWithCapacity:80];

    int number = 0;

    for(NSString* family in [UIFont familyNames])
    
        //NSLog(@"%@", family);
        //number++;
        FontType *temp = [[FontType alloc]init];
        temp.familyName = family;
        temp.font = [[NSMutableArray alloc]init];
        int flag = 0;

        for(NSString* name in [UIFont fontNamesForFamilyName:family])
        
            //NSLog(@" %@", name);
            //number++;
            flag++;
            [temp.font addObject:name];
        

        // add Heiti SC, Heiti TC, Telugu Sangam MN, and Bangla Sangam MN to font array
        if(flag == 0)
        
            [temp.font addObject:family];
        

        [_fontTypeArray addObject:temp];
    


    // print all fonts test
    for(FontType *x in _fontTypeArray)
    
        number++;
        NSLog(@"%@", x.familyName);
        for(NSString *y in x.font)
        
            //number++;
            NSLog(@"\t%@", y);
        
          

    NSLog(@"//////////////////////////////");
    NSLog(@"%d", number);


- (void)createSelectPanel

    [self createSelectPanelForPancel1];
    [self createSelectPanelForPancel2];
    [self createSelectPanelForFont];
    [self createSelectPanelForShape];
    [self createSelectPanelForEraser];


- (void)createSelectPanelForFont

    _textFieldFont = [[UITextField alloc]initWithFrame:CGRectMake(19, 148, 150, 12)];
    [_textFieldFont setBackground:[UIImage imageNamed:@"font-type-bar.png"]];
    _textFieldFont.rightViewMode = UITextFieldViewModeAlways;
    _textFieldFont.delegate = self;
    [_textFieldFont setPlaceholder:@"Heiti TC"];
    _textFieldFont.font = [_textFieldFont.font fontWithSize:10 * _aspectRatio];


    // resize right view image
    UIImageView *rightViewImage = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, 12 * _aspectRatio, 12 * _aspectRatio)];
    [rightViewImage setImage:[UIImage imageNamed:@"font-type-bar-roll.png"]];
    _textFieldFont.rightView = rightViewImage;


    _pickerFont = [[UIPickerView alloc]init];
    _pickerFont.dataSource = self;
    _pickerFont.delegate = self;
    _pickerFont.showsSelectionIndicator = YES;


    _doneButton = [[UIBarButtonItem alloc]initWithTitle:@"Done" style:UIBarButtonItemStyleDone target:self action:@selector(pickerViewButtonClicked:)];
    _spaceButton = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
    _cancelButton = [[UIBarButtonItem alloc]initWithTitle:@"Cancel" style:UIBarButtonItemStylePlain target:self action:@selector(pickerViewButtonClicked:)];
    _toolBar = [[UIToolbar alloc]initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 45)];
    [_toolBar setBarStyle:UIBarStyleDefault];
    _toolBarItems = [NSArray arrayWithObjects:_cancelButton, _spaceButton, _doneButton, nil];
    [_toolBar setItems:_toolBarItems];

    _textFieldFont.inputView = _pickerFont;
    _textFieldFont.inputAccessoryView = _toolBar;
    if (@available(iOS 9.0, *)) 
        _textFieldFont.inputAssistantItem.leadingBarButtonGroups = @[];
     else 
        // Fallback on earlier versions
    
    if (@available(iOS 9.0, *)) 
        _textFieldFont.inputAssistantItem.trailingBarButtonGroups = @[];
     else 
        // Fallback on earlier versions
    

    // I want to add these codes to select row in advanced to make sure first time NSLog will print 9, but it doesn't work.
//    [_pickerFont reloadAllComponents];
//    _familyType = 9;
//    _fontType = 0;
//    _fontName = @"Heiti TC";
//    [_pickerFont selectRow:_familyType inComponent:0 animated:YES];

    [_selectPanelFontView addSubview:_textFieldFont];

这是委托,我写在 MenuLayerTwoPlusThree.m 中:

// The number of columns of data
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView

    return 2;


// The number of rows of data
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component

    if(component == 0)
    
        return _fontTypeArray.count;
    
    else
    
        NSInteger rowOneSelected = [_pickerFont selectedRowInComponent:0];
        FontType *temp = _fontTypeArray[rowOneSelected];
        NSLog(@"%ld", (long)rowOneSelected);    // I use this to debug, and there is a main question: why every time it logs 0 first?
        return temp.font.count;
    


// The data to return for the row and component (column) that's being passed in
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component

    if(component == 0)
    
        FontType *temp = _fontTypeArray[row];
        return temp.familyName;
    
    else
    
        NSInteger rowOneSelected = [_pickerFont selectedRowInComponent:0];
        FontType *temp = _fontTypeArray[rowOneSelected];
        return [temp.font objectAtIndex:row];
    


- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component

    if(component == 0)
    
        [_pickerFont reloadComponent:1];
    

    // This block is moved to pickerViewButtonClicked (sender == _doneButton)
//    else
//    
//        NSInteger rowOneSelected = [_pickerFont selectedRowInComponent:0];
//        FontType *temp = _fontTypeArray[rowOneSelected];
//        [_textFieldFont setText:temp.font[row]];
//    


- (IBAction)pickerViewButtonClicked:(id)sender

    if(sender == _doneButton)
    
        // Save value when I clicked the done button.
        _familyType = [_pickerFont selectedRowInComponent:0];
        _fontType = [_pickerFont selectedRowInComponent:1];

//        NSLog(@"family: %ld", _familyType);
//        NSLog(@"font: %ld", _fontType);

        FontType *temp = _fontTypeArray[_familyType];
        _fontName = temp.font[_fontType];
        [_textFieldFont setText:_fontName];

//        NSLog(@"font name: %@", _fontName);


        [_textFieldFont endEditing:YES];
    
    else if(sender == _cancelButton)
    
        [_textFieldFont endEditing:YES];

        // I want to turn back to the last selected value when I clicked the cancel button.
        [_pickerFont reloadAllComponents];
        [_pickerFont selectRow:_familyType inComponent:0 animated:NO];
        [_pickerFont selectRow:_fontType inComponent:1 animated:NO];
    

【问题讨论】:

我不确定我是否理解您的问题。你期望什么而不是 0? @JörnEyrich 例如,当第一次弹出选择器视图时,我在第 1 列第 9 行中选择了“Heiti TC”。在第 2 列第 0 行中只有一种名为“Heiti TC”的字体,所以我选择了它们并单击完成按钮以关闭它们。下次我单击文本字段以弹出选择器视图时,我希望它会在第 1 列中显示“Heiti TC”,在第 2 列中显示“Heiti TC”。但是,它会崩溃并显示错误日志“索引 1 越界” [0 .. 0]”。 我知道为什么它会显示这个错误日志。我使用 NSLog 打印 rowOneSelected,它会打印 0 而不是 9。因为我在第 1 列第 0 行中的数据是“Copperplate”,并且在第 2 列中有三种字体,所以 temp.font.count 在我的代码中将是 3。但是,当第一列选择“Heiti TC”时,第二列只有一行。所以它会立即崩溃并显示它超出了范围。 对不起,第 1 列表示组件 0,第 2 列表示组件 1。 并且我尝试添加一些代码来提前选择组件0中的值(请查看MenuLayerTwoPlusThree.m中的最后几行),但它仍然崩溃并再次打印0。 【参考方案1】:

确实,当您在组件 0 中选择第 9 行后,UIPickerView 显示为 inputView 时,selectedRowInComponent: 0numberOfRowsInComponent: 1 中返回 0,但随后在 titleForRow: row forComponent: 1 中返回 9。

p>

我不认为你做错了什么,所以它看起来像 UIKit 中的一个错误。

作为一种解决方法,我建议您不要向选择器视图询问所选行,而是自己跟踪所选行(在您的视图控制器中初始化您自己的变量并在didSelectRow: row inComponent: 0 中更新它)

【讨论】:

谢谢!我跟踪 UIPickerView 的价值并找到一种非正式的方式来解决这个问题。今天课程结束后我会分享我的代码!【参考方案2】:

抱歉,我忘记发布我的解决方案了。

我使用 _fontTypeIsFirst 来查看 UIPickerView 是否被选中。 滚动选择器视图时,应将 _fontTypeIsFirst 设置为 NO 并重新加载组件 1,以便它可以像往常一样返回到组件 1 中的第 0 行。

这是我的代码:

部分代表:

// The number of columns of data
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView

    return 2;


// The number of rows of data
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component

    if(component == 0)
    
        return _fontTypeArray.count;
    
    else
    
        NSInteger rowOneSelected;
        if (_fontTypeIsFirst == YES)
        

            rowOneSelected = _selectedRow;
        
        else
        
            rowOneSelected = [_pickerFont selectedRowInComponent:0];
        
        FontType *temp = _fontTypeArray[rowOneSelected];
        return temp.font.count;
    


// The data to return for the row and component (column) that's being passed in
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component

    if(component == 0)
    
        FontType *temp = _fontTypeArray[row];
        return temp.familyName;
    
    else
    
        NSInteger rowOneSelected;
        if (_fontTypeIsFirst == YES)
        
            rowOneSelected = _selectedRow;
        
        else
        
            rowOneSelected = [_pickerFont selectedRowInComponent:0];
        

        FontType *temp = _fontTypeArray[rowOneSelected];
        return [temp.font objectAtIndex:row];
    


- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component

    _fontTypeIsFirst = NO;

    if(component == 0)
    
        [_pickerFont reloadComponent:1];
    

这是完成和取消按钮的操作:

- (IBAction)pickerViewButtonClicked:(id)sender

    if(sender == _doneButton)
    
        _selectedRow = [_pickerFont selectedRowInComponent:0];
        _familyType = [_pickerFont selectedRowInComponent:0];
        _fontType = [_pickerFont selectedRowInComponent:1];

        FontType *temp = _fontTypeArray[_familyType];
        _fontName = temp.font[_fontType];
        [_textFieldFont setText:_fontName];

        [_textFieldFont endEditing:YES];
        _fontTypeIsFirst = YES;
    
    else if(sender == _cancelButton)
    
        [_textFieldFont endEditing:YES];
        _fontTypeIsFirst = YES;

        [_pickerFont selectRow:_familyType inComponent:0 animated:NO];
        [_pickerFont selectRow:_fontType inComponent:1 animated:NO];
    

您可以添加这样的代码来在 viewDidLoad 或某个地方选择选择器视图的默认值:

_fontTypeIsFirst = YES;
_selectedRow = 9;
_familyType = 9;
_fontType = 0;
_fontName = @"Heiti TC";
[_pickerFont selectRow:_familyType inComponent:0 animated:NO];
[_pickerFont selectRow:_fontType inComponent:1 animated:NO];

【讨论】:

以上是关于当我尝试在第二个组件中设置数据时,UIPickerView selectedRowInComponent:0 总是首先返回零的主要内容,如果未能解决你的问题,请参考以下文章

不保存组件数据之间的角度通信

在android中的不同活动中设置按钮上的时间

如何在 extjs 3.2 中设置值

Cloudinary 的上传小部件 v2 中存在多个文件的问题 [关闭]

如何在 UIPicker 中动态填充值

在几个JLabel中设置相同的gif作为图标