私は iOS プログラミングにかなり慣れていないので、自分では解決できない問題に遭遇しました。
私のアプリの主要部分は、検索可能な動物のリスト (AnimalTableViewController) です (この関数は機能します)。特定のセルをクリックすると、動物の画像が表示されるはずです。すべての動物の画像は、PagerViewController (CustomPagerViewController) でコンパイルされます。
私がする必要があるのは、動的テーブル セルを特定のビュー/ストーリーボードに接続することです。以前、セルを画像に接続することができました - 画像の配列が単一のView Controllerに表示されていました。スワイプ機能が必要だったので、今回は PagerViewController 経由で実行することにしました (スワイプに関連するメソッドは PagerViewController.m にあり、すべて期待どおりに動作します)。
UITableViewとPagerViewControllerの間でデータを渡す方法に関するチュートリアルやアドバイスは見つかりませんでした。
AnimalTableViewController.m
@implementation AnimalTableViewController
@synthesize allTableData;
@synthesize filteredTableData;
@synthesize searchBar;
@synthesize isFiltered;
@synthesize tableView;
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super init];
if (self) {
// Custom initialization
}
return self;
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
tableView.delegate = (id)self;
tableView.dataSource = (id)self;
searchBar.delegate = (id)self;
allTableData = [[NSMutableArray alloc] initWithObjects:
[[Animal alloc] initWithName:@"Aardvark" andDescription:@"Aardvark"],
[[Animal alloc] initWithName:@"Alligator" andDescription:@"Alligator"],
[[Animal alloc] initWithName:@"Alpaca" andDescription:@"Alpaca"],
[[Animal alloc] initWithName:@"Ant" andDescription:@"Ant"],
[[Animal alloc] initWithName:@"Anteater" andDescription:@"Anteater"],
[[Animal alloc] initWithName:@"Armadillo" andDescription:@"Armadillo"],
[[Animal alloc] initWithName:@"Baboon" andDescription:@"Baboon"],
[[Animal alloc] initWithName:@"Badger" andDescription:@"Badger"],
[[Animal alloc] initWithName:@"Bat" andDescription:@"Bat"],
[[Animal alloc] initWithName:@"Bear" andDescription:@"Bear"],
[[Animal alloc] initWithName:@"Beaver" andDescription:@"Beaver"],
[[Animal alloc] initWithName:@"Bee" andDescription:@"Bee"],
[[Animal alloc] initWithName:@"Bison" andDescription:@"Bison"],
nil ];
}
- (void)viewDidUnload
{
[self setSearchBar:nil];
[super viewDidUnload];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
int rowCount;
if(self.isFiltered)
rowCount = filteredTableData.count;
else
rowCount = allTableData.count;
return rowCount;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
Animal* animal;
if(isFiltered)
animal = [filteredTableData objectAtIndex:indexPath.row];
else
animal = [allTableData objectAtIndex:indexPath.row];
cell.textLabel.text = animal.name;
// cell.detailTextLabel.text = animal.description;
return cell;
}
#pragma mark - Table view delegate
-(void)searchBar:(UISearchBar*)searchBar textDidChange:(NSString*)text
{
if(text.length == 0)
{
isFiltered = FALSE;
}
else
{
isFiltered = true;
filteredTableData = [[NSMutableArray alloc] init];
for (Animal* animal in allTableData)
{
NSRange nameRange = [animal.name rangeOfString:text options:NSCaseInsensitiveSearch];
NSRange descriptionRange = [animal.description rangeOfString:text options:NSCaseInsensitiveSearch];
if(nameRange.location != NSNotFound || descriptionRange.location != NSNotFound)
{
[filteredTableData addObject:animal];
}
}
}
[self.tableView reloadData];
}
@end
CustomPagerViewController.m
@interface CustomPagerViewController ()
@end
@implementation CustomPagerViewController
- (void)viewDidLoad
{
// Do any additional setup after loading the view, typically from a nib.
[super viewDidLoad];
[self addChildViewController:[self.storyboard instantiateViewControllerWithIdentifier:@"Aardvark"]];
[self addChildViewController:[self.storyboard instantiateViewControllerWithIdentifier:@"Alligator"]];
[self addChildViewController:[self.storyboard instantiateViewControllerWithIdentifier:@"Alpaca"]];
}
@end
PagerViewController.m
@interface PagerViewController ()
@property (assign) BOOL pageControlUsed;
@property (assign) NSUInteger page;
@property (assign) BOOL rotating;
- (void)loadScrollViewWithPage:(int)page;
@end
@implementation PagerViewController
@synthesize scrollView;
@synthesize pageControl;
@synthesize pageControlUsed = _pageControlUsed;
@synthesize page = _page;
@synthesize rotating = _rotating;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self.scrollView setPagingEnabled:YES];
[self.scrollView setScrollEnabled:YES];
[self.scrollView setShowsHorizontalScrollIndicator:NO];
[self.scrollView setShowsVerticalScrollIndicator:NO];
[self.scrollView setDelegate:self];
}
- (BOOL)automaticallyForwardAppearanceAndRotationMethodsToChildViewControllers {
return NO;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
UIViewController *viewController = [self.childViewControllers objectAtIndex:self.pageControl.currentPage];
[viewController willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
_rotating = YES;
}
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
UIViewController *viewController = [self.childViewControllers objectAtIndex:self.pageControl.currentPage];
[viewController willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration];
self.scrollView.contentSize = CGSizeMake(scrollView.frame.size.width * [self.childViewControllers count], scrollView.frame.size.height);
NSUInteger page = 0;
for (viewController in self.childViewControllers) {
CGRect frame = self.scrollView.frame;
frame.origin.x = frame.size.width * page;
frame.origin.y = 0;
viewController.view.frame = frame;
page++;
}
CGRect frame = self.scrollView.frame;
frame.origin.x = frame.size.width * _page;
frame.origin.y = 0;
[self.scrollView scrollRectToVisible:frame animated:NO];
}
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
_rotating = NO;
UIViewController *viewController = [self.childViewControllers objectAtIndex:self.pageControl.currentPage];
[viewController didRotateFromInterfaceOrientation:fromInterfaceOrientation];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
for (NSUInteger i =0; i < [self.childViewControllers count]; i++) {
[self loadScrollViewWithPage:i];
}
self.pageControl.currentPage = 0;
_page = 0;
[self.pageControl setNumberOfPages:[self.childViewControllers count]];
UIViewController *viewController = [self.childViewControllers objectAtIndex:self.pageControl.currentPage];
if (viewController.view.superview != nil) {
[viewController viewWillAppear:animated];
}
self.scrollView.contentSize = CGSizeMake(scrollView.frame.size.width * [self.childViewControllers count], scrollView.frame.size.height);
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
if ([self.childViewControllers count]) {
UIViewController *viewController = [self.childViewControllers objectAtIndex:self.pageControl.currentPage];
if (viewController.view.superview != nil) {
[viewController viewDidAppear:animated];
}
}
}
- (void)viewWillDisappear:(BOOL)animated {
if ([self.childViewControllers count]) {
UIViewController *viewController = [self.childViewControllers objectAtIndex:self.pageControl.currentPage];
if (viewController.view.superview != nil) {
[viewController viewWillDisappear:animated];
}
}
[super viewWillDisappear:animated];
}
- (void)viewDidDisappear:(BOOL)animated {
UIViewController *viewController = [self.childViewControllers objectAtIndex:self.pageControl.currentPage];
if (viewController.view.superview != nil) {
[viewController viewDidDisappear:animated];
}
[super viewDidDisappear:animated];
}
- (void)loadScrollViewWithPage:(int)page {
if (page < 0)
return;
if (page >= [self.childViewControllers count])
return;
// replace the placeholder if necessary
UIViewController *controller = [self.childViewControllers objectAtIndex:page];
if (controller == nil) {
return;
}
// add the controller's view to the scroll view
if (controller.view.superview == nil) {
CGRect frame = self.scrollView.frame;
frame.origin.x = frame.size.width * page;
frame.origin.y = 0;
controller.view.frame = frame;
[self.scrollView addSubview:controller.view];
}
}
- (void)previousPage {
if (_page - 1 > 0) {
// update the scroll view to the appropriate page
CGRect frame = self.scrollView.frame;
frame.origin.x = frame.size.width * (_page - 1);
frame.origin.y = 0;
UIViewController *oldViewController = [self.childViewControllers objectAtIndex:_page];
UIViewController *newViewController = [self.childViewControllers objectAtIndex:_page - 1];
[oldViewController viewWillDisappear:YES];
[newViewController viewWillAppear:YES];
[self.scrollView scrollRectToVisible:frame animated:YES];
self.pageControl.currentPage = _page - 1;
// Set the boolean used when scrolls originate from the UIPageControl. See scrollViewDidScroll: above.
_pageControlUsed = YES;
}
}
- (void)nextPage {
if (_page + 1 > self.pageControl.numberOfPages) {
// update the scroll view to the appropriate page
CGRect frame = self.scrollView.frame;
frame.origin.x = frame.size.width * (_page + 1);
frame.origin.y = 0;
UIViewController *oldViewController = [self.childViewControllers objectAtIndex:_page];
UIViewController *newViewController = [self.childViewControllers objectAtIndex:_page + 1];
[oldViewController viewWillDisappear:YES];
[newViewController viewWillAppear:YES];
[self.scrollView scrollRectToVisible:frame animated:YES];
self.pageControl.currentPage = _page + 1;
// Set the boolean used when scrolls originate from the UIPageControl. See scrollViewDidScroll: above.
_pageControlUsed = YES;
}
}
- (IBAction)changePage:(id)sender {
int page = ((UIPageControl *)sender).currentPage;
// update the scroll view to the appropriate page
CGRect frame = self.scrollView.frame;
frame.origin.x = frame.size.width * page;
frame.origin.y = 0;
UIViewController *oldViewController = [self.childViewControllers objectAtIndex:_page];
UIViewController *newViewController = [self.childViewControllers objectAtIndex:self.pageControl.currentPage];
[oldViewController viewWillDisappear:YES];
[newViewController viewWillAppear:YES];
[self.scrollView scrollRectToVisible:frame animated:YES];
// Set the boolean used when scrolls originate from the UIPageControl. See scrollViewDidScroll: above.
_pageControlUsed = YES;
}
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView {
UIViewController *oldViewController = [self.childViewControllers objectAtIndex:_page];
UIViewController *newViewController = [self.childViewControllers objectAtIndex:self.pageControl.currentPage];
[oldViewController viewDidDisappear:YES];
[newViewController viewDidAppear:YES];
_page = self.pageControl.currentPage;
}
#pragma mark -
#pragma mark UIScrollViewDelegate methods
- (void)scrollViewDidScroll:(UIScrollView *)sender {
// We don't want a "feedback loop" between the UIPageControl and the scroll delegate in
// which a scroll event generated from the user hitting the page control triggers updates from
// the delegate method. We use a boolean to disable the delegate logic when the page control is used.
if (_pageControlUsed || _rotating) {
// do nothing - the scroll was initiated from the page control, not the user dragging
return;
}
// Switch the indicator when more than 50% of the previous/next page is visible
CGFloat pageWidth = self.scrollView.frame.size.width;
int page = floor((self.scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
if (self.pageControl.currentPage != page) {
UIViewController *oldViewController = [self.childViewControllers objectAtIndex:self.pageControl.currentPage];
UIViewController *newViewController = [self.childViewControllers objectAtIndex:page];
[oldViewController viewWillDisappear:YES];
[newViewController viewWillAppear:YES];
self.pageControl.currentPage = page;
[oldViewController viewDidDisappear:YES];
[newViewController viewDidAppear:YES];
_page = page;
}
}
// At the begin of scroll dragging, reset the boolean used when scrolls originate from the UIPageControl
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
_pageControlUsed = NO;
}
// At the end of scroll animation, reset the boolean used when scrolls originate from the UIPageControl
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
_pageControlUsed = NO;
}
@end