// // 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 () @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