美文网首页iOS DeveloperiOS 开发
用PageFlow实现类似App Store中截图查看的效果

用PageFlow实现类似App Store中截图查看的效果

作者: 海边的遐想 | 来源:发表于2016-06-29 15:51 被阅读503次

首先在pageFlow.h中定义

#import <UIKit/UIKit.h>

@protocol PagedFlowViewDataSource;

@protocol PagedFlowViewDelegate;

typedef enum{

PagedFlowViewOrientationHorizontal = 0,

PagedFlowViewOrientationVertical

}PagedFlowViewOrientation;

typedef enum{    PagedFlowViewOrientationHorizontal = 0,              PagedFlowViewOrientationVertical

}PagedFlowViewOrientation;

@interface PageFlow : UIView<UIScrollViewDelegate>{        

PagedFlowViewOrientation orientation;//默认为横向    

    UIScrollView        *_scrollView;  

  BOOL                _needsReload;  

  CGSize              _pageSize; //一页的尺寸    

NSInteger          _pageCount;  //总页数    

NSInteger          _currentPageIndex;    

    NSMutableArray      *_cells;   

 NSRange              _visibleRange;  

  NSMutableArray      *_reusableCells;//如果以后需要支持reuseIdentifier,这边就得使用字典类型了        UIPageControl      *pageControl; //可以是自己自定义的PageControl       

 //如果希望非当前页的大小或者透明度发生变化可以设置这两个值  

  CGFloat _minimumPageAlpha;  

  CGFloat _minimumPageScale;

}

@property(nonatomic,assign)  iddataSource;

@property(nonatomic,assign)  iddelegate;

@property(nonatomic,retain)    UIPageControl      *pageControl;

@property (nonatomic, assign) CGFloat minimumPageAlpha;

@property (nonatomic, assign) CGFloat minimumPageScale;

@property (nonatomic, assign) PagedFlowViewOrientation orientation;

@property (nonatomic, assign, readonly) NSInteger currentPageIndex;

- (void)reloadData;//获取可重复使用的Cell

- (UIView *)dequeueReusableCell;

- (void)scrollToPage:(NSUInteger)pageNumber;

@end@protocol  PagedFlowViewDelegate

- (CGSize)sizeForPageInFlowView:(PageFlow *)flowView;

@optional

- (void)didScrollToPage:(NSInteger)pageNumber inFlowView:(PageFlow *)flowView;

@end

@protocol PagedFlowViewDataSource//返回显示View的个数

- (NSInteger)numberOfPagesInFlowView:(PageFlow *)flowView;

//返回给某列使用的View

- (UIView *)flowView:(PageFlow *)flowView cellForPageAtIndex:(NSInteger)index;

@end

在.m文件中需要填写

#import "PageFlow.h"

@interface PageFlow()

@property (nonatomic, assign, readwrite) NSInteger currentPageIndex;

@end

@implementation PageFlow

@synthesize pageControl;

@synthesize minimumPageAlpha = _minimumPageAlpha;

@synthesize minimumPageScale = _minimumPageScale;

@synthesize orientation;

@synthesize currentPageIndex = _currentPageIndex;

////////////////////////////////////////////////////////////////////////////////////////////////////

#pragma mark -

#pragma mark Private Methods

- (void)initialize{

self.clipsToBounds = YES;

_needsReload = YES;

_pageSize = self.bounds.size;

_pageCount = 0;

_currentPageIndex = 0;

_minimumPageAlpha = 1.0;

_minimumPageScale = 1.0;

_visibleRange = NSMakeRange(0, 0);

_reusableCells = [[NSMutableArray alloc] initWithCapacity:0];

_cells = [[NSMutableArray alloc] initWithCapacity:0];

_scrollView = [[UIScrollView alloc] initWithFrame:self.bounds];

_scrollView.delegate = self;

_scrollView.pagingEnabled = YES;

_scrollView.clipsToBounds = NO;

_scrollView.showsHorizontalScrollIndicator = NO;

_scrollView.showsVerticalScrollIndicator = NO;

/*由于UIScrollView在滚动之后会调用自己的layoutSubviews以及父View的layoutSubviews

这里为了避免scrollview滚动带来自己layoutSubviews的调用,所以给scrollView加了一层父View

*/

UIView *superViewOfScrollView = [[UIView alloc] initWithFrame:self.bounds];

[superViewOfScrollView setAutoresizingMask:UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight];

[superViewOfScrollView setBackgroundColor:[UIColor clearColor]];

[superViewOfScrollView addSubview:_scrollView];

[self addSubview:superViewOfScrollView];

}

- (void)queueReusableCell:(UIView *)cell{

[_reusableCells addObject:cell];

}

- (void)removeCellAtIndex:(NSInteger)index{

UIView *cell = [_cells objectAtIndex:index];

if ((NSObject *)cell == [NSNull null]) {

return;

}

[self queueReusableCell:cell];

if (cell.superview) {

[cell removeFromSuperview];

}

[_cells replaceObjectAtIndex:index withObject:[NSNull null]];

}

- (void)refreshVisibleCellAppearance{

if (_minimumPageAlpha == 1.0 && _minimumPageScale == 1.0) {

return;//无需更新

}

switch (orientation) {

case PagedFlowViewOrientationHorizontal:{

CGFloat offset = _scrollView.contentOffset.x;

for (NSInteger i = _visibleRange.location; i < _visibleRange.location + _visibleRange.length; i++) {

UIView *cell = [_cells objectAtIndex:i];

CGFloat origin = cell.frame.origin.x;

CGFloat delta = fabs(origin - offset);

CGRect originCellFrame = CGRectMake(_pageSize.width * i, 0, _pageSize.width, _pageSize.height);//如果没有缩小效果的情况下的本该的Frame

[UIView beginAnimations:@"CellAnimation" context:nil];

if (delta < _pageSize.width) {

cell.alpha = 1 - (delta / _pageSize.width) * (1 - _minimumPageAlpha);

CGFloat inset = (_pageSize.width * (1 - _minimumPageScale)) * (delta / _pageSize.width)/2.0;

cell.frame = UIEdgeInsetsInsetRect(originCellFrame, UIEdgeInsetsMake(inset, inset, inset, inset));

} else {

cell.alpha = _minimumPageAlpha;

CGFloat inset = _pageSize.width * (1 - _minimumPageScale) / 2.0 ;

cell.frame = UIEdgeInsetsInsetRect(originCellFrame, UIEdgeInsetsMake(inset, inset, inset, inset));

}

[UIView commitAnimations];

}

break;

}

case PagedFlowViewOrientationVertical:{

CGFloat offset = _scrollView.contentOffset.y;

for (NSInteger i = _visibleRange.location; i < _visibleRange.location + _visibleRange.length; i++) {

UIView *cell = [_cells objectAtIndex:i];

CGFloat origin = cell.frame.origin.y;

CGFloat delta = fabs(origin - offset);

CGRect originCellFrame = CGRectMake(0, _pageSize.height * i, _pageSize.width, _pageSize.height);//如果没有缩小效果的情况下的本该的Frame

[UIView beginAnimations:@"CellAnimation" context:nil];

if (delta < _pageSize.height) {

cell.alpha = 1 - (delta / _pageSize.height) * (1 - _minimumPageAlpha);

CGFloat inset = (_pageSize.height * (1 - _minimumPageScale)) * (delta / _pageSize.height)/2.0;

cell.frame = UIEdgeInsetsInsetRect(originCellFrame, UIEdgeInsetsMake(inset, inset, inset, inset));

} else {

cell.alpha = _minimumPageAlpha;

CGFloat inset = _pageSize.height * (1 - _minimumPageScale) / 2.0 ;

cell.frame = UIEdgeInsetsInsetRect(originCellFrame, UIEdgeInsetsMake(inset, inset, inset, inset));

}

[UIView commitAnimations];

}

}

default:

break;

}

}

- (void)setPageAtIndex:(NSInteger)pageIndex{

NSParameterAssert(pageIndex >= 0 && pageIndex < [_cells count]);

UIView *cell = [_cells objectAtIndex:pageIndex];

if ((NSObject *)cell == [NSNull null]) {

cell = [_dataSource flowView:self cellForPageAtIndex:pageIndex];

NSAssert(cell!=nil, @"datasource must not return nil");

[_cells replaceObjectAtIndex:pageIndex withObject:cell];

switch (orientation) {

case PagedFlowViewOrientationHorizontal:

cell.frame = CGRectMake(_pageSize.width * pageIndex, 0, _pageSize.width, _pageSize.height);

break;

case PagedFlowViewOrientationVertical:

cell.frame = CGRectMake(0, _pageSize.height * pageIndex, _pageSize.width, _pageSize.height);

break;

default:

break;

}

if (!cell.superview) {

[_scrollView addSubview:cell];

}

}

}

- (void)setPagesAtContentOffset:(CGPoint)offset{

//计算_visibleRange

CGPoint startPoint = CGPointMake(offset.x - _scrollView.frame.origin.x, offset.y - _scrollView.frame.origin.y);

CGPoint endPoint = CGPointMake(startPoint.x + self.bounds.size.width, startPoint.y + self.bounds.size.height);

switch (orientation) {

case PagedFlowViewOrientationHorizontal:{

NSInteger startIndex = 0;

for (int i =0; i < [_cells count]; i++) {

if (_pageSize.width * (i +1) > startPoint.x) {

startIndex = i;

break;

}

}

NSInteger endIndex = startIndex;

for (NSInteger i = startIndex; i < [_cells count]; i++) {

//如果都不超过则取最后一个

if ((_pageSize.width * (i + 1) < endPoint.x && _pageSize.width * (i + 2) >= endPoint.x) || i+ 2 == [_cells count]) {

endIndex = i + 1;//i+2 是以个数,所以其index需要减去1

break;

}

}

//可见页分别向前向后扩展一个,提高效率

startIndex = MAX(startIndex - 1, 0);

endIndex = MIN(endIndex + 1, [_cells count] - 1);

_visibleRange.location = startIndex;

_visibleRange.length = endIndex - startIndex + 1;

for (NSInteger i = startIndex; i <= endIndex; i++) {

[self setPageAtIndex:i];

}

for (int i = 0; i < startIndex; i ++) {

[self removeCellAtIndex:i];

}

for (NSInteger i = endIndex + 1; i < [_cells count]; i ++) {

[self removeCellAtIndex:i];

}

break;

}

case PagedFlowViewOrientationVertical:{

NSInteger startIndex = 0;

for (int i =0; i < [_cells count]; i++) {

if (_pageSize.height * (i +1) > startPoint.y) {

startIndex = i;

break;

}

}

NSInteger endIndex = startIndex;

for (NSInteger i = startIndex; i < [_cells count]; i++) {

//如果都不超过则取最后一个

if ((_pageSize.height * (i + 1) < endPoint.y && _pageSize.height * (i + 2) >= endPoint.y) || i+ 2 == [_cells count]) {

endIndex = i + 1;//i+2 是以个数,所以其index需要减去1

break;

}

}

//可见页分别向前向后扩展一个,提高效率

startIndex = MAX(startIndex - 1, 0);

endIndex = MIN(endIndex + 1, [_cells count] - 1);

_visibleRange.location = startIndex;

_visibleRange.length = endIndex - startIndex + 1;

for (NSInteger i = startIndex; i <= endIndex; i++) {

[self setPageAtIndex:i];

}

for (int i = 0; i < startIndex; i ++) {

[self removeCellAtIndex:i];

}

for (NSInteger i = endIndex + 1; i < [_cells count]; i ++) {

[self removeCellAtIndex:i];

}

break;

}

default:

break;

}

}

////////////////////////////////////////////////////////////////////////////////////////////////////

#pragma mark -

#pragma mark Override Methods

- (id)initWithFrame:(CGRect)frame

{

self = [super initWithFrame:frame];

if (self)

{

[self initialize];

}

return self;

}

- (id)initWithCoder:(NSCoder *)aDecoder

{

self = [super initWithCoder:aDecoder];

if (self)

{

[self initialize];

}

return self;

}

- (void)layoutSubviews{

[super layoutSubviews];

if (_needsReload) {

//如果需要重新加载数据,则需要清空相关数据全部重新加载

//重置pageCount

if (_dataSource && [_dataSource respondsToSelector:@selector(numberOfPagesInFlowView:)]) {

_pageCount = [_dataSource numberOfPagesInFlowView:self];

if (pageControl && [pageControl respondsToSelector:@selector(setNumberOfPages:)]) {

[pageControl setNumberOfPages:_pageCount];

}

}

//重置pageWidth

if (_delegate && [_delegate respondsToSelector:@selector(sizeForPageInFlowView:)]) {

_pageSize = [_delegate sizeForPageInFlowView:self];

}

[_reusableCells removeAllObjects];

_visibleRange = NSMakeRange(0, 0);

//填充cells数组

[_cells removeAllObjects];

for (NSInteger index=0; index<_pageCount; index++)

{

[_cells addObject:[NSNull null]];

}

// 重置_scrollView的contentSize

switch (orientation) {

case PagedFlowViewOrientationHorizontal://横向

_scrollView.frame = CGRectMake(0, 0, _pageSize.width, _pageSize.height);

_scrollView.contentSize = CGSizeMake(_pageSize.width * _pageCount,_pageSize.height);

CGPoint theCenter = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds));

_scrollView.center = theCenter;

break;

case PagedFlowViewOrientationVertical:{

_scrollView.frame = CGRectMake(0, 0, _pageSize.width, _pageSize.height);

_scrollView.contentSize = CGSizeMake(_pageSize.width ,_pageSize.height * _pageCount);

CGPoint theCenter = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds));

_scrollView.center = theCenter;

break;

}

default:

break;

}

}

[self setPagesAtContentOffset:_scrollView.contentOffset];//根据当前scrollView的offset设置cell

[self refreshVisibleCellAppearance];//更新各个可见Cell的显示外貌

}

////////////////////////////////////////////////////////////////////////////////////////////////////

#pragma mark -

#pragma mark PagedFlowView API

- (void)reloadData

{

_needsReload = YES;

[self setNeedsLayout];

}

- (UIView *)dequeueReusableCell{

UIView *cell = [_reusableCells lastObject];

if (cell)

{

[_reusableCells removeLastObject];

}

return cell;

}

- (void)scrollToPage:(NSUInteger)pageNumber {

if (pageNumber < _pageCount) {

switch (orientation) {

case PagedFlowViewOrientationHorizontal:

[_scrollView setContentOffset:CGPointMake(_pageSize.width * pageNumber, 0) animated:YES];

break;

case PagedFlowViewOrientationVertical:

[_scrollView setContentOffset:CGPointMake(0, _pageSize.height * pageNumber) animated:YES];

break;

}

[self setPagesAtContentOffset:_scrollView.contentOffset];

[self refreshVisibleCellAppearance];

}

}

////////////////////////////////////////////////////////////////////////////////////////////////////

#pragma mark -

#pragma mark hitTest

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {

if ([self pointInside:point withEvent:event]) {

CGPoint newPoint = CGPointZero;

newPoint.x = point.x - _scrollView.frame.origin.x + _scrollView.contentOffset.x;

newPoint.y = point.y - _scrollView.frame.origin.y + _scrollView.contentOffset.y;

if ([_scrollView pointInside:newPoint withEvent:event]) {

return [_scrollView hitTest:newPoint withEvent:event];

}

return _scrollView;

}

return nil;

}

////////////////////////////////////////////////////////////////////////////////////////////////////

#pragma mark -

#pragma mark UIScrollView Delegate

- (void)scrollViewDidScroll:(UIScrollView *)scrollView{

[self setPagesAtContentOffset:scrollView.contentOffset];

[self refreshVisibleCellAppearance];

}

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{

//如果有PageControl,计算出当前页码,并对pageControl进行更新

NSInteger pageIndex;

switch (orientation) {

case PagedFlowViewOrientationHorizontal:

pageIndex = floor(_scrollView.contentOffset.x / _pageSize.width);

break;

case PagedFlowViewOrientationVertical:

pageIndex = floor(_scrollView.contentOffset.y / _pageSize.height);

break;

default:

break;

}

if (pageControl && [pageControl respondsToSelector:@selector(setCurrentPage:)]) {

[pageControl setCurrentPage:pageIndex];

}

if ([_delegate respondsToSelector:@selector(didScrollToPage:inFlowView:)] && _currentPageIndex != pageIndex) {

[_delegate didScrollToPage:pageIndex inFlowView:self];

}

_currentPageIndex = pageIndex;

}

@end

在需要使用的viewCOntroller.h中设置

#import "PageFlow.h"

@interface ViewController : UIViewController

@property (strong, nonatomic) IBOutlet UIPageControl *pageControl;

@property (strong, nonatomic) IBOutlet PageFlow *hFlowView;

@property (strong, nonatomic) IBOutlet PageFlow *vFlowView;

- (IBAction)pageControlValueChange:(id)sender;

@end

在.m文件中设置相应的修改:

#import@interface ViewController (){

NSArray *imageArray;

}

@end

@implementation ViewController

- (void)viewDidLoad {

[super viewDidLoad];

imageArray=[[NSArray alloc]initWithObjects:@"0.tiff",@"1.tiff",@"2.tiff",@"3.tiff",@"4.tiff",@"5.tiff",@"6.tiff",@"7.tiff", nil];

_hFlowView.delegate=self;

_hFlowView.dataSource=self;

_hFlowView.pageControl=_pageControl;

_hFlowView.minimumPageAlpha=0.3;

_hFlowView.minimumPageScale=0.9;

_vFlowView.delegate=self;

_vFlowView.dataSource=self;

_vFlowView.minimumPageScale=0.8;

_vFlowView.minimumPageAlpha=0.4;

_vFlowView.orientation=PagedFlowViewOrientationVertical;

}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation

{

// Return YES for supported orientations

return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);

}

-(CGSize)sizeForPageInFlowView:(PageFlow *)flowView{

return CGSizeMake(200, 150);

}

-(NSInteger)numberOfPagesInFlowView:(PageFlow *)flowView{

return [imageArray count];

}

-(UIView *)flowView:(PageFlow *)flowView cellForPageAtIndex:(NSInteger)index{

UIImageView *imageView=(UIImageView *)[flowView dequeueReusableCell];

if (!imageView) {

imageView=[[UIImageView alloc]init];

imageView.layer.cornerRadius=6;

imageView.layer.masksToBounds=YES;

}

imageView.image=[UIImage imageNamed:[imageArray objectAtIndex:index]];

return imageView;

}

- (void)didReceiveMemoryWarning {

[super didReceiveMemoryWarning];

// Dispose of any resources that can be recreated.

}

- (IBAction)pageControlValueChange:(id)sender {

UIPageControl *pageControl=sender;

[_hFlowView scrollToPage:pageControl.currentPage];

[_vFlowView scrollToPage:pageControl.currentPage];

}

相关文章

网友评论

    本文标题:用PageFlow实现类似App Store中截图查看的效果

    本文链接:https://www.haomeiwen.com/subject/malxjttx.html