二手车信息
This commit is contained in:
21
Pods/TYCyclePagerView/LICENSE
generated
Executable file
21
Pods/TYCyclePagerView/LICENSE
generated
Executable file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017 yeBlueColor
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
141
Pods/TYCyclePagerView/README.md
generated
Executable file
141
Pods/TYCyclePagerView/README.md
generated
Executable file
@@ -0,0 +1,141 @@
|
||||
# TYCyclePagerView
|
||||
a simple and usefull cycle pager view ,and auto scroll banner view ,include pageControl for iOS,support Objective-C and swift.this has been used in APP.
|
||||
|
||||
## CocoaPods
|
||||
```
|
||||
pod 'TYCyclePagerView'
|
||||
```
|
||||
|
||||
## Requirements
|
||||
* Xcode 8 or higher
|
||||
* iOS 7.0 or higher
|
||||
* ARC
|
||||
|
||||
### ScreenShot
|
||||
|
||||

|
||||
|
||||
## API
|
||||
|
||||
* DataSource and Delegate
|
||||
```objc
|
||||
|
||||
@protocol TYCyclePagerViewDataSource <NSObject>
|
||||
|
||||
- (NSInteger)numberOfItemsInPagerView:(TYCyclePagerView *)pageView;
|
||||
|
||||
- (__kindof UICollectionViewCell *)pagerView:(TYCyclePagerView *)pagerView cellForItemAtIndex:(NSInteger)index;
|
||||
|
||||
/**
|
||||
return pagerView layout,and cache layout
|
||||
*/
|
||||
- (TYCyclePagerViewLayout *)layoutForPagerView:(TYCyclePagerView *)pageView;
|
||||
|
||||
@protocol TYCyclePagerViewDelegate <NSObject>
|
||||
|
||||
@optional
|
||||
|
||||
/**
|
||||
pagerView did scroll to new index page
|
||||
*/
|
||||
- (void)pagerView:(TYCyclePagerView *)pageView didScrollFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex;
|
||||
|
||||
/**
|
||||
pagerView did selected item cell
|
||||
*/
|
||||
- (void)pagerView:(TYCyclePagerView *)pageView didSelectedItemCell:(__kindof UICollectionViewCell *)cell atIndex:(NSInteger)index;
|
||||
|
||||
// More API see project
|
||||
```
|
||||
|
||||
* Class
|
||||
|
||||
```objc
|
||||
|
||||
@interface TYCyclePagerView : UIView
|
||||
|
||||
// will be automatically resized to track the size of the pagerView
|
||||
@property (nonatomic, strong, nullable) UIView *backgroundView;
|
||||
|
||||
@property (nonatomic, weak, nullable) id<TYCyclePagerViewDataSource> dataSource;
|
||||
@property (nonatomic, weak, nullable) id<TYCyclePagerViewDelegate> delegate;
|
||||
|
||||
// pager view layout is important
|
||||
@property (nonatomic, strong, readonly) TYCyclePagerViewLayout *layout;
|
||||
|
||||
/**
|
||||
is infinite cycle pageview
|
||||
*/
|
||||
@property (nonatomic, assign) BOOL isInfiniteLoop;
|
||||
|
||||
/**
|
||||
pagerView automatic scroll time interval, default 0,disable automatic
|
||||
*/
|
||||
@property (nonatomic, assign) CGFloat autoScrollInterval;
|
||||
|
||||
|
||||
@interface TYCyclePagerViewLayout : NSObject
|
||||
|
||||
@property (nonatomic, assign) CGSize itemSize;
|
||||
@property (nonatomic, assign) CGFloat itemSpacing;
|
||||
@property (nonatomic, assign) UIEdgeInsets sectionInset;
|
||||
|
||||
@property (nonatomic, assign) TYCyclePagerTransformLayoutType layoutType;
|
||||
|
||||
@property (nonatomic, assign) CGFloat minimumScale; // sacle default 0.8
|
||||
@property (nonatomic, assign) CGFloat minimumAlpha; // alpha default 1.0
|
||||
@property (nonatomic, assign) CGFloat maximumAngle; // angle is % default 0.2
|
||||
|
||||
|
||||
@interface TYPageControl : UIControl
|
||||
|
||||
@property (nonatomic, assign) NSInteger numberOfPages; // default is 0
|
||||
@property (nonatomic, assign) NSInteger currentPage; // default is 0. value pinned to 0..numberOfPages-1
|
||||
|
||||
// indicatorTint color
|
||||
@property (nullable, nonatomic,strong) UIColor *pageIndicatorTintColor;
|
||||
@property (nullable, nonatomic,strong) UIColor *currentPageIndicatorTintColor;
|
||||
|
||||
// indicator image
|
||||
@property (nullable, nonatomic,strong) UIImage *pageIndicatorImage;
|
||||
@property (nullable, nonatomic,strong) UIImage *currentPageIndicatorImage;
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```objc
|
||||
|
||||
- (void)addPagerView {
|
||||
TYCyclePagerView *pagerView = [[TYCyclePagerView alloc]init];
|
||||
pagerView.layer.borderWidth = 1;
|
||||
pagerView.isInfiniteLoop = YES;
|
||||
pagerView.autoScrollInterval = 3.0;
|
||||
pagerView.dataSource = self;
|
||||
pagerView.delegate = self;
|
||||
// registerClass or registerNib
|
||||
[pagerView registerClass:[TYCyclePagerViewCell class] forCellWithReuseIdentifier:@"cellId"];
|
||||
[self.view addSubview:pagerView];
|
||||
_pagerView = pagerView;
|
||||
}
|
||||
|
||||
- (void)addPageControl {
|
||||
TYPageControl *pageControl = [[TYPageControl alloc]init];
|
||||
//pageControl.numberOfPages = _datas.count;
|
||||
pageControl.currentPageIndicatorSize = CGSizeMake(8, 8);
|
||||
// pageControl.pageIndicatorImage = [UIImage imageNamed:@"Dot"];
|
||||
// pageControl.currentPageIndicatorImage = [UIImage imageNamed:@"DotSelected"];
|
||||
// [pageControl addTarget:self action:@selector(pageControlValueChangeAction:) forControlEvents:UIControlEventValueChanged];
|
||||
[_pagerView addSubview:pageControl];
|
||||
_pageControl = pageControl;
|
||||
}
|
||||
- (void)loadData {
|
||||
// load data to _datas
|
||||
_pageControl.numberOfPages = _datas.count;
|
||||
[_pagerView reloadData];
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Contact
|
||||
如果你发现bug,please pull reqeust me <br>
|
||||
如果你有更好的改进,please pull reqeust me <br>
|
||||
74
Pods/TYCyclePagerView/TYCyclePagerViewDemo/TYCyclePagerView/TYCyclePagerTransformLayout.h
generated
Executable file
74
Pods/TYCyclePagerView/TYCyclePagerViewDemo/TYCyclePagerView/TYCyclePagerTransformLayout.h
generated
Executable file
@@ -0,0 +1,74 @@
|
||||
//
|
||||
// TYCyclePagerViewLayout.h
|
||||
// TYCyclePagerViewDemo
|
||||
//
|
||||
// Created by tany on 2017/6/19.
|
||||
// Copyright © 2017年 tany. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
typedef NS_ENUM(NSUInteger, TYCyclePagerTransformLayoutType) {
|
||||
TYCyclePagerTransformLayoutNormal,
|
||||
TYCyclePagerTransformLayoutLinear,
|
||||
TYCyclePagerTransformLayoutCoverflow,
|
||||
};
|
||||
|
||||
@class TYCyclePagerTransformLayout;
|
||||
@protocol TYCyclePagerTransformLayoutDelegate <NSObject>
|
||||
|
||||
// initialize layout attributes
|
||||
- (void)pagerViewTransformLayout:(TYCyclePagerTransformLayout *)pagerViewTransformLayout initializeTransformAttributes:(UICollectionViewLayoutAttributes *)attributes;
|
||||
|
||||
// apply layout attributes
|
||||
- (void)pagerViewTransformLayout:(TYCyclePagerTransformLayout *)pagerViewTransformLayout applyTransformToAttributes:(UICollectionViewLayoutAttributes *)attributes;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface TYCyclePagerViewLayout : NSObject
|
||||
|
||||
@property (nonatomic, assign) CGSize itemSize;
|
||||
@property (nonatomic, assign) CGFloat itemSpacing;
|
||||
@property (nonatomic, assign) UIEdgeInsets sectionInset;
|
||||
|
||||
@property (nonatomic, assign) TYCyclePagerTransformLayoutType layoutType;
|
||||
|
||||
@property (nonatomic, assign) CGFloat minimumScale; // sacle default 0.8
|
||||
@property (nonatomic, assign) CGFloat minimumAlpha; // alpha default 1.0
|
||||
@property (nonatomic, assign) CGFloat maximumAngle; // angle is % default 0.2
|
||||
|
||||
@property (nonatomic, assign) BOOL isInfiniteLoop; // infinte scroll
|
||||
@property (nonatomic, assign) CGFloat rateOfChange; // scale and angle change rate
|
||||
@property (nonatomic, assign) BOOL adjustSpacingWhenScroling;
|
||||
|
||||
/**
|
||||
pageView cell item vertical centering
|
||||
*/
|
||||
@property (nonatomic, assign) BOOL itemVerticalCenter;
|
||||
|
||||
/**
|
||||
first and last item horizontalc enter, when isInfiniteLoop is NO
|
||||
*/
|
||||
@property (nonatomic, assign) BOOL itemHorizontalCenter;
|
||||
|
||||
// sectionInset
|
||||
@property (nonatomic, assign, readonly) UIEdgeInsets onlyOneSectionInset;
|
||||
@property (nonatomic, assign, readonly) UIEdgeInsets firstSectionInset;
|
||||
@property (nonatomic, assign, readonly) UIEdgeInsets lastSectionInset;
|
||||
@property (nonatomic, assign, readonly) UIEdgeInsets middleSectionInset;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface TYCyclePagerTransformLayout : UICollectionViewFlowLayout
|
||||
|
||||
@property (nonatomic, strong) TYCyclePagerViewLayout *layout;
|
||||
|
||||
@property (nonatomic, weak, nullable) id<TYCyclePagerTransformLayoutDelegate> delegate;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
300
Pods/TYCyclePagerView/TYCyclePagerViewDemo/TYCyclePagerView/TYCyclePagerTransformLayout.m
generated
Executable file
300
Pods/TYCyclePagerView/TYCyclePagerViewDemo/TYCyclePagerView/TYCyclePagerTransformLayout.m
generated
Executable file
@@ -0,0 +1,300 @@
|
||||
//
|
||||
// TYCyclePagerViewLayout.m
|
||||
// TYCyclePagerViewDemo
|
||||
//
|
||||
// Created by tany on 2017/6/19.
|
||||
// Copyright © 2017年 tany. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TYCyclePagerTransformLayout.h"
|
||||
|
||||
typedef NS_ENUM(NSUInteger, TYTransformLayoutItemDirection) {
|
||||
TYTransformLayoutItemLeft,
|
||||
TYTransformLayoutItemCenter,
|
||||
TYTransformLayoutItemRight,
|
||||
};
|
||||
|
||||
|
||||
@interface TYCyclePagerTransformLayout () {
|
||||
struct {
|
||||
unsigned int applyTransformToAttributes :1;
|
||||
unsigned int initializeTransformAttributes :1;
|
||||
}_delegateFlags;
|
||||
}
|
||||
|
||||
@property (nonatomic, assign) BOOL applyTransformToAttributesDelegate;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface TYCyclePagerViewLayout ()
|
||||
|
||||
@property (nonatomic, weak) UIView *pageView;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation TYCyclePagerTransformLayout
|
||||
|
||||
- (instancetype)init {
|
||||
if (self = [super init]) {
|
||||
self.scrollDirection = UICollectionViewScrollDirectionHorizontal;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
|
||||
if (self = [super initWithCoder:aDecoder]) {
|
||||
self.scrollDirection = UICollectionViewScrollDirectionHorizontal;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - getter setter
|
||||
|
||||
- (void)setDelegate:(id<TYCyclePagerTransformLayoutDelegate>)delegate {
|
||||
_delegate = delegate;
|
||||
_delegateFlags.initializeTransformAttributes = [delegate respondsToSelector:@selector(pagerViewTransformLayout:initializeTransformAttributes:)];
|
||||
_delegateFlags.applyTransformToAttributes = [delegate respondsToSelector:@selector(pagerViewTransformLayout:applyTransformToAttributes:)];
|
||||
}
|
||||
|
||||
- (void)setLayout:(TYCyclePagerViewLayout *)layout {
|
||||
_layout = layout;
|
||||
_layout.pageView = self.collectionView;
|
||||
self.itemSize = _layout.itemSize;
|
||||
self.minimumInteritemSpacing = _layout.itemSpacing;
|
||||
self.minimumLineSpacing = _layout.itemSpacing;
|
||||
}
|
||||
|
||||
- (CGSize)itemSize {
|
||||
if (!_layout) {
|
||||
return [super itemSize];
|
||||
}
|
||||
return _layout.itemSize;
|
||||
}
|
||||
|
||||
- (CGFloat)minimumLineSpacing {
|
||||
if (!_layout) {
|
||||
return [super minimumLineSpacing];
|
||||
}
|
||||
return _layout.itemSpacing;
|
||||
}
|
||||
|
||||
- (CGFloat)minimumInteritemSpacing {
|
||||
if (!_layout) {
|
||||
return [super minimumInteritemSpacing];
|
||||
}
|
||||
return _layout.itemSpacing;
|
||||
}
|
||||
|
||||
- (TYTransformLayoutItemDirection)directionWithCenterX:(CGFloat)centerX {
|
||||
TYTransformLayoutItemDirection direction= TYTransformLayoutItemRight;
|
||||
CGFloat contentCenterX = self.collectionView.contentOffset.x + CGRectGetWidth(self.collectionView.frame)/2;
|
||||
if (ABS(centerX - contentCenterX) < 0.5) {
|
||||
direction = TYTransformLayoutItemCenter;
|
||||
}else if (centerX - contentCenterX < 0) {
|
||||
direction = TYTransformLayoutItemLeft;
|
||||
}
|
||||
return direction;
|
||||
}
|
||||
|
||||
#pragma mark - layout
|
||||
|
||||
-(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
|
||||
{
|
||||
return _layout.layoutType == TYCyclePagerTransformLayoutNormal ? [super shouldInvalidateLayoutForBoundsChange:newBounds] : YES;
|
||||
}
|
||||
|
||||
- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect {
|
||||
if (_delegateFlags.applyTransformToAttributes || _layout.layoutType != TYCyclePagerTransformLayoutNormal) {
|
||||
NSArray *attributesArray = [[NSArray alloc] initWithArray:[super layoutAttributesForElementsInRect:rect] copyItems:YES];
|
||||
CGRect visibleRect = {self.collectionView.contentOffset,self.collectionView.bounds.size};
|
||||
for (UICollectionViewLayoutAttributes *attributes in attributesArray) {
|
||||
if (!CGRectIntersectsRect(visibleRect, attributes.frame)) {
|
||||
continue;
|
||||
}
|
||||
if (_delegateFlags.applyTransformToAttributes) {
|
||||
[_delegate pagerViewTransformLayout:self applyTransformToAttributes:attributes];
|
||||
}else {
|
||||
[self applyTransformToAttributes:attributes layoutType:_layout.layoutType];
|
||||
}
|
||||
}
|
||||
return attributesArray;
|
||||
}
|
||||
return [super layoutAttributesForElementsInRect:rect];
|
||||
}
|
||||
|
||||
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
UICollectionViewLayoutAttributes *attributes = [super layoutAttributesForItemAtIndexPath:indexPath];
|
||||
if (_delegateFlags.initializeTransformAttributes) {
|
||||
[_delegate pagerViewTransformLayout:self initializeTransformAttributes:attributes];
|
||||
}else if(_layout.layoutType != TYCyclePagerTransformLayoutNormal){
|
||||
[self initializeTransformAttributes:attributes layoutType:_layout.layoutType];
|
||||
}
|
||||
return attributes;
|
||||
}
|
||||
|
||||
#pragma mark - transform
|
||||
|
||||
- (void)initializeTransformAttributes:(UICollectionViewLayoutAttributes *)attributes layoutType:(TYCyclePagerTransformLayoutType)layoutType {
|
||||
switch (layoutType) {
|
||||
case TYCyclePagerTransformLayoutLinear:
|
||||
[self applyLinearTransformToAttributes:attributes scale:_layout.minimumScale alpha:_layout.minimumAlpha];
|
||||
break;
|
||||
case TYCyclePagerTransformLayoutCoverflow:
|
||||
{
|
||||
[self applyCoverflowTransformToAttributes:attributes angle:_layout.maximumAngle alpha:_layout.minimumAlpha];
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)applyTransformToAttributes:(UICollectionViewLayoutAttributes *)attributes layoutType:(TYCyclePagerTransformLayoutType)layoutType {
|
||||
switch (layoutType) {
|
||||
case TYCyclePagerTransformLayoutLinear:
|
||||
[self applyLinearTransformToAttributes:attributes];
|
||||
break;
|
||||
case TYCyclePagerTransformLayoutCoverflow:
|
||||
[self applyCoverflowTransformToAttributes:attributes];
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - LinearTransform
|
||||
|
||||
- (void)applyLinearTransformToAttributes:(UICollectionViewLayoutAttributes *)attributes {
|
||||
CGFloat collectionViewWidth = self.collectionView.frame.size.width;
|
||||
if (collectionViewWidth <= 0) {
|
||||
return;
|
||||
}
|
||||
CGFloat centetX = self.collectionView.contentOffset.x + collectionViewWidth/2;
|
||||
CGFloat delta = ABS(attributes.center.x - centetX);
|
||||
CGFloat scale = MAX(1 - delta/collectionViewWidth*_layout.rateOfChange, _layout.minimumScale);
|
||||
CGFloat alpha = MAX(1 - delta/collectionViewWidth, _layout.minimumAlpha);
|
||||
[self applyLinearTransformToAttributes:attributes scale:scale alpha:alpha];
|
||||
}
|
||||
|
||||
- (void)applyLinearTransformToAttributes:(UICollectionViewLayoutAttributes *)attributes scale:(CGFloat)scale alpha:(CGFloat)alpha {
|
||||
CGAffineTransform transform = CGAffineTransformMakeScale(scale, scale);
|
||||
if (_layout.adjustSpacingWhenScroling) {
|
||||
TYTransformLayoutItemDirection direction = [self directionWithCenterX:attributes.center.x];
|
||||
CGFloat translate = 0;
|
||||
switch (direction) {
|
||||
case TYTransformLayoutItemLeft:
|
||||
translate = 1.15 * attributes.size.width*(1-scale)/2;
|
||||
break;
|
||||
case TYTransformLayoutItemRight:
|
||||
translate = -1.15 * attributes.size.width*(1-scale)/2;
|
||||
break;
|
||||
default:
|
||||
// center
|
||||
scale = 1.0;
|
||||
alpha = 1.0;
|
||||
break;
|
||||
}
|
||||
transform = CGAffineTransformTranslate(transform,translate, 0);
|
||||
}
|
||||
attributes.transform = transform;
|
||||
attributes.alpha = alpha;
|
||||
}
|
||||
|
||||
#pragma mark - CoverflowTransform
|
||||
|
||||
- (void)applyCoverflowTransformToAttributes:(UICollectionViewLayoutAttributes *)attributes{
|
||||
CGFloat collectionViewWidth = self.collectionView.frame.size.width;
|
||||
if (collectionViewWidth <= 0) {
|
||||
return;
|
||||
}
|
||||
CGFloat centetX = self.collectionView.contentOffset.x + collectionViewWidth/2;
|
||||
CGFloat delta = ABS(attributes.center.x - centetX);
|
||||
CGFloat angle = MIN(delta/collectionViewWidth*(1-_layout.rateOfChange), _layout.maximumAngle);
|
||||
CGFloat alpha = MAX(1 - delta/collectionViewWidth, _layout.minimumAlpha);
|
||||
[self applyCoverflowTransformToAttributes:attributes angle:angle alpha:alpha];
|
||||
}
|
||||
|
||||
- (void)applyCoverflowTransformToAttributes:(UICollectionViewLayoutAttributes *)attributes angle:(CGFloat)angle alpha:(CGFloat)alpha {
|
||||
TYTransformLayoutItemDirection direction = [self directionWithCenterX:attributes.center.x];
|
||||
CATransform3D transform3D = CATransform3DIdentity;
|
||||
transform3D.m34 = -0.002;
|
||||
CGFloat translate = 0;
|
||||
switch (direction) {
|
||||
case TYTransformLayoutItemLeft:
|
||||
translate = (1-cos(angle*1.2*M_PI))*attributes.size.width;
|
||||
break;
|
||||
case TYTransformLayoutItemRight:
|
||||
translate = -(1-cos(angle*1.2*M_PI))*attributes.size.width;
|
||||
angle = -angle;
|
||||
break;
|
||||
default:
|
||||
// center
|
||||
angle = 0;
|
||||
alpha = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
transform3D = CATransform3DRotate(transform3D, M_PI*angle, 0, 1, 0);
|
||||
if (_layout.adjustSpacingWhenScroling) {
|
||||
transform3D = CATransform3DTranslate(transform3D, translate, 0, 0);
|
||||
}
|
||||
attributes.transform3D = transform3D;
|
||||
attributes.alpha = alpha;
|
||||
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
@implementation TYCyclePagerViewLayout
|
||||
|
||||
- (instancetype)init {
|
||||
if (self = [super init]) {
|
||||
_itemVerticalCenter = YES;
|
||||
_minimumScale = 0.8;
|
||||
_minimumAlpha = 1.0;
|
||||
_maximumAngle = 0.2;
|
||||
_rateOfChange = 0.4;
|
||||
_adjustSpacingWhenScroling = YES;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - getter
|
||||
|
||||
- (UIEdgeInsets)onlyOneSectionInset {
|
||||
CGFloat leftSpace = _pageView && !_isInfiniteLoop && _itemHorizontalCenter ? (CGRectGetWidth(_pageView.frame) - _itemSize.width)/2 : _sectionInset.left;
|
||||
CGFloat rightSpace = _pageView && !_isInfiniteLoop && _itemHorizontalCenter ? (CGRectGetWidth(_pageView.frame) - _itemSize.width)/2 : _sectionInset.right;
|
||||
if (_itemVerticalCenter) {
|
||||
CGFloat verticalSpace = (CGRectGetHeight(_pageView.frame) - _itemSize.height)/2;
|
||||
return UIEdgeInsetsMake(verticalSpace, leftSpace, verticalSpace, rightSpace);
|
||||
}
|
||||
return UIEdgeInsetsMake(_sectionInset.top, leftSpace, _sectionInset.bottom, rightSpace);
|
||||
}
|
||||
|
||||
- (UIEdgeInsets)firstSectionInset {
|
||||
if (_itemVerticalCenter) {
|
||||
CGFloat verticalSpace = (CGRectGetHeight(_pageView.frame) - _itemSize.height)/2;
|
||||
return UIEdgeInsetsMake(verticalSpace, _sectionInset.left, verticalSpace, _itemSpacing);
|
||||
}
|
||||
return UIEdgeInsetsMake(_sectionInset.top, _sectionInset.left, _sectionInset.bottom, _itemSpacing);
|
||||
}
|
||||
|
||||
- (UIEdgeInsets)lastSectionInset {
|
||||
if (_itemVerticalCenter) {
|
||||
CGFloat verticalSpace = (CGRectGetHeight(_pageView.frame) - _itemSize.height)/2;
|
||||
return UIEdgeInsetsMake(verticalSpace, 0, verticalSpace, _sectionInset.right);
|
||||
}
|
||||
return UIEdgeInsetsMake(_sectionInset.top, 0, _sectionInset.bottom, _sectionInset.right);
|
||||
}
|
||||
|
||||
- (UIEdgeInsets)middleSectionInset {
|
||||
if (_itemVerticalCenter) {
|
||||
CGFloat verticalSpace = (CGRectGetHeight(_pageView.frame) - _itemSize.height)/2;
|
||||
return UIEdgeInsetsMake(verticalSpace, 0, verticalSpace, _itemSpacing);
|
||||
}
|
||||
return _sectionInset;
|
||||
}
|
||||
|
||||
@end
|
||||
180
Pods/TYCyclePagerView/TYCyclePagerViewDemo/TYCyclePagerView/TYCyclePagerView.h
generated
Executable file
180
Pods/TYCyclePagerView/TYCyclePagerViewDemo/TYCyclePagerView/TYCyclePagerView.h
generated
Executable file
@@ -0,0 +1,180 @@
|
||||
//
|
||||
// TYCyclePagerView.h
|
||||
// TYCyclePagerViewDemo
|
||||
//
|
||||
// Created by tany on 2017/6/14.
|
||||
// Copyright © 2017年 tany. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "TYCyclePagerTransformLayout.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
typedef struct {
|
||||
NSInteger index;
|
||||
NSInteger section;
|
||||
}TYIndexSection;
|
||||
|
||||
// pagerView scrolling direction
|
||||
typedef NS_ENUM(NSUInteger, TYPagerScrollDirection) {
|
||||
TYPagerScrollDirectionLeft,
|
||||
TYPagerScrollDirectionRight,
|
||||
};
|
||||
|
||||
@class TYCyclePagerView;
|
||||
@protocol TYCyclePagerViewDataSource <NSObject>
|
||||
|
||||
- (NSInteger)numberOfItemsInPagerView:(TYCyclePagerView *)pageView;
|
||||
|
||||
- (__kindof UICollectionViewCell *)pagerView:(TYCyclePagerView *)pagerView cellForItemAtIndex:(NSInteger)index;
|
||||
|
||||
/**
|
||||
return pagerView layout,and cache layout
|
||||
*/
|
||||
- (TYCyclePagerViewLayout *)layoutForPagerView:(TYCyclePagerView *)pageView;
|
||||
|
||||
@end
|
||||
|
||||
@protocol TYCyclePagerViewDelegate <NSObject>
|
||||
|
||||
@optional
|
||||
|
||||
/**
|
||||
pagerView did scroll to new index page
|
||||
*/
|
||||
- (void)pagerView:(TYCyclePagerView *)pageView didScrollFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex;
|
||||
|
||||
/**
|
||||
pagerView did selected item cell
|
||||
*/
|
||||
- (void)pagerView:(TYCyclePagerView *)pageView didSelectedItemCell:(__kindof UICollectionViewCell *)cell atIndex:(NSInteger)index;
|
||||
- (void)pagerView:(TYCyclePagerView *)pageView didSelectedItemCell:(__kindof UICollectionViewCell *)cell atIndexSection:(TYIndexSection)indexSection;
|
||||
|
||||
// custom layout
|
||||
- (void)pagerView:(TYCyclePagerView *)pageView initializeTransformAttributes:(UICollectionViewLayoutAttributes *)attributes;
|
||||
|
||||
- (void)pagerView:(TYCyclePagerView *)pageView applyTransformToAttributes:(UICollectionViewLayoutAttributes *)attributes;
|
||||
|
||||
|
||||
// scrollViewDelegate
|
||||
|
||||
- (void)pagerViewDidScroll:(TYCyclePagerView *)pageView;
|
||||
|
||||
- (void)pagerViewWillBeginDragging:(TYCyclePagerView *)pageView;
|
||||
|
||||
- (void)pagerViewDidEndDragging:(TYCyclePagerView *)pageView willDecelerate:(BOOL)decelerate;
|
||||
|
||||
- (void)pagerViewWillBeginDecelerating:(TYCyclePagerView *)pageView;
|
||||
|
||||
- (void)pagerViewDidEndDecelerating:(TYCyclePagerView *)pageView;
|
||||
|
||||
- (void)pagerViewWillBeginScrollingAnimation:(TYCyclePagerView *)pageView;
|
||||
|
||||
- (void)pagerViewDidEndScrollingAnimation:(TYCyclePagerView *)pageView;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface TYCyclePagerView : UIView
|
||||
|
||||
// will be automatically resized to track the size of the pagerView
|
||||
@property (nonatomic, strong, nullable) UIView *backgroundView;
|
||||
|
||||
@property (nonatomic, weak, nullable) id<TYCyclePagerViewDataSource> dataSource;
|
||||
@property (nonatomic, weak, nullable) id<TYCyclePagerViewDelegate> delegate;
|
||||
|
||||
// pager view, don't set dataSource and delegate
|
||||
@property (nonatomic, weak, readonly) UICollectionView *collectionView;
|
||||
// pager view layout
|
||||
@property (nonatomic, strong, readonly) TYCyclePagerViewLayout *layout;
|
||||
|
||||
/**
|
||||
is infinite cycle pageview
|
||||
*/
|
||||
@property (nonatomic, assign) BOOL isInfiniteLoop;
|
||||
|
||||
/**
|
||||
pagerView automatic scroll time interval, default 0,disable automatic
|
||||
*/
|
||||
@property (nonatomic, assign) CGFloat autoScrollInterval;
|
||||
|
||||
@property (nonatomic, assign) BOOL reloadDataNeedResetIndex;
|
||||
|
||||
/**
|
||||
current page index
|
||||
*/
|
||||
@property (nonatomic, assign, readonly) NSInteger curIndex;
|
||||
@property (nonatomic, assign, readonly) TYIndexSection indexSection;
|
||||
|
||||
// scrollView property
|
||||
@property (nonatomic, assign, readonly) CGPoint contentOffset;
|
||||
@property (nonatomic, assign, readonly) BOOL tracking;
|
||||
@property (nonatomic, assign, readonly) BOOL dragging;
|
||||
@property (nonatomic, assign, readonly) BOOL decelerating;
|
||||
|
||||
|
||||
/**
|
||||
reload data, !!important!!: will clear layout and call delegate layoutForPagerView
|
||||
*/
|
||||
- (void)reloadData;
|
||||
|
||||
/**
|
||||
update data is reload data, but not clear layuot
|
||||
*/
|
||||
- (void)updateData;
|
||||
|
||||
/**
|
||||
if you only want update layout
|
||||
*/
|
||||
- (void)setNeedUpdateLayout;
|
||||
|
||||
/**
|
||||
will set layout nil and call delegate->layoutForPagerView
|
||||
*/
|
||||
- (void)setNeedClearLayout;
|
||||
|
||||
/**
|
||||
current index cell in pagerView
|
||||
*/
|
||||
- (__kindof UICollectionViewCell * _Nullable)curIndexCell;
|
||||
|
||||
/**
|
||||
visible cells in pageView
|
||||
*/
|
||||
- (NSArray<__kindof UICollectionViewCell *> *_Nullable)visibleCells;
|
||||
|
||||
|
||||
/**
|
||||
visible pageView indexs, maybe repeat index
|
||||
*/
|
||||
- (NSArray *)visibleIndexs;
|
||||
|
||||
/**
|
||||
scroll to item at index
|
||||
*/
|
||||
- (void)scrollToItemAtIndex:(NSInteger)index animate:(BOOL)animate;
|
||||
- (void)scrollToItemAtIndexSection:(TYIndexSection)indexSection animate:(BOOL)animate;
|
||||
/**
|
||||
scroll to next or pre item
|
||||
*/
|
||||
- (void)scrollToNearlyIndexAtDirection:(TYPagerScrollDirection)direction animate:(BOOL)animate;
|
||||
|
||||
/**
|
||||
register pager view cell with class
|
||||
*/
|
||||
- (void)registerClass:(Class)Class forCellWithReuseIdentifier:(NSString *)identifier;
|
||||
|
||||
/**
|
||||
register pager view cell with nib
|
||||
*/
|
||||
- (void)registerNib:(UINib *)nib forCellWithReuseIdentifier:(NSString *)identifier;
|
||||
|
||||
/**
|
||||
dequeue reusable cell for pagerView
|
||||
*/
|
||||
- (__kindof UICollectionViewCell *)dequeueReusableCellWithReuseIdentifier:(NSString *)identifier forIndex:(NSInteger)index;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
607
Pods/TYCyclePagerView/TYCyclePagerViewDemo/TYCyclePagerView/TYCyclePagerView.m
generated
Executable file
607
Pods/TYCyclePagerView/TYCyclePagerViewDemo/TYCyclePagerView/TYCyclePagerView.m
generated
Executable file
@@ -0,0 +1,607 @@
|
||||
//
|
||||
// TYCyclePagerView.m
|
||||
// TYCyclePagerViewDemo
|
||||
//
|
||||
// Created by tany on 2017/6/14.
|
||||
// Copyright © 2017年 tany. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TYCyclePagerView.h"
|
||||
|
||||
NS_INLINE BOOL TYEqualIndexSection(TYIndexSection indexSection1,TYIndexSection indexSection2) {
|
||||
return indexSection1.index == indexSection2.index && indexSection1.section == indexSection2.section;
|
||||
}
|
||||
|
||||
NS_INLINE TYIndexSection TYMakeIndexSection(NSInteger index, NSInteger section) {
|
||||
TYIndexSection indexSection;
|
||||
indexSection.index = index;
|
||||
indexSection.section = section;
|
||||
return indexSection;
|
||||
}
|
||||
|
||||
@interface TYCyclePagerView () <UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, TYCyclePagerTransformLayoutDelegate> {
|
||||
struct {
|
||||
unsigned int pagerViewDidScroll :1;
|
||||
unsigned int didScrollFromIndexToNewIndex :1;
|
||||
unsigned int initializeTransformAttributes :1;
|
||||
unsigned int applyTransformToAttributes :1;
|
||||
}_delegateFlags;
|
||||
struct {
|
||||
unsigned int cellForItemAtIndex :1;
|
||||
unsigned int layoutForPagerView :1;
|
||||
}_dataSourceFlags;
|
||||
}
|
||||
|
||||
// UI
|
||||
@property (nonatomic, weak) UICollectionView *collectionView;
|
||||
@property (nonatomic, strong) TYCyclePagerViewLayout *layout;
|
||||
@property (nonatomic, strong) NSTimer *timer;
|
||||
|
||||
// Data
|
||||
@property (nonatomic, assign) NSInteger numberOfItems;
|
||||
|
||||
@property (nonatomic, assign) NSInteger dequeueSection;
|
||||
@property (nonatomic, assign) TYIndexSection beginDragIndexSection;
|
||||
@property (nonatomic, assign) NSInteger firstScrollIndex;
|
||||
|
||||
@property (nonatomic, assign) BOOL needClearLayout;
|
||||
@property (nonatomic, assign) BOOL didReloadData;
|
||||
@property (nonatomic, assign) BOOL didLayout;
|
||||
@property (nonatomic, assign) BOOL needResetIndex;
|
||||
|
||||
@end
|
||||
|
||||
#define kPagerViewMaxSectionCount 200
|
||||
#define kPagerViewMinSectionCount 18
|
||||
|
||||
@implementation TYCyclePagerView
|
||||
|
||||
#pragma mark - life Cycle
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
if (self = [super initWithFrame:frame]) {
|
||||
[self configureProperty];
|
||||
|
||||
[self addCollectionView];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
|
||||
if (self = [super initWithCoder:aDecoder]) {
|
||||
[self configureProperty];
|
||||
|
||||
[self addCollectionView];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)configureProperty {
|
||||
_needResetIndex = NO;
|
||||
_didReloadData = NO;
|
||||
_didLayout = NO;
|
||||
_autoScrollInterval = 0;
|
||||
_isInfiniteLoop = YES;
|
||||
_beginDragIndexSection.index = 0;
|
||||
_beginDragIndexSection.section = 0;
|
||||
_indexSection.index = -1;
|
||||
_indexSection.section = -1;
|
||||
_firstScrollIndex = -1;
|
||||
}
|
||||
|
||||
- (void)addCollectionView {
|
||||
TYCyclePagerTransformLayout *layout = [[TYCyclePagerTransformLayout alloc]init];
|
||||
UICollectionView *collectionView = [[UICollectionView alloc]initWithFrame:CGRectZero collectionViewLayout:layout];
|
||||
layout.delegate = _delegateFlags.applyTransformToAttributes ? self : nil;;
|
||||
collectionView.backgroundColor = [UIColor clearColor];
|
||||
collectionView.dataSource = self;
|
||||
collectionView.delegate = self;
|
||||
collectionView.pagingEnabled = NO;
|
||||
collectionView.decelerationRate = 1-0.0076;
|
||||
if ([collectionView respondsToSelector:@selector(setPrefetchingEnabled:)]) {
|
||||
collectionView.prefetchingEnabled = NO;
|
||||
}
|
||||
collectionView.showsHorizontalScrollIndicator = NO;
|
||||
collectionView.showsVerticalScrollIndicator = NO;
|
||||
[self addSubview:collectionView];
|
||||
_collectionView = collectionView;
|
||||
}
|
||||
|
||||
- (void)willMoveToSuperview:(UIView *)newSuperview {
|
||||
if (!newSuperview) {
|
||||
[self removeTimer];
|
||||
}else {
|
||||
[self removeTimer];
|
||||
if (_autoScrollInterval > 0) {
|
||||
[self addTimer];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - timer
|
||||
|
||||
- (void)addTimer {
|
||||
if (_timer || _autoScrollInterval <= 0) {
|
||||
return;
|
||||
}
|
||||
_timer = [NSTimer timerWithTimeInterval:_autoScrollInterval target:self selector:@selector(timerFired:) userInfo:nil repeats:YES];
|
||||
[[NSRunLoop mainRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];
|
||||
}
|
||||
|
||||
- (void)removeTimer {
|
||||
if (!_timer) {
|
||||
return;
|
||||
}
|
||||
[_timer invalidate];
|
||||
_timer = nil;
|
||||
}
|
||||
|
||||
- (void)timerFired:(NSTimer *)timer {
|
||||
if (!self.superview || !self.window || _numberOfItems == 0 || self.tracking) {
|
||||
return;
|
||||
}
|
||||
|
||||
[self scrollToNearlyIndexAtDirection:TYPagerScrollDirectionRight animate:YES];
|
||||
}
|
||||
|
||||
#pragma mark - getter
|
||||
|
||||
- (TYCyclePagerViewLayout *)layout {
|
||||
if (!_layout) {
|
||||
if (_dataSourceFlags.layoutForPagerView) {
|
||||
_layout = [_dataSource layoutForPagerView:self];
|
||||
_layout.isInfiniteLoop = _isInfiniteLoop;
|
||||
}
|
||||
if (_layout.itemSize.width <= 0 || _layout.itemSize.height <= 0) {
|
||||
_layout = nil;
|
||||
}
|
||||
}
|
||||
return _layout;
|
||||
}
|
||||
|
||||
- (NSInteger)curIndex {
|
||||
return _indexSection.index;
|
||||
}
|
||||
|
||||
- (CGPoint)contentOffset {
|
||||
return _collectionView.contentOffset;
|
||||
}
|
||||
|
||||
- (BOOL)tracking {
|
||||
return _collectionView.tracking;
|
||||
}
|
||||
|
||||
- (BOOL)dragging {
|
||||
return _collectionView.dragging;
|
||||
}
|
||||
|
||||
- (BOOL)decelerating {
|
||||
return _collectionView.decelerating;
|
||||
}
|
||||
|
||||
- (UIView *)backgroundView {
|
||||
return _collectionView.backgroundView;
|
||||
}
|
||||
|
||||
- (__kindof UICollectionViewCell *)curIndexCell {
|
||||
return [_collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForItem:_indexSection.index inSection:_indexSection.section]];
|
||||
}
|
||||
|
||||
- (NSArray<__kindof UICollectionViewCell *> *)visibleCells {
|
||||
return _collectionView.visibleCells;
|
||||
}
|
||||
|
||||
- (NSArray *)visibleIndexs {
|
||||
NSMutableArray *indexs = [NSMutableArray array];
|
||||
for (NSIndexPath *indexPath in _collectionView.indexPathsForVisibleItems) {
|
||||
[indexs addObject:@(indexPath.item)];
|
||||
}
|
||||
return [indexs copy];
|
||||
}
|
||||
|
||||
#pragma mark - setter
|
||||
|
||||
- (void)setBackgroundView:(UIView *)backgroundView {
|
||||
[_collectionView setBackgroundView:backgroundView];
|
||||
}
|
||||
|
||||
- (void)setAutoScrollInterval:(CGFloat)autoScrollInterval {
|
||||
_autoScrollInterval = autoScrollInterval;
|
||||
[self removeTimer];
|
||||
if (autoScrollInterval > 0 && self.superview) {
|
||||
[self addTimer];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setDelegate:(id<TYCyclePagerViewDelegate>)delegate {
|
||||
_delegate = delegate;
|
||||
_delegateFlags.pagerViewDidScroll = [delegate respondsToSelector:@selector(pagerViewDidScroll:)];
|
||||
_delegateFlags.didScrollFromIndexToNewIndex = [delegate respondsToSelector:@selector(pagerView:didScrollFromIndex:toIndex:)];
|
||||
_delegateFlags.initializeTransformAttributes = [delegate respondsToSelector:@selector(pagerView:initializeTransformAttributes:)];
|
||||
_delegateFlags.applyTransformToAttributes = [delegate respondsToSelector:@selector(pagerView:applyTransformToAttributes:)];
|
||||
if (self.collectionView && self.collectionView.collectionViewLayout) {
|
||||
((TYCyclePagerTransformLayout *)self.collectionView.collectionViewLayout).delegate = _delegateFlags.applyTransformToAttributes ? self : nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setDataSource:(id<TYCyclePagerViewDataSource>)dataSource {
|
||||
_dataSource = dataSource;
|
||||
_dataSourceFlags.cellForItemAtIndex = [dataSource respondsToSelector:@selector(pagerView:cellForItemAtIndex:)];
|
||||
_dataSourceFlags.layoutForPagerView = [dataSource respondsToSelector:@selector(layoutForPagerView:)];
|
||||
}
|
||||
|
||||
#pragma mark - public
|
||||
|
||||
- (void)reloadData {
|
||||
_didReloadData = YES;
|
||||
_needResetIndex = YES;
|
||||
[self setNeedClearLayout];
|
||||
[self clearLayout];
|
||||
[self updateData];
|
||||
}
|
||||
|
||||
// not clear layout
|
||||
- (void)updateData {
|
||||
[self updateLayout];
|
||||
_numberOfItems = [_dataSource numberOfItemsInPagerView:self];
|
||||
[_collectionView reloadData];
|
||||
if (!_didLayout && !CGRectIsEmpty(self.collectionView.frame) && _indexSection.index < 0) {
|
||||
_didLayout = YES;
|
||||
}
|
||||
BOOL needResetIndex = _needResetIndex && _reloadDataNeedResetIndex;
|
||||
_needResetIndex = NO;
|
||||
if (needResetIndex) {
|
||||
[self removeTimer];
|
||||
}
|
||||
[self resetPagerViewAtIndex:(_indexSection.index < 0 && !CGRectIsEmpty(self.collectionView.frame)) || needResetIndex ? 0 :_indexSection.index];
|
||||
if (needResetIndex) {
|
||||
[self addTimer];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)scrollToNearlyIndexAtDirection:(TYPagerScrollDirection)direction animate:(BOOL)animate {
|
||||
TYIndexSection indexSection = [self nearlyIndexPathAtDirection:direction];
|
||||
[self scrollToItemAtIndexSection:indexSection animate:animate];
|
||||
}
|
||||
|
||||
- (void)scrollToItemAtIndex:(NSInteger)index animate:(BOOL)animate {
|
||||
if (!_didLayout && _didReloadData) {
|
||||
_firstScrollIndex = index;
|
||||
}else {
|
||||
_firstScrollIndex = -1;
|
||||
}
|
||||
if (!_isInfiniteLoop) {
|
||||
[self scrollToItemAtIndexSection:TYMakeIndexSection(index, 0) animate:animate];
|
||||
return;
|
||||
}
|
||||
|
||||
[self scrollToItemAtIndexSection:TYMakeIndexSection(index, index >= self.curIndex ? _indexSection.section : _indexSection.section+1) animate:animate];
|
||||
}
|
||||
|
||||
- (void)scrollToItemAtIndexSection:(TYIndexSection)indexSection animate:(BOOL)animate {
|
||||
if (_numberOfItems <= 0 || ![self isValidIndexSection:indexSection]) {
|
||||
//NSLog(@"scrollToItemAtIndex: item indexSection is invalid!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (animate && [_delegate respondsToSelector:@selector(pagerViewWillBeginScrollingAnimation:)]) {
|
||||
[_delegate pagerViewWillBeginScrollingAnimation:self];
|
||||
}
|
||||
CGFloat offset = [self caculateOffsetXAtIndexSection:indexSection];
|
||||
[_collectionView setContentOffset:CGPointMake(offset, _collectionView.contentOffset.y) animated:animate];
|
||||
}
|
||||
|
||||
- (void)registerClass:(Class)Class forCellWithReuseIdentifier:(NSString *)identifier {
|
||||
[_collectionView registerClass:Class forCellWithReuseIdentifier:identifier];
|
||||
}
|
||||
|
||||
- (void)registerNib:(UINib *)nib forCellWithReuseIdentifier:(NSString *)identifier {
|
||||
[_collectionView registerNib:nib forCellWithReuseIdentifier:identifier];
|
||||
}
|
||||
|
||||
- (__kindof UICollectionViewCell *)dequeueReusableCellWithReuseIdentifier:(NSString *)identifier forIndex:(NSInteger)index {
|
||||
UICollectionViewCell *cell = [_collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:[NSIndexPath indexPathForItem:index inSection:_dequeueSection]];
|
||||
return cell;
|
||||
}
|
||||
|
||||
#pragma mark - configure layout
|
||||
|
||||
- (void)updateLayout {
|
||||
if (!self.layout) {
|
||||
return;
|
||||
}
|
||||
self.layout.isInfiniteLoop = _isInfiniteLoop;
|
||||
((TYCyclePagerTransformLayout *)_collectionView.collectionViewLayout).layout = self.layout;
|
||||
}
|
||||
|
||||
- (void)clearLayout {
|
||||
if (_needClearLayout) {
|
||||
_layout = nil;
|
||||
_needClearLayout = NO;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setNeedClearLayout {
|
||||
_needClearLayout = YES;
|
||||
}
|
||||
|
||||
- (void)setNeedUpdateLayout {
|
||||
if (!self.layout) {
|
||||
return;
|
||||
}
|
||||
[self clearLayout];
|
||||
[self updateLayout];
|
||||
[_collectionView.collectionViewLayout invalidateLayout];
|
||||
[self resetPagerViewAtIndex:_indexSection.index < 0 ? 0 :_indexSection.index];
|
||||
}
|
||||
|
||||
#pragma mark - pager index
|
||||
|
||||
- (BOOL)isValidIndexSection:(TYIndexSection)indexSection {
|
||||
return indexSection.index >= 0 && indexSection.index < _numberOfItems && indexSection.section >= 0 && indexSection.section < kPagerViewMaxSectionCount;
|
||||
}
|
||||
|
||||
- (TYIndexSection)nearlyIndexPathAtDirection:(TYPagerScrollDirection)direction{
|
||||
return [self nearlyIndexPathForIndexSection:_indexSection direction:direction];
|
||||
}
|
||||
|
||||
- (TYIndexSection)nearlyIndexPathForIndexSection:(TYIndexSection)indexSection direction:(TYPagerScrollDirection)direction {
|
||||
if (indexSection.index < 0 || indexSection.index >= _numberOfItems) {
|
||||
return indexSection;
|
||||
}
|
||||
|
||||
if (!_isInfiniteLoop) {
|
||||
if (direction == TYPagerScrollDirectionRight && indexSection.index == _numberOfItems - 1) {
|
||||
return _autoScrollInterval > 0 ? TYMakeIndexSection(0, 0) : indexSection;
|
||||
} else if (direction == TYPagerScrollDirectionRight) {
|
||||
return TYMakeIndexSection(indexSection.index+1, 0);
|
||||
}
|
||||
|
||||
if (indexSection.index == 0) {
|
||||
return _autoScrollInterval > 0 ? TYMakeIndexSection(_numberOfItems - 1, 0) : indexSection;
|
||||
}
|
||||
return TYMakeIndexSection(indexSection.index-1, 0);
|
||||
}
|
||||
|
||||
if (direction == TYPagerScrollDirectionRight) {
|
||||
if (indexSection.index < _numberOfItems-1) {
|
||||
return TYMakeIndexSection(indexSection.index+1, indexSection.section);
|
||||
}
|
||||
if (indexSection.section >= kPagerViewMaxSectionCount-1) {
|
||||
return TYMakeIndexSection(indexSection.index, kPagerViewMaxSectionCount-1);
|
||||
}
|
||||
return TYMakeIndexSection(0, indexSection.section+1);
|
||||
}
|
||||
|
||||
if (indexSection.index > 0) {
|
||||
return TYMakeIndexSection(indexSection.index-1, indexSection.section);
|
||||
}
|
||||
if (indexSection.section <= 0) {
|
||||
return TYMakeIndexSection(indexSection.index, 0);
|
||||
}
|
||||
return TYMakeIndexSection(_numberOfItems-1, indexSection.section-1);
|
||||
}
|
||||
|
||||
- (TYIndexSection)caculateIndexSectionWithOffsetX:(CGFloat)offsetX {
|
||||
if (_numberOfItems <= 0) {
|
||||
return TYMakeIndexSection(0, 0);
|
||||
}
|
||||
UICollectionViewFlowLayout *layout = (UICollectionViewFlowLayout *)_collectionView.collectionViewLayout;
|
||||
CGFloat leftEdge = _isInfiniteLoop ? _layout.sectionInset.left : _layout.onlyOneSectionInset.left;
|
||||
CGFloat width = CGRectGetWidth(_collectionView.frame);
|
||||
CGFloat middleOffset = offsetX + width/2;
|
||||
CGFloat itemWidth = layout.itemSize.width + layout.minimumInteritemSpacing;
|
||||
NSInteger curIndex = 0;
|
||||
NSInteger curSection = 0;
|
||||
if (middleOffset - leftEdge >= 0) {
|
||||
NSInteger itemIndex = (middleOffset - leftEdge+layout.minimumInteritemSpacing/2)/itemWidth;
|
||||
if (itemIndex < 0) {
|
||||
itemIndex = 0;
|
||||
}else if (itemIndex >= _numberOfItems*kPagerViewMaxSectionCount) {
|
||||
itemIndex = _numberOfItems*kPagerViewMaxSectionCount-1;
|
||||
}
|
||||
curIndex = itemIndex%_numberOfItems;
|
||||
curSection = itemIndex/_numberOfItems;
|
||||
}
|
||||
return TYMakeIndexSection(curIndex, curSection);
|
||||
}
|
||||
|
||||
- (CGFloat)caculateOffsetXAtIndexSection:(TYIndexSection)indexSection{
|
||||
if (_numberOfItems == 0) {
|
||||
return 0;
|
||||
}
|
||||
UICollectionViewFlowLayout *layout = (UICollectionViewFlowLayout *)_collectionView.collectionViewLayout;
|
||||
UIEdgeInsets edge = _isInfiniteLoop ? _layout.sectionInset : _layout.onlyOneSectionInset;
|
||||
CGFloat leftEdge = edge.left;
|
||||
CGFloat rightEdge = edge.right;
|
||||
CGFloat width = CGRectGetWidth(_collectionView.frame);
|
||||
CGFloat itemWidth = layout.itemSize.width + layout.minimumInteritemSpacing;
|
||||
CGFloat offsetX = 0;
|
||||
if (!_isInfiniteLoop && !_layout.itemHorizontalCenter && indexSection.index == _numberOfItems - 1) {
|
||||
offsetX = leftEdge + itemWidth*(indexSection.index + indexSection.section*_numberOfItems) - (width - itemWidth) - layout.minimumInteritemSpacing + rightEdge;
|
||||
}else {
|
||||
offsetX = leftEdge + itemWidth*(indexSection.index + indexSection.section*_numberOfItems) - layout.minimumInteritemSpacing/2 - (width - itemWidth)/2;
|
||||
}
|
||||
return MAX(offsetX, 0);
|
||||
}
|
||||
|
||||
- (void)resetPagerViewAtIndex:(NSInteger)index {
|
||||
if (_didLayout && _firstScrollIndex >= 0) {
|
||||
index = _firstScrollIndex;
|
||||
_firstScrollIndex = -1;
|
||||
}
|
||||
if (index < 0) {
|
||||
return;
|
||||
}
|
||||
if (index >= _numberOfItems) {
|
||||
index = 0;
|
||||
}
|
||||
[self scrollToItemAtIndexSection:TYMakeIndexSection(index, _isInfiniteLoop ? kPagerViewMaxSectionCount/3 : 0) animate:NO];
|
||||
if (!_isInfiniteLoop && _indexSection.index < 0) {
|
||||
[self scrollViewDidScroll:_collectionView];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)recyclePagerViewIfNeed {
|
||||
if (!_isInfiniteLoop) {
|
||||
return;
|
||||
}
|
||||
if (_indexSection.section > kPagerViewMaxSectionCount - kPagerViewMinSectionCount || _indexSection.section < kPagerViewMinSectionCount) {
|
||||
[self resetPagerViewAtIndex:_indexSection.index];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - UICollectionViewDataSource
|
||||
|
||||
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
|
||||
return _isInfiniteLoop ? kPagerViewMaxSectionCount : 1;
|
||||
}
|
||||
|
||||
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
|
||||
_numberOfItems = [_dataSource numberOfItemsInPagerView:self];
|
||||
return _numberOfItems;
|
||||
}
|
||||
|
||||
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
_dequeueSection = indexPath.section;
|
||||
if (_dataSourceFlags.cellForItemAtIndex) {
|
||||
return [_dataSource pagerView:self cellForItemAtIndex:indexPath.row];
|
||||
}
|
||||
NSAssert(NO, @"pagerView cellForItemAtIndex: is nil!");
|
||||
return nil;
|
||||
}
|
||||
|
||||
#pragma mark - UICollectionViewDelegateFlowLayout
|
||||
|
||||
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
|
||||
if (!_isInfiniteLoop) {
|
||||
return _layout.onlyOneSectionInset;
|
||||
}
|
||||
if (section == 0 ) {
|
||||
return _layout.firstSectionInset;
|
||||
}else if (section == kPagerViewMaxSectionCount -1) {
|
||||
return _layout.lastSectionInset;
|
||||
}
|
||||
return _layout.middleSectionInset;
|
||||
}
|
||||
|
||||
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath];
|
||||
if ([_delegate respondsToSelector:@selector(pagerView:didSelectedItemCell:atIndex:)]) {
|
||||
[_delegate pagerView:self didSelectedItemCell:cell atIndex:indexPath.item];
|
||||
}
|
||||
if ([_delegate respondsToSelector:@selector(pagerView:didSelectedItemCell:atIndexSection:)]) {
|
||||
[_delegate pagerView:self didSelectedItemCell:cell atIndexSection:TYMakeIndexSection(indexPath.item, indexPath.section)];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - UIScrollViewDelegate
|
||||
|
||||
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
|
||||
if (!_didLayout) {
|
||||
return;
|
||||
}
|
||||
TYIndexSection newIndexSection = [self caculateIndexSectionWithOffsetX:scrollView.contentOffset.x];
|
||||
if (_numberOfItems <= 0 || ![self isValidIndexSection:newIndexSection]) {
|
||||
NSLog(@"inVlaidIndexSection:(%ld,%ld)!",(long)newIndexSection.index,(long)newIndexSection.section);
|
||||
return;
|
||||
}
|
||||
TYIndexSection indexSection = _indexSection;
|
||||
_indexSection = newIndexSection;
|
||||
|
||||
if (_delegateFlags.pagerViewDidScroll) {
|
||||
[_delegate pagerViewDidScroll:self];
|
||||
}
|
||||
|
||||
if (_delegateFlags.didScrollFromIndexToNewIndex && !TYEqualIndexSection(_indexSection, indexSection)) {
|
||||
//NSLog(@"curIndex %ld",(long)_indexSection.index);
|
||||
[_delegate pagerView:self didScrollFromIndex:MAX(indexSection.index, 0) toIndex:_indexSection.index];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
|
||||
if (_autoScrollInterval > 0) {
|
||||
[self removeTimer];
|
||||
}
|
||||
_beginDragIndexSection = [self caculateIndexSectionWithOffsetX:scrollView.contentOffset.x];
|
||||
if ([_delegate respondsToSelector:@selector(pagerViewWillBeginDragging:)]) {
|
||||
[_delegate pagerViewWillBeginDragging:self];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {
|
||||
if (fabs(velocity.x) < 0.35 || !TYEqualIndexSection(_beginDragIndexSection, _indexSection)) {
|
||||
targetContentOffset->x = [self caculateOffsetXAtIndexSection:_indexSection];
|
||||
return;
|
||||
}
|
||||
TYPagerScrollDirection direction = TYPagerScrollDirectionRight;
|
||||
if ((scrollView.contentOffset.x < 0 && targetContentOffset->x <= 0) || (targetContentOffset->x < scrollView.contentOffset.x && scrollView.contentOffset.x < scrollView.contentSize.width - scrollView.frame.size.width)) {
|
||||
direction = TYPagerScrollDirectionLeft;
|
||||
}
|
||||
TYIndexSection indexSection = [self nearlyIndexPathForIndexSection:_indexSection direction:direction];
|
||||
targetContentOffset->x = [self caculateOffsetXAtIndexSection:indexSection];
|
||||
}
|
||||
|
||||
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
|
||||
if (_autoScrollInterval > 0) {
|
||||
[self addTimer];
|
||||
}
|
||||
if ([_delegate respondsToSelector:@selector(pagerViewDidEndDragging:willDecelerate:)]) {
|
||||
[_delegate pagerViewDidEndDragging:self willDecelerate:decelerate];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView {
|
||||
if ([_delegate respondsToSelector:@selector(pagerViewWillBeginDecelerating:)]) {
|
||||
[_delegate pagerViewWillBeginDecelerating:self];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
|
||||
[self recyclePagerViewIfNeed];
|
||||
if ([_delegate respondsToSelector:@selector(pagerViewDidEndDecelerating:)]) {
|
||||
[_delegate pagerViewDidEndDecelerating:self];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView {
|
||||
[self recyclePagerViewIfNeed];
|
||||
if ([_delegate respondsToSelector:@selector(pagerViewDidEndScrollingAnimation:)]) {
|
||||
[_delegate pagerViewDidEndScrollingAnimation:self];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - TYCyclePagerTransformLayoutDelegate
|
||||
|
||||
- (void)pagerViewTransformLayout:(TYCyclePagerTransformLayout *)pagerViewTransformLayout initializeTransformAttributes:(UICollectionViewLayoutAttributes *)attributes {
|
||||
if (_delegateFlags.initializeTransformAttributes) {
|
||||
[_delegate pagerView:self initializeTransformAttributes:attributes];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)pagerViewTransformLayout:(TYCyclePagerTransformLayout *)pagerViewTransformLayout applyTransformToAttributes:(UICollectionViewLayoutAttributes *)attributes {
|
||||
if (_delegateFlags.applyTransformToAttributes) {
|
||||
[_delegate pagerView:self applyTransformToAttributes:attributes];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)layoutSubviews {
|
||||
[super layoutSubviews];
|
||||
BOOL needUpdateLayout = !CGRectEqualToRect(_collectionView.frame, self.bounds);
|
||||
_collectionView.frame = self.bounds;
|
||||
if ((_indexSection.section < 0 || needUpdateLayout) && (_numberOfItems > 0 || _didReloadData)) {
|
||||
_didLayout = YES;
|
||||
[self setNeedUpdateLayout];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
((TYCyclePagerTransformLayout *)_collectionView.collectionViewLayout).delegate = nil;
|
||||
_collectionView.delegate = nil;
|
||||
_collectionView.dataSource = nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
47
Pods/TYCyclePagerView/TYCyclePagerViewDemo/TYCyclePagerView/TYPageControl.h
generated
Executable file
47
Pods/TYCyclePagerView/TYCyclePagerViewDemo/TYCyclePagerView/TYPageControl.h
generated
Executable file
@@ -0,0 +1,47 @@
|
||||
//
|
||||
// TYPageControl.h
|
||||
// TYCyclePagerViewDemo
|
||||
//
|
||||
// Created by tany on 2017/6/20.
|
||||
// Copyright © 2017年 tany. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface TYPageControl : UIControl
|
||||
|
||||
@property (nonatomic, assign) NSInteger numberOfPages; // default is 0
|
||||
@property (nonatomic, assign) NSInteger currentPage; // default is 0. value pinned to 0..numberOfPages-1
|
||||
|
||||
@property (nonatomic, assign) BOOL hidesForSinglePage; // hide the the indicator if there is only one page. default is NO
|
||||
|
||||
@property (nonatomic, assign) CGFloat pageIndicatorSpaing;
|
||||
@property (nonatomic, assign) UIEdgeInsets contentInset; // center will ignore this
|
||||
@property (nonatomic, assign ,readonly) CGSize contentSize; // real content size
|
||||
|
||||
// override super
|
||||
//@property (nonatomic, assign) UIControlContentVerticalAlignment contentVerticalAlignment; // how to position content vertically inside control. default is center
|
||||
//@property (nonatomic, assign) UIControlContentHorizontalAlignment contentHorizontalAlignment; // how to position content hozontally inside control. default is center
|
||||
|
||||
// indicatorTint color
|
||||
@property (nullable, nonatomic,strong) UIColor *pageIndicatorTintColor;
|
||||
@property (nullable, nonatomic,strong) UIColor *currentPageIndicatorTintColor;
|
||||
|
||||
// indicator image
|
||||
@property (nullable, nonatomic,strong) UIImage *pageIndicatorImage;
|
||||
@property (nullable, nonatomic,strong) UIImage *currentPageIndicatorImage;
|
||||
|
||||
@property (nonatomic, assign) UIViewContentMode indicatorImageContentMode; // default is UIViewContentModeCenter
|
||||
|
||||
@property (nonatomic, assign) CGSize pageIndicatorSize; // indicator size
|
||||
@property (nonatomic, assign) CGSize currentPageIndicatorSize; // default pageIndicatorSize
|
||||
|
||||
@property (nonatomic, assign) CGFloat animateDuring; // default 0.3
|
||||
|
||||
- (void)setCurrentPage:(NSInteger)currentPage animate:(BOOL)animate;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
285
Pods/TYCyclePagerView/TYCyclePagerViewDemo/TYCyclePagerView/TYPageControl.m
generated
Executable file
285
Pods/TYCyclePagerView/TYCyclePagerViewDemo/TYCyclePagerView/TYPageControl.m
generated
Executable file
@@ -0,0 +1,285 @@
|
||||
//
|
||||
// TYPageControl.m
|
||||
// TYCyclePagerViewDemo
|
||||
//
|
||||
// Created by tany on 2017/6/20.
|
||||
// Copyright © 2017年 tany. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TYPageControl.h"
|
||||
|
||||
@interface TYPageControl ()
|
||||
// UI
|
||||
@property (nonatomic, strong) NSArray<UIImageView *> *indicatorViews;
|
||||
|
||||
// Data
|
||||
@property (nonatomic, assign) BOOL forceUpdate;
|
||||
|
||||
@end
|
||||
|
||||
@implementation TYPageControl
|
||||
|
||||
#pragma mark - life cycle
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
if (self = [super initWithFrame:frame]) {
|
||||
[self configurePropertys];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
|
||||
if (self = [super initWithCoder:aDecoder]) {
|
||||
[self configurePropertys];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)configurePropertys {
|
||||
self.userInteractionEnabled = NO;
|
||||
_forceUpdate = NO;
|
||||
_animateDuring = 0.3;
|
||||
_pageIndicatorSpaing = 10;
|
||||
_indicatorImageContentMode = UIViewContentModeCenter;
|
||||
_pageIndicatorSize = CGSizeMake(6,6);
|
||||
_currentPageIndicatorSize = _pageIndicatorSize;
|
||||
_pageIndicatorTintColor = [UIColor colorWithRed:128/255. green:128/255. blue:128/255. alpha:1];
|
||||
_currentPageIndicatorTintColor = [UIColor whiteColor];
|
||||
}
|
||||
|
||||
- (void)willMoveToSuperview:(UIView *)newSuperview {
|
||||
[super willMoveToSuperview:newSuperview];
|
||||
if (newSuperview) {
|
||||
_forceUpdate = YES;
|
||||
[self updateIndicatorViews];
|
||||
_forceUpdate = NO;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - getter setter
|
||||
|
||||
- (CGSize)contentSize {
|
||||
CGFloat width = (_indicatorViews.count - 1) * (_pageIndicatorSize.width + _pageIndicatorSpaing) + _pageIndicatorSize.width + _contentInset.left +_contentInset.right;
|
||||
CGFloat height = _currentPageIndicatorSize.height + _contentInset.top + _contentInset.bottom;
|
||||
return CGSizeMake(width, height);
|
||||
}
|
||||
|
||||
- (void)setNumberOfPages:(NSInteger)numberOfPages {
|
||||
if (numberOfPages == _numberOfPages) {
|
||||
return;
|
||||
}
|
||||
_numberOfPages = numberOfPages;
|
||||
if (_currentPage >= numberOfPages) {
|
||||
_currentPage = 0;
|
||||
}
|
||||
[self updateIndicatorViews];
|
||||
if (_indicatorViews.count > 0) {
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setCurrentPage:(NSInteger)currentPage {
|
||||
if (_currentPage == currentPage || _indicatorViews.count <= currentPage) {
|
||||
return;
|
||||
}
|
||||
_currentPage = currentPage;
|
||||
if (!CGSizeEqualToSize(_currentPageIndicatorSize, _pageIndicatorSize)) {
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
[self updateIndicatorViewsBehavior];
|
||||
if (self.userInteractionEnabled) {
|
||||
[self sendActionsForControlEvents:UIControlEventValueChanged];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setCurrentPage:(NSInteger)currentPage animate:(BOOL)animate {
|
||||
if (animate) {
|
||||
[UIView animateWithDuration:_animateDuring animations:^{
|
||||
[self setCurrentPage:currentPage];
|
||||
}];
|
||||
}else {
|
||||
[self setCurrentPage:currentPage];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setPageIndicatorImage:(UIImage *)pageIndicatorImage {
|
||||
_pageIndicatorImage = pageIndicatorImage;
|
||||
[self updateIndicatorViewsBehavior];
|
||||
}
|
||||
|
||||
- (void)setCurrentPageIndicatorImage:(UIImage *)currentPageIndicatorImage {
|
||||
_currentPageIndicatorImage = currentPageIndicatorImage;
|
||||
[self updateIndicatorViewsBehavior];
|
||||
}
|
||||
|
||||
- (void)setPageIndicatorTintColor:(UIColor *)pageIndicatorTintColor {
|
||||
_pageIndicatorTintColor = pageIndicatorTintColor;
|
||||
[self updateIndicatorViewsBehavior];
|
||||
}
|
||||
|
||||
- (void)setCurrentPageIndicatorTintColor:(UIColor *)currentPageIndicatorTintColor {
|
||||
_currentPageIndicatorTintColor = currentPageIndicatorTintColor;
|
||||
[self updateIndicatorViewsBehavior];
|
||||
}
|
||||
|
||||
- (void)setPageIndicatorSize:(CGSize)pageIndicatorSize {
|
||||
if (CGSizeEqualToSize(_pageIndicatorSize, pageIndicatorSize)) {
|
||||
return;
|
||||
}
|
||||
_pageIndicatorSize = pageIndicatorSize;
|
||||
if (CGSizeEqualToSize(_currentPageIndicatorSize, CGSizeZero) || (_currentPageIndicatorSize.width < pageIndicatorSize.width && _currentPageIndicatorSize.height < pageIndicatorSize.height)) {
|
||||
_currentPageIndicatorSize = pageIndicatorSize;
|
||||
}
|
||||
if (_indicatorViews.count > 0) {
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setPageIndicatorSpaing:(CGFloat)pageIndicatorSpaing {
|
||||
_pageIndicatorSpaing = pageIndicatorSpaing;
|
||||
if (_indicatorViews.count > 0) {
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setCurrentPageIndicatorSize:(CGSize)currentPageIndicatorSize {
|
||||
if (CGSizeEqualToSize(_currentPageIndicatorSize, currentPageIndicatorSize)) {
|
||||
return;
|
||||
}
|
||||
_currentPageIndicatorSize = currentPageIndicatorSize;
|
||||
if (_indicatorViews.count > 0) {
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setContentHorizontalAlignment:(UIControlContentHorizontalAlignment)contentHorizontalAlignment {
|
||||
[super setContentHorizontalAlignment:contentHorizontalAlignment];
|
||||
if (_indicatorViews.count > 0) {
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setContentVerticalAlignment:(UIControlContentVerticalAlignment)contentVerticalAlignment {
|
||||
[super setContentVerticalAlignment:contentVerticalAlignment];
|
||||
if (_indicatorViews.count > 0) {
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - update indicator
|
||||
|
||||
- (void)updateIndicatorViews {
|
||||
if (!self.superview && !_forceUpdate) {
|
||||
return;
|
||||
}
|
||||
if (_indicatorViews.count == _numberOfPages) {
|
||||
[self updateIndicatorViewsBehavior];
|
||||
return;
|
||||
}
|
||||
NSMutableArray *indicatorViews = _indicatorViews ? [_indicatorViews mutableCopy] :[NSMutableArray array];
|
||||
if (indicatorViews.count < _numberOfPages) {
|
||||
for (NSInteger idx = indicatorViews.count; idx < _numberOfPages; ++idx) {
|
||||
UIImageView *indicatorView = [[UIImageView alloc]init];
|
||||
indicatorView.contentMode = _indicatorImageContentMode;
|
||||
[self addSubview:indicatorView];
|
||||
[indicatorViews addObject:indicatorView];
|
||||
}
|
||||
}else if (indicatorViews.count > _numberOfPages) {
|
||||
for (NSInteger idx = indicatorViews.count - 1; idx >= _numberOfPages; --idx) {
|
||||
UIImageView *indicatorView = indicatorViews[idx];
|
||||
[indicatorView removeFromSuperview];
|
||||
[indicatorViews removeObjectAtIndex:idx];
|
||||
}
|
||||
}
|
||||
_indicatorViews = [indicatorViews copy];
|
||||
[self updateIndicatorViewsBehavior];
|
||||
}
|
||||
|
||||
- (void)updateIndicatorViewsBehavior {
|
||||
if (_indicatorViews.count == 0 || (!self.superview && !_forceUpdate)) {
|
||||
return;
|
||||
}
|
||||
if (_hidesForSinglePage && _indicatorViews.count == 1) {
|
||||
UIImageView *indicatorView = _indicatorViews.lastObject;
|
||||
indicatorView.hidden = YES;
|
||||
return;
|
||||
}
|
||||
NSInteger index = 0;
|
||||
for (UIImageView *indicatorView in _indicatorViews) {
|
||||
if (_pageIndicatorImage) {
|
||||
indicatorView.contentMode = _indicatorImageContentMode;
|
||||
indicatorView.image = _currentPage == index ? _currentPageIndicatorImage : _pageIndicatorImage;
|
||||
}else {
|
||||
indicatorView.image = nil;
|
||||
indicatorView.backgroundColor = _currentPage == index ? _currentPageIndicatorTintColor : _pageIndicatorTintColor;
|
||||
}
|
||||
indicatorView.hidden = NO;
|
||||
++index;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - layout
|
||||
|
||||
- (void)layoutIndicatorViews {
|
||||
if (_indicatorViews.count == 0) {
|
||||
return;
|
||||
}
|
||||
CGFloat orignX = 0;
|
||||
CGFloat centerY = 0;
|
||||
CGFloat pageIndicatorSpaing = _pageIndicatorSpaing;
|
||||
switch (self.contentHorizontalAlignment) {
|
||||
case UIControlContentHorizontalAlignmentCenter:
|
||||
// ignore contentInset
|
||||
orignX = (CGRectGetWidth(self.frame) - (_indicatorViews.count - 1) * (_pageIndicatorSize.width + _pageIndicatorSpaing) - _currentPageIndicatorSize.width)/2;
|
||||
break;
|
||||
case UIControlContentHorizontalAlignmentLeft:
|
||||
orignX = _contentInset.left;
|
||||
break;
|
||||
case UIControlContentHorizontalAlignmentRight:
|
||||
orignX = CGRectGetWidth(self.frame) - ((_indicatorViews.count - 1) * (_pageIndicatorSize.width + _pageIndicatorSpaing) + _currentPageIndicatorSize.width) - _contentInset.right;
|
||||
break;
|
||||
case UIControlContentHorizontalAlignmentFill:
|
||||
orignX = _contentInset.left;
|
||||
if (_indicatorViews.count > 1) {
|
||||
pageIndicatorSpaing = (CGRectGetWidth(self.frame) - _contentInset.left - _contentInset.right - _pageIndicatorSize.width - (_indicatorViews.count - 1) * _pageIndicatorSize.width)/(_indicatorViews.count - 1);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
switch (self.contentVerticalAlignment) {
|
||||
case UIControlContentVerticalAlignmentCenter:
|
||||
centerY = CGRectGetHeight(self.frame)/2;
|
||||
break;
|
||||
case UIControlContentVerticalAlignmentTop:
|
||||
centerY = _contentInset.top + _currentPageIndicatorSize.height/2;
|
||||
break;
|
||||
case UIControlContentVerticalAlignmentBottom:
|
||||
centerY = CGRectGetHeight(self.frame) - _currentPageIndicatorSize.height/2 - _contentInset.bottom;
|
||||
break;
|
||||
case UIControlContentVerticalAlignmentFill:
|
||||
centerY = (CGRectGetHeight(self.frame) - _contentInset.top - _contentInset.bottom)/2 + _contentInset.top;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
NSInteger index = 0;
|
||||
for (UIImageView *indicatorView in _indicatorViews) {
|
||||
if (_pageIndicatorImage) {
|
||||
indicatorView.layer.cornerRadius = 0;
|
||||
}else {
|
||||
indicatorView.layer.cornerRadius = _currentPage == index ? _currentPageIndicatorSize.height/2 : _pageIndicatorSize.height/2;
|
||||
}
|
||||
CGSize size = index == _currentPage ? _currentPageIndicatorSize : _pageIndicatorSize;
|
||||
indicatorView.frame = CGRectMake(orignX, centerY - size.height/2, size.width, size.height);
|
||||
orignX += size.width + pageIndicatorSpaing;
|
||||
++index;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)layoutSubviews {
|
||||
[super layoutSubviews];
|
||||
[self layoutIndicatorViews];
|
||||
}
|
||||
|
||||
@end
|
||||
Reference in New Issue
Block a user