Skip to content

Commit

Permalink
Merge pull request #379 from wordpress-mobile/feature/custom-header-view
Browse files Browse the repository at this point in the history
Add support for custom header views
  • Loading branch information
frosty authored Jan 14, 2022
2 parents 751b604 + 8e14480 commit 3074b3f
Show file tree
Hide file tree
Showing 10 changed files with 190 additions and 4 deletions.
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

0 comments on commit 3074b3f

Please sign in to comment.