346 lines
12 KiB
Objective-C
346 lines
12 KiB
Objective-C
//
|
|
// IfishCardScrollView.m
|
|
// ShotViewAnimation
|
|
//
|
|
// Created by imac on 16/10/25.
|
|
// Copyright © 2016年 xiang. All rights reserved.
|
|
//
|
|
|
|
#import "IfishCardScrollView.h"
|
|
#define kGCRatio 0.8
|
|
#define kGCViewWidth CGRectGetWidth(self.frame)
|
|
#define kGCViewHeight CGRectGetHeight(self.frame)
|
|
#define kGCScrollViewWidth kGCViewWidth*kGCRatio
|
|
@interface IfishCardScrollView ()<UIScrollViewDelegate,UIGestureRecognizerDelegate>
|
|
|
|
|
|
@property (nonatomic, strong) NSMutableArray *cards;
|
|
@property (nonatomic, assign) NSInteger totalNumberOfCards;
|
|
@property (nonatomic, assign) NSInteger startCardIndex;
|
|
@property (nonatomic, assign) NSInteger currentCardIndex;
|
|
@property (nonatomic ,strong) UIPageControl *pageControl;
|
|
|
|
@end
|
|
|
|
@implementation IfishCardScrollView
|
|
#pragma mark - initialize
|
|
|
|
- (instancetype)initWithFrame:(CGRect)frame {
|
|
self = [super initWithFrame:frame];
|
|
if (self) {
|
|
[self setUp];
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (void)setUp{
|
|
|
|
self.scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, kGCScrollViewWidth, kGCViewHeight)];
|
|
self.scrollView.center = self.center;
|
|
self.scrollView.showsHorizontalScrollIndicator = NO;
|
|
self.scrollView.showsVerticalScrollIndicator = NO;
|
|
self.scrollView.clipsToBounds = NO;
|
|
self.scrollView.delegate = self;
|
|
self.scrollView.pagingEnabled = YES;
|
|
self.scrollView.bounces =YES;
|
|
|
|
//self.scrollView.backgroundColor = [UIColor blueColor];
|
|
|
|
[self addSubview:self.scrollView];
|
|
|
|
self.cards = [NSMutableArray array];
|
|
self.startCardIndex = 0;
|
|
self.currentCardIndex = 0;
|
|
self.canDeleteCard = NO;
|
|
|
|
//CGRect pagerect=[self convertRect:self.pageControl.frame toView:self.scrollView];
|
|
self.pageControl = [[UIPageControl alloc] initWithFrame:CGRectMake(CGRectGetMinX(self.scrollView.frame), CGRectGetMaxY(self.scrollView.frame) - 30, kGCScrollViewWidth, 20)];
|
|
|
|
self.pageControl.numberOfPages = 2;
|
|
self.pageControl.currentPage = 0;
|
|
|
|
[self.pageControl setValue:[UIImage imageNamed:@"equipment_point"] forKeyPath:@"pageImage"];
|
|
[self.pageControl setValue:[UIImage imageNamed:@"equipment_longpoint"] forKeyPath:@"currentPageImage"];
|
|
|
|
//self.pageControl.backgroundColor = [UIColor yellowColor];
|
|
|
|
[self.pageControl addTarget:self action:@selector(changePage:) forControlEvents:UIControlEventValueChanged];
|
|
|
|
[self addSubview:self.pageControl];
|
|
|
|
|
|
}
|
|
|
|
- (void)changePage:(id)sender
|
|
{
|
|
|
|
|
|
[self.pageControl updateCurrentPageDisplay];
|
|
[self.pageControl setValue:[UIImage imageNamed:@"equipment_point"] forKeyPath:@"pageImage"];
|
|
[self.pageControl setValue:[UIImage imageNamed:@"equipment_longpoint"] forKeyPath:@"currentPageImage"];
|
|
|
|
NSInteger page = self.pageControl.currentPage;
|
|
|
|
|
|
int index =(int)page;
|
|
|
|
[self updatePageControlImageWithCurentPage:index];
|
|
// update the scroll view to the appropriate page
|
|
[self.scrollView setContentOffset:[self contentOffsetWithIndex:page] animated:YES];
|
|
}
|
|
|
|
|
|
|
|
#pragma mark - public methods
|
|
|
|
- (void)loadCard {
|
|
|
|
|
|
|
|
for (UIView *card in self.cards) {
|
|
[card removeFromSuperview];
|
|
}
|
|
|
|
self.totalNumberOfCards = [self.cardDataSource numberOfCards];
|
|
if (self.totalNumberOfCards == 0) {
|
|
return;
|
|
}
|
|
|
|
[self.scrollView setContentSize:CGSizeMake(kGCScrollViewWidth*self.totalNumberOfCards, kGCViewHeight - 64)];
|
|
|
|
[self.scrollView setContentOffset:[self contentOffsetWithIndex:0]];
|
|
|
|
for (NSInteger index = 0; index < (self.totalNumberOfCards < 4 ? self.totalNumberOfCards : 4); index++) {
|
|
UIView *card = [self.cardDataSource cardReuseView:nil atIndex:index];
|
|
card.center = [self centerForCardWithIndex:index];
|
|
card.tag = index;
|
|
[self.scrollView addSubview:card];
|
|
[self.cards addObject:card];
|
|
|
|
if (self.canDeleteCard) {
|
|
UIPanGestureRecognizer *deleteGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(deleteCard:)];
|
|
deleteGesture.minimumNumberOfTouches = 1;
|
|
deleteGesture.maximumNumberOfTouches = 1;
|
|
deleteGesture.delegate = self;
|
|
[card addGestureRecognizer:deleteGesture];
|
|
}
|
|
|
|
[self.cardDelegate updateCard:card withProgress:1 direction:CardMoveDirectionNone];
|
|
}
|
|
|
|
|
|
}
|
|
|
|
- (NSArray *)allCards {
|
|
return self.cards;
|
|
}
|
|
|
|
- (NSInteger)currentCard {
|
|
return self.currentCardIndex;
|
|
}
|
|
|
|
#pragma mark - private methods
|
|
|
|
- (void)scrollToIndex:(NSInteger)index animated:(BOOL)animated {
|
|
[self.scrollView setContentOffset:[self contentOffsetWithIndex:index] animated:animated];
|
|
}
|
|
|
|
- (CGPoint)centerForCardWithIndex:(NSInteger)index {
|
|
return CGPointMake(kGCScrollViewWidth*(index + 0.5), self.scrollView.center.y);
|
|
}
|
|
|
|
- (CGPoint)contentOffsetWithIndex:(NSInteger)index {
|
|
return CGPointMake(kGCScrollViewWidth*index, 0);
|
|
}
|
|
|
|
- (NSInteger)indexMapperTag:(NSInteger)tag {
|
|
for (NSInteger index = 0; index < self.cards.count; index++) {
|
|
UIView *card = [self.cards objectAtIndex:index];
|
|
if (card.tag == tag) {
|
|
return index;
|
|
break;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
- (void)reloadCardWithIndex:(NSInteger)index {
|
|
[self reuseDeleteCardWithIndex:index];
|
|
if (index == 3) {
|
|
self.currentCardIndex-=1;
|
|
}
|
|
self.totalNumberOfCards-=1;
|
|
|
|
[UIView animateWithDuration:0.3 animations:^{
|
|
[self.scrollView setContentSize:CGSizeMake(kGCScrollViewWidth*self.totalNumberOfCards, kGCViewHeight)];
|
|
for (UIView *card in self.cards) {
|
|
[self.cardDelegate updateCard:card withProgress:1 direction:CardMoveDirectionNone];
|
|
}
|
|
}];
|
|
}
|
|
|
|
- (void)deleteCard:(UIPanGestureRecognizer *)gesture {
|
|
CGPoint translatedPoint = [gesture translationInView:gesture.view];
|
|
CGPoint cardCenter = CGPointMake(gesture.view.center.x, kGCViewHeight/2);
|
|
CGFloat progress = fabs(translatedPoint.y/(kGCViewHeight/2));
|
|
if (gesture.state == UIGestureRecognizerStateChanged) {
|
|
cardCenter.y+=translatedPoint.y;
|
|
[gesture.view setCenter:cardCenter];
|
|
gesture.view.layer.opacity = 1 - 0.2*progress;
|
|
} else if (gesture.state == UIGestureRecognizerStateEnded) {
|
|
CGPoint velocity = [gesture velocityInView:gesture.view];
|
|
if ((translatedPoint.y < 0 && progress >= 1.0) || (translatedPoint.y < 0 && fabs(velocity.y) > 500)) {
|
|
[UIView animateWithDuration:0.3 animations:^{
|
|
[gesture.view setCenter:CGPointMake(gesture.view.center.x, -kGCViewHeight/2)];
|
|
} completion:^(BOOL finished) {
|
|
[self reloadCardWithIndex:[self indexMapperTag:gesture.view.tag]];
|
|
[self.cardDataSource deleteCardWithIndex:gesture.view.tag];
|
|
}];
|
|
} else {
|
|
[UIView animateWithDuration:0.3 animations:^{
|
|
[gesture.view setCenter:cardCenter];
|
|
gesture.view.layer.opacity = 1.0;
|
|
}];
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)reuseCardWithMoveDirection:(CardMoveDirection)moveDirection {
|
|
BOOL isLeft = moveDirection == CardMoveDirectionLeft;
|
|
UIView *card = nil;
|
|
if (isLeft) {
|
|
if (self.currentCardIndex > self.totalNumberOfCards - 3 || self.currentCardIndex < 2) {
|
|
return;
|
|
}
|
|
card = [self.cards objectAtIndex:0];
|
|
card.tag+=4;
|
|
} else {
|
|
if (self.currentCardIndex > self.totalNumberOfCards - 4 ||
|
|
self.currentCardIndex < 1) {
|
|
return;
|
|
}
|
|
card = [self.cards objectAtIndex:3];
|
|
card.tag-=4;
|
|
}
|
|
card.center = [self centerForCardWithIndex:card.tag];
|
|
[self.cardDataSource cardReuseView:card atIndex:card.tag];
|
|
[self ascendingSortCards];
|
|
}
|
|
|
|
- (void)reuseDeleteCardWithIndex:(NSInteger)index {
|
|
if (self.totalNumberOfCards <= 4) {
|
|
[(UIView *)[self.cards objectAtIndex:index] removeFromSuperview];
|
|
[self resetTagFromIndex:index];
|
|
[self.cards removeObjectAtIndex:index];
|
|
[self ascendingSortCards];
|
|
return;
|
|
}
|
|
|
|
UIView *card = [self.cards objectAtIndex:index];
|
|
NSInteger fromIndex = index;
|
|
if (index == 0) {
|
|
card.tag+=4;
|
|
fromIndex = index - 1;
|
|
} else if (index == 3) {
|
|
card.tag-=4;
|
|
} else {
|
|
NSInteger lastTag = ((UIView *)[self.cards lastObject]).tag;
|
|
NSInteger firstTag = ((UIView *)[self.cards firstObject]).tag;
|
|
if (lastTag == self.totalNumberOfCards - 1) {
|
|
card.tag = firstTag - 1;
|
|
} else {
|
|
card.tag = lastTag + 1;
|
|
fromIndex = index - 1;
|
|
}
|
|
}
|
|
card.center = [self centerForCardWithIndex:card.tag];
|
|
[self ascendingSortCards];
|
|
[self resetTagFromIndex:fromIndex];
|
|
[self.cardDataSource cardReuseView:card atIndex:card.tag];
|
|
}
|
|
|
|
- (void)resetTagFromIndex:(NSInteger)index {
|
|
[self.cards enumerateObjectsUsingBlock:^(UIView *card, NSUInteger idx, BOOL * _Nonnull stop) {
|
|
if ((NSInteger)idx > index) {
|
|
card.tag-=1;
|
|
[UIView animateWithDuration:0.3 animations:^{
|
|
card.center = [self centerForCardWithIndex:card.tag];
|
|
}];
|
|
}
|
|
}];
|
|
}
|
|
|
|
- (void)ascendingSortCards {
|
|
[self.cards sortUsingComparator:^NSComparisonResult(UIView *obj1, UIView *obj2) {
|
|
return obj1.tag > obj2.tag;
|
|
}];
|
|
}
|
|
|
|
#pragma mark - UIGestureRecognizerDelegate
|
|
|
|
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
|
|
if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) {
|
|
CGPoint translatedPoint = [(UIPanGestureRecognizer *)gestureRecognizer translationInView:gestureRecognizer.view];
|
|
if (fabs(translatedPoint.y) > fabs(translatedPoint.x)) {
|
|
return YES;
|
|
}
|
|
}
|
|
return NO;
|
|
}
|
|
|
|
#pragma mark - UIScrollViewDelegate
|
|
|
|
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
|
|
CGFloat orginContentOffset = self.currentCardIndex*kGCScrollViewWidth;
|
|
CGFloat diff = scrollView.contentOffset.x - orginContentOffset;
|
|
CGFloat progress = fabs(diff)/(kGCViewWidth*0.8);
|
|
CardMoveDirection direction = diff > 0 ? CardMoveDirectionLeft : CardMoveDirectionRight;
|
|
for (UIView *card in self.cards) {
|
|
[self.cardDelegate updateCard:card withProgress:progress direction:direction];
|
|
}
|
|
|
|
if (fabs(diff) >= kGCScrollViewWidth*0.8) {
|
|
self.currentCardIndex = direction == CardMoveDirectionLeft ? self.currentCardIndex + 1 : self.currentCardIndex - 1;
|
|
[self reuseCardWithMoveDirection:direction];
|
|
}
|
|
}
|
|
|
|
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
|
|
//[self.pageControl updateCurrentPageDisplay];
|
|
|
|
self.pageControl.currentPage = self.currentCardIndex;
|
|
// [self.pageControl setValue:[UIImage imageNamed:@"equipment_point"] forKeyPath:@"pageImage"];
|
|
// [self.pageControl setValue:[UIImage imageNamed:@"equipment_longpoint"] forKeyPath:@"currentPageImage"];
|
|
int index = (int)self.currentCardIndex;
|
|
|
|
[self updatePageControlImageWithCurentPage:index];
|
|
|
|
}
|
|
|
|
-(void)updatePageControlImageWithCurentPage:(int)index{
|
|
for (int i=0; i<[self.pageControl.subviews count]; i++) {
|
|
|
|
UIImageView* dot = [self.pageControl.subviews objectAtIndex:i];
|
|
|
|
CGSize size;
|
|
|
|
size.height = 8; //自定义圆点的大小
|
|
|
|
size.width = 8; //自定义圆点的大小
|
|
[dot setFrame:CGRectMake(dot.frame.origin.x, dot.frame.origin.y, size.width, size.width)];
|
|
|
|
if (i==index) {
|
|
dot.image=[UIImage imageNamed:@"equipment_longpoint"] ;
|
|
[dot setFrame:CGRectMake(dot.frame.origin.x, dot.frame.origin.y, size.width *2.5, size.width)];
|
|
}else{
|
|
dot.image=[UIImage imageNamed:@"equipment_point"] ;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
@end
|