327 lines
8.8 KiB
Objective-C
327 lines
8.8 KiB
Objective-C
//
|
||
// NTESPageView.m
|
||
// NIM
|
||
//
|
||
// Created by chris on 15/12/16.
|
||
// Copyright © 2015年 Netease. All rights reserved.
|
||
//
|
||
|
||
#import "NTESPageView.h"
|
||
|
||
@interface NTESPageScrollView : UIScrollView
|
||
|
||
@end
|
||
|
||
@interface NTESPageView ()
|
||
{
|
||
NSInteger _currentPage;
|
||
NSInteger _currentPageForRotation;
|
||
}
|
||
|
||
@property (nonatomic,strong) NSMutableArray *pages;
|
||
|
||
- (void)setupControls;
|
||
|
||
//重新载入的流程
|
||
- (void)calculatePageNumbers;
|
||
- (void)reloadPage;
|
||
- (void)raisePageIndexChangedDelegate;
|
||
@end
|
||
|
||
@implementation NTESPageView
|
||
|
||
- (id)initWithFrame:(CGRect)frame
|
||
{
|
||
self = [super initWithFrame:frame];
|
||
if (self)
|
||
{
|
||
[self setupControls];
|
||
}
|
||
return self;
|
||
}
|
||
|
||
- (id)initWithCoder:(NSCoder *)aDecoder
|
||
{
|
||
if (self = [super initWithCoder:aDecoder])
|
||
{
|
||
[self setupControls];
|
||
}
|
||
return self;
|
||
}
|
||
|
||
- (void)setFrame:(CGRect)frame{
|
||
CGFloat originalWidth = self.frame.size.width;
|
||
[super setFrame:frame];
|
||
if (originalWidth != frame.size.width) {
|
||
[self reloadData];
|
||
}
|
||
}
|
||
|
||
- (void)dealloc
|
||
{
|
||
_scrollView.delegate = nil;
|
||
}
|
||
|
||
- (void)layoutSubviews
|
||
{
|
||
[super layoutSubviews];
|
||
[_scrollView setFrame:self.bounds];
|
||
|
||
CGSize size = self.bounds.size;
|
||
[self.scrollView setContentSize:CGSizeMake(size.width * [self.pages count], size.height)];
|
||
for (NSInteger i = 0; i < [self.pages count]; i++)
|
||
{
|
||
id obj = [self.pages objectAtIndex:i];
|
||
if ([obj isKindOfClass:[UIView class]])
|
||
{
|
||
[(UIView *)obj setFrame:CGRectMake(size.width * i, 0, size.width, size.height)];
|
||
}
|
||
}
|
||
|
||
//CGSize size = self.bounds.size;
|
||
BOOL animation = NO;
|
||
if (self.pageViewDelegate && [self.pageViewDelegate respondsToSelector:@selector(needScrollAnimation)])
|
||
{
|
||
animation = [self.pageViewDelegate needScrollAnimation];
|
||
}
|
||
[self.scrollView scrollRectToVisible:CGRectMake(_currentPage * size.width, 0, size.width, size.height)
|
||
animated:animation];
|
||
|
||
}
|
||
|
||
- (void)setupControls
|
||
{
|
||
if (_scrollView == nil)
|
||
{
|
||
_scrollView = [[NTESPageScrollView alloc]initWithFrame:self.bounds];
|
||
_scrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
|
||
[self addSubview:_scrollView];
|
||
_scrollView.pagingEnabled = YES;
|
||
_scrollView.showsVerticalScrollIndicator = NO;
|
||
_scrollView.showsHorizontalScrollIndicator = NO;
|
||
_scrollView.delegate = self;
|
||
_scrollView.scrollsToTop = NO;
|
||
}
|
||
}
|
||
|
||
#pragma mark - 对外接口
|
||
- (void)scrollToPage: (NSInteger)page
|
||
{
|
||
if (_currentPage != page || page == 0)
|
||
{
|
||
_currentPage = page;
|
||
[self reloadData];
|
||
}
|
||
|
||
}
|
||
|
||
- (void)reloadData
|
||
{
|
||
[self calculatePageNumbers];
|
||
[self reloadPage];
|
||
}
|
||
|
||
- (UIView *)viewAtIndex: (NSInteger)index
|
||
{
|
||
UIView *view = nil;
|
||
if (index >= 0 && index < [_pages count])
|
||
{
|
||
id obj = [_pages objectAtIndex:index];
|
||
if ([obj isKindOfClass:[UIView class]])
|
||
{
|
||
view = obj;
|
||
}
|
||
}
|
||
return view;
|
||
}
|
||
|
||
- (NSInteger)currentPage
|
||
{
|
||
return _currentPage;
|
||
}
|
||
|
||
- (NSInteger)pageInBound:(NSInteger)value min:(NSInteger)min max:(NSInteger)max{
|
||
if (max < min) {
|
||
max = min;
|
||
}
|
||
NSInteger bounded = value;
|
||
if (bounded > max) {
|
||
bounded = max;
|
||
}
|
||
if (bounded < min) {
|
||
bounded = min;
|
||
}
|
||
return bounded;
|
||
}
|
||
|
||
#pragma mark - Page载入和销毁
|
||
- (void)loadPagesForCurrentPage:(NSInteger)currentPage
|
||
{
|
||
NSUInteger count = [_pages count];
|
||
if (count == 0)
|
||
{
|
||
return;
|
||
}
|
||
NSInteger first = [self pageInBound:currentPage - 1 min:0 max:count - 1];
|
||
NSInteger last = [self pageInBound:currentPage + 1 min:0 max:count - 1];
|
||
NSRange range = NSMakeRange(first, last - first + 1);
|
||
|
||
for (NSUInteger index = 0; index < count; index++)
|
||
{
|
||
if (NSLocationInRange(index, range))
|
||
{
|
||
id obj = [_pages objectAtIndex:index];
|
||
if (![obj isKindOfClass:[UIView class]])
|
||
{
|
||
if (_dataSource && [_dataSource respondsToSelector:@selector(pageView:viewInPage:)])
|
||
{
|
||
UIView *view = [_dataSource pageView:self viewInPage:index];
|
||
[_pages replaceObjectAtIndex:index withObject:view];
|
||
[self.scrollView addSubview:view];
|
||
CGSize size = self.bounds.size;
|
||
[view setFrame:CGRectMake(size.width * index, 0, size.width, size.height)];
|
||
}
|
||
else
|
||
{
|
||
assert(0);
|
||
}
|
||
}
|
||
|
||
}
|
||
else
|
||
{
|
||
id obj = [_pages objectAtIndex:index];
|
||
if ([obj isKindOfClass:[UIView class]])
|
||
{
|
||
[obj removeFromSuperview];
|
||
[_pages replaceObjectAtIndex:index withObject:[NSNull null]];
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
- (void)calculatePageNumbers
|
||
{
|
||
NSInteger numberOfPages = 0;
|
||
for (id obj in _pages)
|
||
{
|
||
if ([obj isKindOfClass:[UIView class]])
|
||
{
|
||
[(UIView *)obj removeFromSuperview];
|
||
}
|
||
}
|
||
if(_dataSource && [_dataSource respondsToSelector:@selector(numberOfPages:)])
|
||
{
|
||
numberOfPages = [_dataSource numberOfPages:self];
|
||
}
|
||
self.pages = [NSMutableArray arrayWithCapacity:numberOfPages];
|
||
for (NSInteger i = 0; i < numberOfPages; i ++)
|
||
{
|
||
[_pages addObject:[NSNull null]];
|
||
}
|
||
//注意,这里设置delegate是因为计算contentsize的时候会引起scrollViewDidScroll执行,修改currentpage的值,这样在贴图(举个例子)前面的分类页数比后面的分类页数多,前面的分类滚动到最后面一页后,再显示后面的分类,会显示不正确
|
||
self.scrollView.delegate = nil;
|
||
CGSize size = self.bounds.size;
|
||
[self.scrollView setContentSize:CGSizeMake(size.width * numberOfPages, size.height)];
|
||
self.scrollView.delegate = self;
|
||
}
|
||
|
||
- (void)reloadPage
|
||
{
|
||
//reload的时候尽量记住上次的位置
|
||
if (_currentPage >= [_pages count])
|
||
{
|
||
_currentPage = [_pages count] - 1;
|
||
}
|
||
if (_currentPage < 0)
|
||
{
|
||
_currentPage = 0;
|
||
}
|
||
|
||
[self loadPagesForCurrentPage:_currentPage];
|
||
[self raisePageIndexChangedDelegate];
|
||
[self setNeedsLayout];
|
||
}
|
||
|
||
|
||
#pragma mark - ScrollView Delegate
|
||
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
|
||
{
|
||
CGFloat width = scrollView.bounds.size.width;
|
||
CGFloat offsetX = scrollView.contentOffset.x;
|
||
NSInteger page = (NSInteger)(fabs(offsetX / width));
|
||
if (page >= 0 && page < [_pages count])
|
||
{
|
||
if (_currentPage == page) {
|
||
return;
|
||
}
|
||
_currentPage = page;
|
||
[self loadPagesForCurrentPage:_currentPage];
|
||
}
|
||
|
||
if (_pageViewDelegate && [_pageViewDelegate respondsToSelector:@selector(pageViewDidScroll:)])
|
||
{
|
||
[_pageViewDelegate pageViewDidScroll:self];
|
||
}
|
||
}
|
||
|
||
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
|
||
{
|
||
[self raisePageIndexChangedDelegate];
|
||
}
|
||
|
||
#pragma mark - 辅助方法
|
||
- (void)raisePageIndexChangedDelegate
|
||
{
|
||
if (_pageViewDelegate && [_pageViewDelegate respondsToSelector:@selector(pageViewScrollEnd:currentIndex:totolPages:)])
|
||
{
|
||
[_pageViewDelegate pageViewScrollEnd:self
|
||
currentIndex:_currentPage
|
||
totolPages:[_pages count]];
|
||
}
|
||
}
|
||
|
||
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
|
||
duration:(NSTimeInterval)duration
|
||
{
|
||
_scrollView.delegate = nil;
|
||
_currentPageForRotation = _currentPage;
|
||
}
|
||
|
||
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
|
||
duration:(NSTimeInterval)duration
|
||
{
|
||
CGSize size = self.bounds.size;
|
||
_scrollView.contentSize = CGSizeMake(size.width * [_pages count], size.height);
|
||
for (NSUInteger i = 0; i < [_pages count]; i++)
|
||
{
|
||
id obj = [_pages objectAtIndex:i];
|
||
if ([obj isKindOfClass:[UIView class]])
|
||
{
|
||
[(UIView *)obj setFrame:CGRectMake(size.width * i, 0, size.width, size.height)];
|
||
|
||
/*
|
||
//这里有点ugly,先这样吧...
|
||
if ([obj respondsToSelector:@selector(reset)])
|
||
{
|
||
[obj performSelector:@selector(reset)];
|
||
}*/
|
||
}
|
||
}
|
||
_scrollView.contentOffset = CGPointMake(_currentPageForRotation * self.bounds.size.width, 0);
|
||
_scrollView.delegate = self;
|
||
|
||
}
|
||
|
||
@end
|
||
|
||
|
||
@implementation NTESPageScrollView
|
||
//fix: swipe to delete in a UITableView which is embeded in a UIScrollView
|
||
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRequireFailureOfGestureRecognizer:(nonnull UIGestureRecognizer *)otherGestureRecognizer
|
||
{
|
||
return [otherGestureRecognizer.view.superview isKindOfClass:[UITableView class]];
|
||
}
|
||
|
||
@end |