问题描述
我使用以下链接修改的DateCell代码。
I used the amended DateCell code from the following link DateCell without storyboard.
我想用 UIPickerView
替换 UIDatePicker
。下面是我修改/评论的代码,使其适用于 UIPickerView
。
I want to replace UIDatePicker
with UIPickerView
. Below is the code that I have amended/commented to make it work for UIPickerView
.
在每个单元格点击中,我能够显示 UIPickerView
但它只加载一次,其余的出现具有相同行标题的单元格 UIPickerView
,当我从 UIPickerView
中选择一行时,它会崩溃。最近几天我陷入了困境。
On each cell tap, I'm able to show UIPickerView
but it only loads once and for the rest of the cells UIPickerView
with same row titles appears and it crashes when I select a row from UIPickerView
. I'm stuck into this for last couple of days.
任何帮助都将受到高度赞赏。
Any help would be highly appreciated.
MoreTableViewController.h
#import <UIKit/UIKit.h>
@interface MoreTableViewController : UITableViewController<UIPickerViewDataSource, UIPickerViewDelegate>
@property(nonatomic,retain)NSArray *ASOR;
@property(nonatomic,retain)NSArray *ASQT;
@property(nonatomic,retain)NSArray *respectiveOptions;
@end
MoreTableViewController.m
#import "MoreTableViewController.h"
#import "AppDelegate.h"
#define kPickerAnimationDuration 0.40 // duration for the animation to slide the date picker into view
#define kDatePickerTag 99 // view tag identifiying the date picker view
//#define kTitleKey @"title" // key for obtaining the data source item's title
//#define kDateKey @"date" // key for obtaining the data source item's date value
// keep track of which rows have date cells
#define kDateStartRow 1
#define kDateEndRow 2
static NSString *kDateCellID = @"dateCell"; // the cells with the start or end date
static NSString *kDatePickerID = @"datePicker"; // the cell containing the date picker
static NSString *kOtherCell = @"otherCell"; // the remaining cells at the end
#pragma mark -
@interface MoreTableViewController ()
@property (nonatomic, strong) NSArray *dataArray;
//@property (nonatomic, strong) NSDateFormatter *dateFormatter;
// keep track which indexPath points to the cell with UIDatePicker
@property (nonatomic, strong) NSIndexPath *datePickerIndexPath;
@property (assign) NSInteger pickerCellRowHeight;
@property (nonatomic, strong) UIPickerView *pickerView;
@end
@implementation MoreTableViewController
@synthesize ASOR, ASQT, respectiveOptions;
- (UITableViewCell *) createCellWithIdetifier:(NSString *)cellId {
NSArray *reusableUiComponents = [[NSBundle mainBundle] loadNibNamed:@"ReusableUIComponents" owner:self options:nil];
if ([kDateCellID isEqualToString:cellId]) {
return reusableUiComponents[0];
}
if ([kDatePickerID isEqualToString:cellId]) {
return reusableUiComponents[1];
}
// if ([kOtherCell isEqualToString:cellId]) {
// return reusableUiComponents[2];
// }
return nil;
}
- (AppDelegate *)appDelegate {
return (AppDelegate *)[[UIApplication sharedApplication] delegate];
}
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)setupDataSource {
// setup our data source
// NSMutableDictionary *itemOne = [@{ kTitleKey : @"Tap a cell to change its date:" } mutableCopy];
// NSMutableDictionary *itemTwo = [@{ kTitleKey : @"Start Date",
// kDateKey : [NSDate date] } mutableCopy];
// NSMutableDictionary *itemThree = [@{ kTitleKey : @"End Date",
// kDateKey : [NSDate date] } mutableCopy];
// NSMutableDictionary *itemFour = [@{ kTitleKey : @"(other item1)" } mutableCopy];
// NSMutableDictionary *itemFive = [@{ kTitleKey : @"(other item2)" } mutableCopy];
self.dataArray = [[self appDelegate]advanceSearchQuestionsText];
//self.dateFormatter = [[NSDateFormatter alloc] init];
//[self.dateFormatter setDateStyle:NSDateFormatterShortStyle]; // show short-style date format
//[self.dateFormatter setTimeStyle:NSDateFormatterNoStyle];
// obtain the picker view cell's height, works because the cell was pre-defined in our storyboard
UITableViewCell *pickerViewCellToCheck = [self createCellWithIdetifier:kDatePickerID];
self.pickerCellRowHeight = pickerViewCellToCheck.frame.size.height;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self setupDataSource];
//self.title = @"DateCell";
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
ASQT = [[NSArray alloc]init];
ASOR = [[NSArray alloc]init];
ASQT = [[self appDelegate]advanceSearchQuestionsText];
ASOR = [[self appDelegate]advanceSearchOptionsArray];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Utilities
/*! Returns the major version of iOS, (i.e. for iOS 6.1.3 it returns 6)
*/
NSUInteger UNUSED_DeviceSystemMajorVersion() // TODO - move this to Utils
{
static NSUInteger _deviceSystemMajorVersion = -1;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_deviceSystemMajorVersion = [[[[[UIDevice currentDevice] systemVersion] componentsSeparatedByString:@"."] objectAtIndex:0] intValue];
});
return _deviceSystemMajorVersion;
}
/*! Determines if the given indexPath has a cell below it with a UIDatePicker.
@param indexPath The indexPath to check if its cell has a UIDatePicker below it.
*/
- (BOOL)hasPickerForIndexPath:(NSIndexPath *)indexPath
{
BOOL hasDatePicker = NO;
NSInteger targetedRow = indexPath.row;
targetedRow++;
UITableViewCell *checkDatePickerCell =
[self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:targetedRow inSection:0]];
UIPickerView *checkDatePicker = (UIPickerView *)[checkDatePickerCell viewWithTag:kDatePickerTag];
hasDatePicker = (checkDatePicker != nil);
return hasDatePicker;
}
/*! Updates the UIDatePicker's value to match with the date of the cell above it.
*/
- (void)updateDatePicker
{
if (self.datePickerIndexPath != nil)
{
UITableViewCell *associatedDatePickerCell = [self.tableView cellForRowAtIndexPath:self.datePickerIndexPath];
UIPickerView *targetedDatePicker = (UIPickerView *)[associatedDatePickerCell viewWithTag:kDatePickerTag];
if (targetedDatePicker != nil)
{
// we found a UIDatePicker in this cell, so update it's date value
//
// NSDictionary *itemData = self.dataArray[self.datePickerIndexPath.row - 1];
// [targetedDatePicker setDate:[itemData valueForKey:kDateKey] animated:NO];
// set the call action for the date picker to dateAction
// [targetedDatePicker addTarget:self action:@selector(dateAction:) forControlEvents:UIControlEventValueChanged];
}
}
}
/*! Determines if the UITableViewController has a UIDatePicker in any of its cells.
*/
- (BOOL)hasInlineDatePicker
{
return (self.datePickerIndexPath != nil);
}
/*! Determines if the given indexPath points to a cell that contains the UIDatePicker.
@param indexPath The indexPath to check if it represents a cell with the UIDatePicker.
*/
- (BOOL)indexPathHasPicker:(NSIndexPath *)indexPath
{
return ([self hasInlineDatePicker] && self.datePickerIndexPath.row == indexPath.row);
}
/*! Determines if the given indexPath points to a cell that contains the start/end dates.
@param indexPath The indexPath to check if it represents start/end date cell.
*/
- (BOOL)indexPathHasDate:(NSIndexPath *)indexPath
{
BOOL hasDate = NO;
if ((indexPath.row == kDateStartRow) ||
(indexPath.row == kDateEndRow || ([self hasInlineDatePicker] && (indexPath.row == kDateEndRow + 1))))
{
hasDate = YES;
}
return hasDate;
}
#pragma mark - Table view data source
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
CGFloat height = ([self indexPathHasPicker:indexPath] ? self.pickerCellRowHeight : self.tableView.rowHeight);
return height;
}
//- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
//{
// return 1;
//}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if ([self hasInlineDatePicker])
{
// we have a date picker, so allow for it in the number of rows in this section
NSInteger numRows = self.dataArray.count;
return ++numRows;
}
return self.dataArray.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = nil;
NSString *cellID = kDateCellID;
if ([self indexPathHasPicker:indexPath])
{
// the indexPath is the one containing the inline date picker
cellID = kDatePickerID; // the current/opened date picker cell
}
else if ([self indexPathHasDate:indexPath])
{
// the indexPath is one that contains the date information
cellID = kDateCellID; // the start/end date cells
}
cell = [tableView dequeueReusableCellWithIdentifier:cellID];
if (!cell) {
cell = [self createCellWithIdetifier:cellID];
}
if (indexPath.row == 0)
{
// we decide here that first cell in the table is not selectable (it's just an indicator)
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
// if we have a date picker open whose cell is above the cell we want to update,
// then we have one more cell than the model allows
//
NSInteger modelRow = indexPath.row;
if (self.datePickerIndexPath != nil && self.datePickerIndexPath.row < indexPath.row)
{
modelRow--;
}
NSDictionary *itemData = self.dataArray[modelRow];
// proceed to configure our cell
if ([cellID isEqualToString:kDateCellID])
{
// we have either start or end date cells, populate their date field
//
cell.textLabel.text = [self.dataArray objectAtIndex:indexPath.row];
//cell.detailTextLabel.text = [self.dateFormatter stringFromDate:[itemData valueForKey:kDateKey]];
}
// else if ([cellID isEqualToString:kOtherCell])
// {
// // this cell is a non-date cell, just assign it's text label
// //
// //cell.textLabel.text = [itemData valueForKey:kTitleKey];
// cell.textLabel.text = [self.dataArray objectAtIndex:indexPath.row];
// }
return cell;
}
/*! Adds or removes a UIDatePicker cell below the given indexPath.
@param indexPath The indexPath to reveal the UIDatePicker.
*/
- (void)toggleDatePickerForSelectedIndexPath:(NSIndexPath *)indexPath
{
[self.tableView beginUpdates];
NSArray *indexPaths = @[[NSIndexPath indexPathForRow:indexPath.row + 1 inSection:0]];
// check if 'indexPath' has an attached date picker below it
if ([self hasPickerForIndexPath:indexPath])
{
// found a picker below it, so remove it
[self.tableView deleteRowsAtIndexPaths:indexPaths
withRowAnimation:UITableViewRowAnimationFade];
}
else
{
// didn't find a picker below it, so we should insert it
[self.tableView insertRowsAtIndexPaths:indexPaths
withRowAnimation:UITableViewRowAnimationFade];
}
[self.tableView endUpdates];
}
/*! Reveals the date picker inline for the given indexPath, called by "didSelectRowAtIndexPath".
@param indexPath The indexPath to reveal the UIDatePicker.
*/
- (void)displayInlineDatePickerForRowAtIndexPath:(NSIndexPath *)indexPath
{
// display the date picker inline with the table content
[self.tableView beginUpdates];
BOOL before = NO; // indicates if the date picker is below "indexPath", help us determine which row to reveal
if ([self hasInlineDatePicker])
{
before = self.datePickerIndexPath.row < indexPath.row;
}
BOOL sameCellClicked = (self.datePickerIndexPath.row - 1 == indexPath.row);
// remove any date picker cell if it exists
if ([self hasInlineDatePicker])
{
[self.tableView deleteRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:self.datePickerIndexPath.row inSection:0]]
withRowAnimation:UITableViewRowAnimationFade];
self.datePickerIndexPath = nil;
}
if (!sameCellClicked)
{
// hide the old date picker and display the new one
NSInteger rowToReveal = (before ? indexPath.row - 1 : indexPath.row);
NSIndexPath *indexPathToReveal = [NSIndexPath indexPathForRow:rowToReveal inSection:0];
[self toggleDatePickerForSelectedIndexPath:indexPathToReveal];
self.datePickerIndexPath = [NSIndexPath indexPathForRow:indexPathToReveal.row + 1 inSection:0];
}
// always deselect the row containing the start or end date
[self.tableView deselectRowAtIndexPath:indexPath animated:YES];
[self.tableView endUpdates];
// inform our date picker of the current date to match the current cell
[self updateDatePicker];
}
#pragma mark - UITableViewDelegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
respectiveOptions = [[NSArray alloc]init];
respectiveOptions = [ASOR objectAtIndex:indexPath.row];
if ([kDateCellID isEqualToString:cell.reuseIdentifier])
{
[self displayInlineDatePickerForRowAtIndexPath:indexPath];
}
else
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
}
- (UIPickerView*)pickerViewForCell:(UITableViewCell*)cell {
UIPickerView * picker = [[UIPickerView alloc] initWithFrame:cell.bounds];
[picker setDelegate:self];
[picker setDataSource:self];
picker.hidden = YES;
[cell addSubview:picker];
return picker;
}
#pragma mark - Actions
/*! User chose to change the date by changing the values inside the UIDatePicker.
@param sender The sender for this action: UIDatePicker.
*/
//- (void)dateAction:(id)sender
//{
// NSIndexPath *targetedCellIndexPath = nil;
//
// if ([self hasInlineDatePicker])
// {
// // inline date picker: update the cell's date "above" the date picker cell
// //
// targetedCellIndexPath = [NSIndexPath indexPathForRow:self.datePickerIndexPath.row - 1 inSection:0];
// }
// else
// {
// // external date picker: update the current "selected" cell's date
// targetedCellIndexPath = [self.tableView indexPathForSelectedRow];
// }
//
// UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:targetedCellIndexPath];
// UIDatePicker *targetedDatePicker = sender;
//
// // update our data model
// NSMutableDictionary *itemData = self.dataArray[targetedCellIndexPath.row];
// [itemData setValue:targetedDatePicker.date forKey:kDateKey];
//
// // update the cell's date string
// cell.detailTextLabel.text = [self.dateFormatter stringFromDate:targetedDatePicker.date];
//}
// Number of components.
-(NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView{
return 1;
}
// Total rows in our component.
-(NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component{
return [respectiveOptions count];
}
// Display each row's data.
-(NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component{
return [respectiveOptions objectAtIndex:row];
}
// Do something with the selected row.
-(void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component{
}
推荐答案
以下是使用<$的 UITableView
的示例嵌入在单元格中的c $ c> UIPickerView 。
Here is an example of UITableView
making use of UIPickerView
embedded in the cells.
我没有改变选择器视图,单元格,单元格高度的颜色 - I我会留给你做一些适合你需要的事情。
I am not changing the color of the picker view, cells, height of cells - I will leave that up to you to do something that suits your needs.
但这里的主要想法是向你展示你如何在单元格中拥有选择器视图并且能够相应地得到价值。
But the main idea here is to show you how you could have picker view in cells and be able to get value accordingly.
@interface YourController ()
@property (strong, nonatomic) NSMutableArray *pickerViewsArray;
@end
@implementation YourController
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self)
{
// Custom initialization
}
return self;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.pickerViewsArray = [[NSMutableArray alloc] init];
[self createYourPickerViews];
}
- (void)createYourPickerViews
{
for(int x = 0; x < 10; x++) //number of picker views
{
UIPickerView *pickerView = [[UIPickerView alloc] initWithFrame:(CGRect){{0, 0}, 150, 10}];
pickerView.delegate = self;
pickerView.dataSource = self;
pickerView.tag = x;
[self.pickerViewsArray addObject:pickerView];
}
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [self.pickerViewsArray count]; //As mentioned before, this is important.
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
// Configure the cell...
cell.textLabel.text = [NSString stringWithFormat:@"%i", indexPath.row];
[cell.contentView addSubview:(UIPickerView*)[self.pickerViewsArray objectAtIndex:indexPath.row]];
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 150.0f; //just some arbitrary value, change it to suit your needs.
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
}
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
//tag corresponds to row on tables view.
NSLog(@"view tag:%ld", (long)pickerView.tag);
//row here corresponds to the value selected from picker view.
NSLog(@"view value:%ld", (long)row);
}
- (NSString*) pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
return [NSString stringWithFormat:@"%d", row+1];
}
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
return 1;
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
//change this value to suit your needs.
return 10;
}
@end
最后确保这样做在你的.h:
Finally make sure to do this in your .h:
@interface YourController : UITableViewController <UITableViewDataSource, UITableViewDelegate, UIPickerViewDelegate, UIPickerViewDataSource>
通过此,您可以相应地从每个不同的单元格中从选择器视图中检索值。
With this you could be able to retrieve the value from picker view from each different cell accordingly.
对于UI我留给你。代码经过测试。希望这会有所帮助。
For UI I leave that to you. Code is tested. Hope this helps.
评论后(更新2):
Post-Comment (Update 2):
我再次跑了,我看到了你的意思,虽然昨天没有发生在我身上。
我对以下内容进行了更改并运行了另一个测试,这将修复它:
I ran it again and I see what you meant, although it didn't happen to me yesterday.I made changes to the following and ran another test, this will fix it:
在 cellForRowAtIndexPath
:
if(cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.textLabel.text = [NSString stringWithFormat:@"%i", indexPath.row];
[cell.contentView addSubview:[self.pickerViewsArray objectAtIndex:indexPath.row]];
}
另一个更新(关于UI:如何隐藏和点击单元格时取消隐藏选择器):
Another Update (concerning UI: how to hide and un-hide picker when tapped on cells):
将其修改为:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UIPickerView *temp;
temp = [self.pickerViewsArray objectAtIndex:indexPath.row];
if(!temp.isUserInteractionEnabled)
{
[UIView animateWithDuration:1.0f animations:^
{
temp.userInteractionEnabled = YES;
temp.layer.opacity = 1.0f;
}
completion:^(BOOL finished)
{
}];
}
else
{
[UIView animateWithDuration:1.0f animations:^
{
temp.userInteractionEnabled = NO;
temp.layer.opacity = 0.0f;
}
completion:^(BOOL finished)
{
}];
}
}
并且在:
- (void)createYourPickerViews
{
for(int x = 0; x < 10; x++)
{
UIPickerView *pickerView = [[UIPickerView alloc] initWithFrame:(CGRect){{0, 0}, 150, 10}];
pickerView.delegate = self;
pickerView.dataSource = self;
pickerView.layer.opacity = 0.0f; ======>>> //Add this
pickerView.userInteractionEnabled = NO; =======>>> //And this
pickerView.tag = x;
[self.pickerViewsArray addObject:pickerView];
}
}
同样,代码经过测试。希望这(终于)有所帮助。
Again, code is tested. Hope this (finally) helps.
这篇关于UIPickerView内部UITableView使用DateCell的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!