Правильный способ перехода между представлением коллекции и представлением с разбивкой по страницам
В настоящее время у меня есть вид uicollection, который отображает конкретный альбом на фотографиях пользователей (библиотека ALAssets).
В моем mainView.m я собираю фотографии:
+ (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");}
];
}
Загрузите их (уменьшенная версия) все в представление коллекции, и все это работает хорошо.
Затем, когда пользователь выбирает фотографию, я вызываю этот метод prepareToSegue: (все еще в 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;
}
В настоящее время я отправляю массив с информацией о фотографиях и пытаюсь прокрутить до позиции в массиве.
Я нашел этот ресурс здесь для горизонтальной подкачки:
http://adoptioncurve.net/archives/2013/04/creating-a-paged-photo-gallery-with-a-uicollectionview/
Что позволяет для подкачки с использованием представления коллекции. Я написал, что класс detailViewController.
Вот вопрос. Как мне соединить два?
Идея 1. Пусть мой mainView отправит целое число, представляющее выбранную фотографию, а затем detailViewController загрузит ее и начнет лениво загружать фотографии.
Идея 2: Каким-то образом предварительно загрузить некоторые полноэкранные фотографии, а затем отправить целое число с местом в массиве.
Идея 3: Отправить и число, и мой объект массива в detailViewController, чтобы мне больше не приходилось перечислять библиотеку ресурсов.
Являются ли какие-либо из них правильным подходом или я полностью упустил идею?
редактировать:
В моем подробном контроллере есть макет потока uicollectionview с включенной подкачкой страниц. Это метод, в котором я настроил макет:
- (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];
}
Что он должен сделать, это взять значение из моего основного вида и перейти к этому изображению. К сожалению это не так. Я не уверен, почему, а также я чувствую, что есть лучший способ сделать это. Это просто похоже на хакиш.
Как мне лучше соединить два более качественных контроллера и как правильно загрузить фотографии / как мне добраться до фотографии (в полноразмерном подробном виде), на которой я работал, когда они были в макете сетки.
Помощь приветствуется.
1 ответ
ОК, здесь есть три части.
Во-первых UICollectionViewController
подкласс для отображения галереи фотографий (UIImage
). Второе UIPageViewController
подкласс, чтобы управлять смахиванием из стороны в сторону каждого человека PhotoViewController
, В-третьих, это UIViewController
подкласс (PhotoViewController
), чтобы отобразить одну фотографию.
Раскадровка будет выглядеть примерно так...
Слева находится UICollectionViewController
это имеет отношение к UIPageViewController
в середине. Справа находится UIViewController
это имеет Identifier
установить в панели свойств (обратите внимание, нет никакого перехода к этому).
Идентификатор для PhotoViewController
...
в PhotoPageViewController
У меня есть пользовательский объект...
С типом класса PhotoPageModelController
установить в панели свойств... Это связано как источник данных PhotoPageViewController
,
Это почти все, что нужно для создания раскадровки.
Итак, первое, что нужно настроить, это PhotoPageModelController
, Это источник данных для PhotoPageViewController
как таковой будет распределять подклассы UIViewController
таким образом PhotoPageViewController
может отображать их.
Контроллер модели
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
ХОРОШО. Так что это контроллер модели страницы фотографий.
Контроллер просмотра страницы
Далее для 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
Контроллер просмотра фотографий
Следующим является контроллер вида, который будет отображать фактическую фотографию.
Все, что ему нужно, это свойство типа UIImage
называется photo
а затем UIImageView
поместить это в. Я оставлю это на ваше усмотрение, так как вы можете сделать это разными способами.
Я поставил масштабируемый UIScrollView
в моем, так что пользователь может ущипнуть масштабировать фотографию. У меня также есть некоторая дополнительная информация, такая как имя человека, который сделал фотографию, и дата, когда она была сделана и т. Д. Установите это так, как вам нравится.
Коллекция View Segue
Последняя часть (наконец) идет от представления коллекции к контроллеру представления страницы.
Это сделано в 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.
}
}