当我尝试在第二个组件中设置数据时,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: 0
在 numberOfRowsInComponent: 1
中返回 0,但随后在 titleForRow: row forComponent: 1
中返回 9。
我不认为你做错了什么,所以它看起来像 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 总是首先返回零的主要内容,如果未能解决你的问题,请参考以下文章