Currently I have a uicollection view which displays a specific album in the users photos, (ALAssets library).
In my mainView.m I gather the pictures:
+ (ALAssetsLibrary *)defaultAssetsLibrary {
static dispatch_once_t pred = 0;
static ALAssetsLibrary *library = nil;
dispatch_once(&pred, ^{
library = [[ALAssetsLibrary alloc] init];
});
return library;
}
- (void)beginLoadingPhotoInfo {
...
[library enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos
usingBlock:assetGroupEnumerator
failureBlock:^(NSError *error) {NSLog(@"Probs");}
];
}
Load them (the thumbnail version) all into the collection view and that all works well.
Then when a user selects a photo I call this prepareToSegue method: (still in mainView.m)
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if([[segue identifier] isEqualToString:@"showDetail"])
{
NSIndexPath *indexPath = [[self.collectionView indexPathsForSelectedItems] lastObject];
DetailViewController *detailviewcontroller = [segue destinationViewController];
detailviewcontroller.photoArrayIndex = indexPath.row;
//photos array
detailviewcontroller.photosArray = _photoListArray;
}
Currently I am sending an array with the info of the photos and attempting to scroll to the position in the array.
I found this resource here for the horizontal paging:
http://adoptioncurve.net/archives/2013/04/creating-a-paged-photo-gallery-with-a-uicollectionview/
Which allows for paging using a collection view. I wrote that a detailViewController class.
Here's the question. How should I connect the two?
Idea 1: Have my mainView send an integer number representing the photo selected and the detailViewController will then load that one and begin lazy loading the photos.
Idea 2: Somehow preload some of the full screen photos and then send the integer with the spot in the array.
Idea 3: Send both the number and my array object over to the detailViewController so that I don't have to enumerate through the assets library again.
Are any of these the correct approach or did I miss the idea completely?
edit:
What I have in my detail controller is an uicollectionview flow layout with paging enabled. This is the method where I set up the layout:
- (void) setCollectionView {
[self.collectionView registerClass:[DetailViewCell class] forCellWithReuseIdentifier:@"detailViewCell"];
//Flow Layout
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
[flowLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
[flowLayout setMinimumInteritemSpacing:0.0f];
[flowLayout setMinimumLineSpacing:0.0f];
[self.collectionView setPagingEnabled:YES];
[self.collectionView setCollectionViewLayout:flowLayout];
CGFloat pageWidth = self.collectionView.frame.size.width;
NSInteger num = _photosArrayIndex + 1;
CGPoint scrollTo = CGPointMake(pageWidth * num, 0);
NSLog(@"scroll to: %@", NSStringFromCGPoint(scrollTo));
[self.collectionView setContentOffset:scrollTo];
}
What It should do is take the value from my main view and move to that image. Unfortunately it does not. I'm not sure why and also I feel like there is a better way of doing this. It just seems sort of Hackish.
How do I connect the two better controller better and what is the correct way of loading the photos/ how do I get to the photo (in the full size detail view) I was on when they were in a grid layout.
Help is appreciated.
OK, there are three parts to this.
First is the UICollectionViewController
subclass to display the gallery of photos (UIImage
).
Second is the UIPageViewController
subclass to manage the swiping from side to side of each individual PhotoViewController
.
Third is the UIViewController
subclass (PhotoViewController
) to display a single photo.
The storyboard will look something like this...

On the left is a UICollectionViewController
this has a segue to the UIPageViewController
in the middle. On the right is a UIViewController
that has an Identifier
set in the properties pane (note, there is no segue to this).
Identifier for the PhotoViewController
...

In the PhotoPageViewController
I have a custom object...

With a Class type PhotoPageModelController
set in the properties pane... This is connected as the dataSource of the PhotoPageViewController
.

That's pretty much all the storyboard set up required.
So, the first thing to set up is the PhotoPageModelController
. This is the dataSource for the PhotoPageViewController
as such will dispense subclasses of UIViewController
so that the PhotoPageViewController
can display them.
The Model Controller
PhotoPageModelController.h
@class PhotoViewController;
@interface PhotoPageModelController : NSObject <UIPageViewControllerDataSource>
// this is the array of the photos. Either an array of UIImages or objects containing
// them or something. My personal project had an array of photoIDs that I could use to
// pull the photos out of Core Data.
// In this example the array will contain instances of UIImage.
@property (nonatomic, strong) NSArray *photos;
- (PhotoViewController *)viewControllerAtIndex:(NSUInteger)index storyboard:(UIStoryboard *)storyboard;
- (NSUInteger)indexOfViewController:(PhotoViewController *)controller;
@end
PhotoPageModelController.m
#import "PhotoPageModelController.h"
#import "PhotoViewController.h"
@implementation PhotoPageModelController
- (UIImage *)photoAtIndex:(NSUInteger)index
{
// check that the index is in bounds and then return the UIImage to display.
// In my project I just returned the ID of the photo and let the photo
// controller load the actual image from core data. (See below)
if ([self.photos count] == 0
|| index >= [self.photos count]) {
return nil;
}
return self.photos[index];
}
#pragma mark - convenience methods
- (PhotoViewController *)viewControllerAtIndex:(NSUInteger)index storyboard:(UIStoryboard *)storyboard
{
UIImage *photo = [self photoAtIndex:index];
if (photo == nil) {
return nil;
}
// This is why we don't have a segue. We are loading it manually
// from the storyboard using the identifier.
EventPhotoViewController *controller = [storyboard instantiateViewControllerWithIdentifier:@"PhotoViewController"];
// The model controller is where the PhotoViewController gets the actual image from.
// Or an object containing the image with a name, date, details, etc...
// The controller doesn't know anything about the other photos. Only the one it's displaying.
controller.photo = photo;
return controller;
}
- (NSUInteger)indexOfViewController:(PhotoViewController *)controller
{
// Return the index of the given data view controller.
// For simplicity, this implementation uses a static array of model objects and the view controller stores the model object; you can therefore use the model object to identify the index.
return [self.photos indexOfObject:controller.photo];
}
#pragma mark - page view data source
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController
{
// We need to find the index of the current controller so we can get the index
// and then the view controller for the one before it.
NSUInteger index = [self indexOfViewController:(PhotoViewController *) viewController];
if ((index == 0) || (index == NSNotFound)) {
// We have reached the beginning of the photos array so return nil.
// This tells the Page View Controller that there isn't another page.
return nil;
}
index--;
return [self viewControllerAtIndex:index storyboard:viewController.storyboard];
}
// This is the same as above but going forward instead of backward.
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
{
NSUInteger index = [self indexOfViewController:(EventPhotoViewController *) viewController];
if (index == NSNotFound) {
return nil;
}
index++;
if (index == [self.photoIDs count]) {
return nil;
}
return [self viewControllerAtIndex:index storyboard:viewController.storyboard];
}
@end
OK. So that is the Photo Page Model Controller.
The Page View Controller
Next for the PhotoPageViewController
.
PhotoPageViewController.h
#import <Foundation/Foundation.h>
@interface PhotoPageViewController : UIPageViewController
@property (nonatomic, strong) NSArray *photos;
@property (nonatomic) NSUInteger initialIndex;
@end
PhotoPageViewController.m
#import "PhotoPageViewController.h"
#import "PhotoPageModelController.h"
@interface PhotoPageViewController ()
// this property is connected in the storyboard
@property (nonatomic, weak) IBOutlet PhotoPageModelController *modelController;
@end
@implementation PhotoPageViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.modelController.photos = self.photos;
// We use the initialIndex property to get the first controller and display it.
UIViewController *initialController = (UIViewController *)[self.modelController viewControllerAtIndex:self.initialIndex storyboard:self.storyboard];
[self setViewControllers:@[initialController]
direction:UIPageViewControllerNavigationDirectionForward
animated:NO
completion:^(BOOL finished) {
}];
// That's it. Because we have the datasource class it makes this class really easy and short.
// It doesn't even need to know anything about the view controllers it is displaying.
// It's just a dispensing machine.
}
@end
The Photo View Controller
Next is the view controller that will display the actual photo.
All it needs is a property of type UIImage
called photo
and then a UIImageView
to place it in. I'll leave this up to you as you can do it many different ways.
I've put a zoomable UIScrollView
in mine so that the user can pinch zoom the photo. I've also got some extra info such as the name of the person who took the photo and the date it was taken etc... Set this up however you like.
The collection view segue
The final part (at last) is going from the collection view to the page view controller.
This is done in prepareForSegue
.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:@"PhotoSegue"]) {
PhotoPageViewController *controller = segue.destinationViewController;
NSIndexPath *selectedIndex = [self.collectionView indexPathsForSelectedItems][0];
// The PageViewController doesn't need anything except the index to start on...
// i.e. the index of the photo that the user just selected.
controller.initialIndex = (NSUInteger)selectedIndex.item;
// ...and the array of photos it will be displaying.
controller.photos = self.photos;
// Everything else is done by the PageViewController.
}
}
来源:https://stackoverflow.com/questions/18084002/correct-way-to-transition-between-collection-view-and-paged-detail-view