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

UIPickerView selectedRowInComponent:0 always return zero first when I try to set data in second component

我是 iOS 编程新手。

最近,我试图在 UITextfield 中制作一个 UIPickerView 作为 inputView。

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

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

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

// 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 中选择第 9 行后 UIPickerView 显示为 inputView 时,selectedRowInComponent: 0 returns 0 在 numberOfRowsInComponent: 1,但 returns 9 in titleForRow: row forComponent: 1.

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

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

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

我使用 _fontTypeIsFirst 来查看 UIPickerView 是否已 selected。 当您滚动选择器视图时,您应该将 _fontTypeIsFirst 设置为 NO 并重新加载组件 1,因此它可以像往常一样 return 到组件 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];
    }
}


并且您可以将这样的代码添加到 select 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];