Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for custom header views #379

Merged
merged 5 commits into from
Jan 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Example/WPMediaPicker.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
objects = {

/* Begin PBXBuildFile section */
173B215327873F2E00D4DD6B /* SampleCustomHeaderView.m in Sources */ = {isa = PBXBuildFile; fileRef = 173B215227873F2E00D4DD6B /* SampleCustomHeaderView.m */; };
17475FB81FB46DED00252689 /* SampleCellOverlayView.m in Sources */ = {isa = PBXBuildFile; fileRef = 17475FB71FB46DED00252689 /* SampleCellOverlayView.m */; };
17F64FE01E6DDC74006C5A2B /* CustomPreviewViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 17F64FDF1E6DDC74006C5A2B /* CustomPreviewViewController.m */; };
6003F58E195388D20070C39A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58D195388D20070C39A /* Foundation.framework */; };
Expand Down Expand Up @@ -42,6 +43,8 @@

/* Begin PBXFileReference section */
1120051BDDDC8A558883872E /* Pods-WPMediaPicker.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WPMediaPicker.release.xcconfig"; path = "Pods/Target Support Files/Pods-WPMediaPicker/Pods-WPMediaPicker.release.xcconfig"; sourceTree = "<group>"; };
173B215127873F2E00D4DD6B /* SampleCustomHeaderView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SampleCustomHeaderView.h; sourceTree = "<group>"; };
173B215227873F2E00D4DD6B /* SampleCustomHeaderView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SampleCustomHeaderView.m; sourceTree = "<group>"; };
17475FB61FB46DED00252689 /* SampleCellOverlayView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SampleCellOverlayView.h; sourceTree = "<group>"; };
17475FB71FB46DED00252689 /* SampleCellOverlayView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SampleCellOverlayView.m; sourceTree = "<group>"; };
17F64FDE1E6DDC74006C5A2B /* CustomPreviewViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CustomPreviewViewController.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -155,6 +158,8 @@
17F64FDF1E6DDC74006C5A2B /* CustomPreviewViewController.m */,
17475FB61FB46DED00252689 /* SampleCellOverlayView.h */,
17475FB71FB46DED00252689 /* SampleCellOverlayView.m */,
173B215127873F2E00D4DD6B /* SampleCustomHeaderView.h */,
173B215227873F2E00D4DD6B /* SampleCustomHeaderView.m */,
6003F59C195388D20070C39A /* AppDelegate.h */,
6003F59D195388D20070C39A /* AppDelegate.m */,
6003F5A8195388D20070C39A /* Images.xcassets */,
Expand Down Expand Up @@ -387,6 +392,7 @@
B5FF3BEA1CAD8AB100C1D597 /* PostProcessingViewController.m in Sources */,
6003F59E195388D20070C39A /* AppDelegate.m in Sources */,
17475FB81FB46DED00252689 /* SampleCellOverlayView.m in Sources */,
173B215327873F2E00D4DD6B /* SampleCustomHeaderView.m in Sources */,
FF355D9E1FB5EB4A00244E6D /* WPPHAssetDataSource+Search.m in Sources */,
FFFFD8811A447E67000FC184 /* DemoViewController.m in Sources */,
6003F59A195388D20070C39A /* main.m in Sources */,
Expand Down
28 changes: 27 additions & 1 deletion Example/WPMediaPicker/DemoViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
#import "OptionsViewController.h"
#import "PostProcessingViewController.h"
#import "SampleCellOverlayView.h"
#import "SampleCustomHeaderView.h"
#import <WPMediaPicker/WPMediaPicker.h>

@import MobileCoreServices;

static CGFloat const CellHeight = 100.0f;
Expand Down Expand Up @@ -51,7 +53,8 @@ - (void)viewDidLoad
MediaPickerOptionsCustomPreview:@(NO),
MediaPickerOptionsScrollInputPickerVertically:@(YES),
MediaPickerOptionsShowSampleCellOverlays:@(NO),
MediaPickerOptionsShowSearchBar:@(YES)
MediaPickerOptionsShowSearchBar:@(YES),
MediaPickerOptionsShowCustomHeader:@(NO)
};

}
Expand Down Expand Up @@ -252,6 +255,25 @@ - (BOOL)mediaPickerController:(nonnull WPMediaPickerViewController *)picker hand
return error.domain != WPMediaPickerErrorDomain;
}

- (void)mediaPickerController:(WPMediaPickerViewController *)picker configureCustomHeaderView:(UICollectionReusableView *)headerView {
if (![headerView isKindOfClass:[SampleCustomHeaderView class]]) {
return;
}

SampleCustomHeaderView *view = (SampleCustomHeaderView *)headerView;
view.backgroundColor = [UIColor greenColor];
}

- (BOOL)mediaPickerControllerShouldShowCustomHeaderView:(WPMediaPickerViewController *)picker
{
return [self.options[MediaPickerOptionsShowCustomHeader] boolValue] == YES;
}

- (CGSize)mediaPickerControllerReferenceSizeForCustomHeaderView:(WPMediaPickerViewController *)picker
{
return CGSizeMake(300, 200);
}

#pragma - Actions

- (void) clearSelection:(id) sender
Expand Down Expand Up @@ -293,6 +315,10 @@ - (void)showPicker:(id) sender
if ([self.options[MediaPickerOptionsShowSampleCellOverlays] boolValue]) {
[self.mediaPicker.mediaPicker registerClassForReusableCellOverlayViews:[SampleCellOverlayView class]];
}

if ([self.options[MediaPickerOptionsShowCustomHeader] boolValue]) {
[self.mediaPicker.mediaPicker registerClassForCustomHeaderView:[SampleCustomHeaderView class]];
}

[self presentViewController:self.mediaPicker animated:YES completion:nil];
[self.quickInputTextField resignFirstResponder];
Expand Down
3 changes: 3 additions & 0 deletions Example/WPMediaPicker/OptionsViewController.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ extern NSString const *MediaPickerOptionsScrollInputPickerVertically;
extern NSString const *MediaPickerOptionsShowSampleCellOverlays;
extern NSString const *MediaPickerOptionsShowSearchBar;
extern NSString const *MediaPickerOptionsShowActionBar;
/// Note that a custom header cannot be displayed at the same time as the in-picker camera capture cell.
/// If both are specified, the custom header will take precedence.
extern NSString const *MediaPickerOptionsShowCustomHeader;

@class OptionsViewController;

Expand Down
15 changes: 14 additions & 1 deletion Example/WPMediaPicker/OptionsViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
NSString const *MediaPickerOptionsShowSampleCellOverlays = @"MediaPickerOptionsShowSampleCellOverlays";
NSString const *MediaPickerOptionsShowSearchBar = @"MediaPickerOptionsShowSearchBar";
NSString const *MediaPickerOptionsShowActionBar = @"MediaPickerOptionsShowActionBar";
NSString const *MediaPickerOptionsShowCustomHeader = @"MediaPickerOptionsShowCustomHeader";


typedef NS_ENUM(NSInteger, OptionsViewControllerCell){
Expand All @@ -27,6 +28,7 @@ typedef NS_ENUM(NSInteger, OptionsViewControllerCell){
OptionsViewControllerCellShowSampleCellOverlays,
OptionsViewControllerCellShowSearchBar,
OptionsViewControllerCellShowActionBar,
OptionsViewControllerCellShowCustomHeader,
OptionsViewControllerCellTotal
};

Expand All @@ -43,6 +45,7 @@ @interface OptionsViewController ()
@property (nonatomic, strong) UITableViewCell *cellOverlaysCell;
@property (nonatomic, strong) UITableViewCell *showSearchBarCell;
@property (nonatomic, strong) UITableViewCell *showActionBarCell;
@property (nonatomic, strong) UITableViewCell *showCustomHeaderCell;

@end

Expand Down Expand Up @@ -119,6 +122,13 @@ - (void)viewDidLoad
self.showActionBarCell.accessoryView = [[UISwitch alloc] init];
((UISwitch *)self.showActionBarCell.accessoryView).on = [self.options[MediaPickerOptionsShowActionBar] boolValue];
self.showActionBarCell.textLabel.text = NSLocalizedString(@"Show Action Bar", @"");

self.showCustomHeaderCell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:nil];
self.showCustomHeaderCell.accessoryView = [[UISwitch alloc] init];
((UISwitch *)self.showCustomHeaderCell.accessoryView).on = [self.options[MediaPickerOptionsShowCustomHeader] boolValue];
self.showCustomHeaderCell.textLabel.text = NSLocalizedString(@"Show Custom Header", @"");
self.showCustomHeaderCell.detailTextLabel.text = NSLocalizedString(@"If custom header and capture cell are enabled, custom header takes precedence.", @"");
self.showCustomHeaderCell.detailTextLabel.numberOfLines = 2;
}

#pragma mark - Table view data source
Expand Down Expand Up @@ -166,6 +176,8 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N
return self.showSearchBarCell;
case OptionsViewControllerCellShowActionBar:
return self.showActionBarCell;
case OptionsViewControllerCellShowCustomHeader:
return self.showCustomHeaderCell;
default:
break;
}
Expand Down Expand Up @@ -195,7 +207,8 @@ - (void)done:(id) sender
MediaPickerOptionsScrollInputPickerVertically:@(((UISwitch *)self.scrollInputPickerCell.accessoryView).on),
MediaPickerOptionsShowSampleCellOverlays:@(((UISwitch *)self.cellOverlaysCell.accessoryView).on),
MediaPickerOptionsShowSearchBar:@(((UISwitch *)self.showSearchBarCell.accessoryView).on),
MediaPickerOptionsShowActionBar:@(((UISwitch *)self.showActionBarCell.accessoryView).on)
MediaPickerOptionsShowActionBar:@(((UISwitch *)self.showActionBarCell.accessoryView).on),
MediaPickerOptionsShowCustomHeader:@(((UISwitch *)self.showCustomHeaderCell.accessoryView).on)
};

[delegate optionsViewController:self changed:newOptions];
Expand Down
9 changes: 9 additions & 0 deletions Example/WPMediaPicker/SampleCustomHeaderView.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface SampleCustomHeaderView : UICollectionReusableView

@end

NS_ASSUME_NONNULL_END
36 changes: 36 additions & 0 deletions Example/WPMediaPicker/SampleCustomHeaderView.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#import "SampleCustomHeaderView.h"

@implementation SampleCustomHeaderView

- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
[self commonInit];
}
return self;
}

- (id)initWithCoder:(NSCoder *)aDecoder
{
if (self = [super initWithCoder:aDecoder]) {
[self commonInit];
}
return self;
}

- (void)commonInit
{
self.backgroundColor = [UIColor redColor];

UILabel *label = [UILabel new];
label.translatesAutoresizingMaskIntoConstraints = NO;
label.text = NSLocalizedString(@"Custom Header", @"");
[self addSubview:label];

[NSLayoutConstraint activateConstraints:@[
[label.centerXAnchor constraintEqualToAnchor:self.centerXAnchor],
[label.centerYAnchor constraintEqualToAnchor:self.centerYAnchor]
]];
}

@end
36 changes: 35 additions & 1 deletion Pod/Classes/WPMediaPickerViewController.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@
/**
* Asks the delegate whether an overlay view should be shown for the cell for
* the specified media asset. If you return `YES` from this method, you must
* have registered a reuse class though `-[WPMediaPickerViewController registerClassForReusableCellOverlayViews:]`.
* have registered a reuse class through `-[WPMediaPickerViewController registerClassForReusableCellOverlayViews:]`.
*
* @param asset The asset to display an overlay view for.
* @return `YES` if an overlay view should be displayed, `NO`, if not.
Expand All @@ -178,6 +178,33 @@
*/
- (void)mediaPickerController:(nonnull WPMediaPickerViewController *)picker willShowOverlayView:(nonnull UIView *)overlayView forCellForAsset:(nonnull id<WPMediaAsset>)asset;

/**
* Asks the delegate to configure a custom header view. You must have registered a reuse class
* through `-[WPMediaPickerViewController registerClassForCustomHeaderView:]` and returned `YES`
* from `mediaPickerControllerShouldShowCustomHeaderView` otherwise this method will not be called.
*
* @param picker The controller object managing the assets picker interface.
* @param headerView An instance of the custom header view type to configure.
*/
- (void)mediaPickerController:(nonnull WPMediaPickerViewController *)picker configureCustomHeaderView:(nonnull UICollectionReusableView *)headerView;

/**
* Asks the delegate whether a custom header view should be displayed.
*
* @param picker The controller object managing the assets picker interface.
* @return `YES` if a custom header view should be shown, otherwise `NO`.
*/
- (BOOL)mediaPickerControllerShouldShowCustomHeaderView:(nonnull WPMediaPickerViewController *)picker;

/**
* Asks the delegate for a reference size for the registered custom header view, if one has been registered. This will only be called
* if `mediaPickerControllerShouldShowCustomHeaderView` has been implemented and returns `YES`.
*
* @param picker The controller object managing the assets picker interface.
* @return A size for the header view to be displayed at.
*/
- (CGSize)mediaPickerControllerReferenceSizeForCustomHeaderView:(nonnull WPMediaPickerViewController *)picker;

/**
* Gives the delegate an oportunity to react to a change in the number
* of assets displayed as a consequence of a search filter.
Expand Down Expand Up @@ -341,6 +368,13 @@
*/
- (void)registerClassForReusableCellOverlayViews:(nonnull Class)overlayClass;

/**
Register a `UICollectionReusableView` subclass to be displayed as an optional header at the top of the picker view.
For the header to be displayed, you must register a class using this method, and then
return a configured instance from `customHeaderViewForMediaPickerController:`
*/
- (void)registerClassForCustomHeaderView:(nonnull Class)overlayClass;

/**
Shows the search bar that was hidden by `hideSearchBar`. If the
`showSearchBar` option is set to `NO`, and the data source does not implement
Expand Down
34 changes: 34 additions & 0 deletions Pod/Classes/WPMediaPickerViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
static CGFloat const IPadPortraitWidth = 768.0f;
static CGFloat const IPadLandscapeWidth = 1024.0f;
static CGFloat const IPadPro12LandscapeWidth = 1366.0f;
static NSString *const CustomHeaderReuseIdentifier = @"CustomHeaderReuseIdentifier";

@interface WPMediaPickerViewController ()
<
Expand Down Expand Up @@ -183,6 +184,15 @@ - (void)registerClassForReusableCellOverlayViews:(Class)overlayClass
self.overlayViewClass = overlayClass;
}

- (void)registerClassForCustomHeaderView:(Class)overlayClass
{
NSParameterAssert([overlayClass isSubclassOfClass:[UICollectionReusableView class]]);

[self.collectionView registerClass:overlayClass
forSupplementaryViewOfKind:UICollectionElementKindSectionHeader
withReuseIdentifier:CustomHeaderReuseIdentifier];
}

- (UICollectionViewFlowLayout *)layout
{
return (UICollectionViewFlowLayout *)self.collectionView.collectionViewLayout;
Expand Down Expand Up @@ -935,6 +945,12 @@ - (CGSize)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)collectionViewLayout
referenceSizeForHeaderInSection:(NSInteger)section
{
if ([self shouldShowCustomHeaderView]) {
if ([self.mediaPickerDelegate respondsToSelector:@selector(mediaPickerControllerReferenceSizeForCustomHeaderView:)]) {
return [self.mediaPickerDelegate mediaPickerControllerReferenceSizeForCustomHeaderView:self];
}
}

if ( [self isShowingCaptureCell] && self.options.showMostRecentFirst)
{
return self.cameraPreviewSize;
Expand All @@ -957,6 +973,15 @@ - (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView
viewForSupplementaryElementOfKind:(NSString *)kind
atIndexPath:(NSIndexPath *)indexPath
{
// Custom header view support
if (kind == UICollectionElementKindSectionHeader && [self shouldShowCustomHeaderView]) {
if ([self.mediaPickerDelegate respondsToSelector:@selector(mediaPickerController:configureCustomHeaderView:)]) {
UICollectionReusableView *view = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:CustomHeaderReuseIdentifier forIndexPath:indexPath];
[self.mediaPickerDelegate mediaPickerController:self configureCustomHeaderView:view];
return view;
}
}

if ((kind == UICollectionElementKindSectionHeader && self.options.showMostRecentFirst) ||
(kind == UICollectionElementKindSectionFooter && !self.options.showMostRecentFirst))
{
Expand Down Expand Up @@ -1000,6 +1025,15 @@ - (void)collectionView:(UICollectionView *)collectionView didEndDisplayingCell:(
}
}

- (BOOL)shouldShowCustomHeaderView
{
if ([self.mediaPickerDelegate respondsToSelector:@selector(mediaPickerControllerShouldShowCustomHeaderView:)]) {
return [self.mediaPickerDelegate mediaPickerControllerShouldShowCustomHeaderView:self];
}

return NO;
}

/**
Returns the position of the asset in the current selection if any

Expand Down
25 changes: 25 additions & 0 deletions Pod/Classes/WPNavigationMediaPickerViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,31 @@ - (void)mediaPickerController:(WPMediaPickerViewController *)picker willShowOver
}
}

- (BOOL)mediaPickerControllerShouldShowCustomHeaderView:(WPMediaPickerViewController *)picker
{
if ([self.delegate respondsToSelector:@selector(mediaPickerControllerShouldShowCustomHeaderView:)]) {
return [self.delegate mediaPickerControllerShouldShowCustomHeaderView:picker];
}

return NO;
}

- (CGSize)mediaPickerControllerReferenceSizeForCustomHeaderView:(WPMediaPickerViewController *)picker
{
if ([self.delegate respondsToSelector:@selector(mediaPickerControllerReferenceSizeForCustomHeaderView:)]) {
return [self.delegate mediaPickerControllerReferenceSizeForCustomHeaderView:picker];
}

return CGSizeZero;
}

- (void)mediaPickerController:(WPMediaPickerViewController *)picker configureCustomHeaderView:(UICollectionReusableView *)headerView
{
if ([self.delegate respondsToSelector:@selector(mediaPickerController:configureCustomHeaderView:)]) {
[self.delegate mediaPickerController:picker configureCustomHeaderView:headerView];
}
}

- (nullable UIViewController *)mediaPickerController:(WPMediaPickerViewController *)picker previewViewControllerForAssets:(nonnull NSArray<id<WPMediaAsset>> *)assets selectedIndex:(NSInteger)selected {
UIViewController *previewVC;
if ([self.delegate respondsToSelector:@selector(mediaPickerController:previewViewControllerForAssets:selectedIndex:)]) {
Expand Down
2 changes: 1 addition & 1 deletion WPMediaPicker.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Pod::Spec.new do |s|
s.name = 'WPMediaPicker'
s.version = '1.8.1'
s.version = '1.8.2-beta.1'

s.summary = 'WPMediaPicker is an iOS controller that allows capture and picking of media assets.'
s.description = <<-DESC
Expand Down