2022-03-14

#import "TRCardListView.h"

#define TR_HEIGTH [UIScreen mainScreen].bounds.size.height

#define TR_WIDTH [UIScreen mainScreen].bounds.size.width

#ifndef __OPTIMIZE__

#? ? define TRLog(...) NSLog(__VA_ARGS__)

#else

#? ? define TRLog(...)

#endif

@interface TRCard : NSObject

@property (nonatomic, strong) UIView *view;

@property (nonatomic, assign) CGFloat positionY;

@end

@implementation TRCard

- (instancetype)initWithPositionY:(CGFloat)positionY{

? ?

? ? if (self = [super init]) {

? ? ? ? _positionY = positionY;

? ? ? ? _view = nil;

? ? }

? ? return self;

}

@end

@interface TRCardListView()

@property (nonatomic, strong) UIView *contentView;

//用來存儲card位置

@property (nonatomic, strong) NSMutableArray<TRCard *> * cards;

@property (nonatomic, strong) NSMutableArray<UIView *> * unUsedCards;

@property (nonatomic, assign) NSInteger countOfCard;

@property (nonatomic) Class cardClass;

@end

@implementation TRCardListView

- (void)registerForReuseWithClass:(Class)cardClass{

? ?

? ? _cardClass = cardClass;

? ? [self updateLayout];

}

- (UIView *)dequeueReusableCardAtIndex:(NSInteger)index{

? ?

? ? UIView *view = nil;

? ? if (_unUsedCards.count > 0) {

? ? ? ? view = _unUsedCards.firstObject;

? ? }else{

? ? ? ? UIView *card = [[_cardClass alloc] initWithFrame:CGRectMake(0, 0, TR_WIDTH, TR_HEIGTH)];

? ? ? ? view = card;

? ? ? ?

? ? ? ? UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapGesture:)];

? ? ? ? [card addGestureRecognizer:tap];

? ? ? ?

//? ? ? ? UISwipeGestureRecognizer *swipe = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleSwipeGesture:)];

//? ? ? ? swipe.direction = UISwipeGestureRecognizerDirectionRight;

//? ? ? ? [card addGestureRecognizer:swipe];

? ? }

? ? return view;

}

- (void)handleTapGesture:(UITapGestureRecognizer *)tap{

? ? UIView *view = tap.view;

? ? if (_trDelegate && [_trDelegate respondsToSelector:@selector(tr_cardListView:didSelectCardAtIndex:)]) {

? ? ? ? for (int i = 0; i < self.countOfCard; i++) {

? ? ? ? ? ? if (_cards[i].view) {

? ? ? ? ? ? ? ? if (view == _cards[i].view) {

? ? ? ? ? ? ? ? ? ? [_trDelegate tr_cardListView:self didSelectCardAtIndex:i];

? ? ? ? ? ? ? ? ? ? break;

? ? ? ? ? ? ? ? }

? ? ? ? ? ? }

? ? ? ? }

? ? }

}

//- (void)handleSwipeGesture:(UISwipeGestureRecognizer *)swipe{

//? ? NSLog(@"swipe");

//? ? UIView *view = swipe.view;

//}

- (void)reloadData{

? ?

? ? [self initCards];

? ? [self updateLayout];

}

- (void)awakeFromNib{

? ?

? ? [super awakeFromNib];

? ? [self setupContentView];

? ? [self setupDefaultValue];

? ? self.contentView.frame = self.bounds;

}

- (instancetype)init{

? ?

? ? if (self = [super init]) {

? ? ? ? [self setupDefaultValue];

? ? ? ? [self setupContentView];

? ? }

? ? return self;

}

- (void)setFrame:(CGRect)frame{

? ?

? ? [super setFrame:frame];

? ? self.contentView.frame = self.bounds;

}

- (instancetype)initWithFrame:(CGRect)frame{

? ?

? ? if (self = [super initWithFrame:frame]) {

? ? ? ? [self setupContentView];

? ? ? ? [self setupDefaultValue];

? ? }

? ? return self;

}

- (void)setupContentView{

? ?

? ? _contentView = [[UIView alloc] init];

? ? _contentView.backgroundColor = [UIColor clearColor];

? ? [self addSubview:_contentView];

}

- (void)setupDefaultValue{

? ?

? ? _top = 64.0;

? ? _distance = 64.0;

}

- (void)initCards{

? ?

? ? _cards = [NSMutableArray array];

? ? _unUsedCards = [NSMutableArray array];

? ? NSInteger count = self.countOfCard;

? ? for (NSInteger i = 0; i < count; i++) {

? ? ? ? TRCard *card = [[TRCard alloc] initWithPositionY:0];

? ? ? ? [_cards insertObject:card atIndex:0];

? ? }

}

- (void)setTrDelegate:(id<TRCardListViewDelegate>)trDelegate{

? ? _trDelegate = trDelegate;

? ? if (self.countOfCard) {

? ? ? ? [self initCards];

? ? ? ? [self updateLayout];

? ? }

}

- (void)setTrDataSource:(id<TRCardListViewDataSource>)trDataSource{

? ? _trDataSource = trDataSource;

? ? if (self.countOfCard) {

? ? ? ? [self initCards];

? ? ? ? [self updateLayout];

? ? }

}

- (NSInteger)countOfCard{

? ?

? ? if (_trDataSource && [_trDataSource respondsToSelector:@selector(tr_numberOfCardsInCardListView:)]) {

? ? ? ? return [_trDataSource tr_numberOfCardsInCardListView:self];

? ? }

? ? return 0;

}

- (void)setTop:(CGFloat)top{

? ?

? ? _top = top;

? ? [self updateLayout];

}

- (void)setDistance:(CGFloat)distance{

? ?

? ? _distance = distance;

? ? [self updateLayout];

}

- (void)setContentOffset:(CGPoint)contentOffset{

? ?

? ? [self updateLayoutOfCardWithContentOffset:contentOffset];

? ? [super setContentOffset:contentOffset];

}

- (void)updateLayout{

? ?

? ? self.contentSize = CGSizeMake(TR_WIDTH, TR_HEIGTH + self.distance * self.countOfCard - 1.5);

? ? self.contentOffset = CGPointMake(0, 0);

}

- (void)updateLayoutOfCardWithContentOffset:(CGPoint)contentOffset{

? ?

? ? self.contentView.frame = CGRectMake(0, contentOffset.y, TR_WIDTH, TR_HEIGTH);

? ? [_cards enumerateObjectsUsingBlock:^(TRCard * card, NSUInteger idx, BOOL *stop) {

? ? ? ?

? ? ? ? NSInteger value = self.distance;

? ? ? ? /*************設置位置***************/

? ? ? ? NSInteger begin_y = value * (self.countOfCard - idx - 1);

? ? ? ? CGFloat distance_y = self.contentSize.height - contentOffset.y - TR_HEIGTH - begin_y;

? ? ? ? CGFloat positionY = self.top + pow(distance_y, 2) / pow(2, 6);

? ? ? ? if (distance_y >= -50) {

? ? ? ? ? ? CGFloat alpha = distance_y >= 0?1:(distance_y + 50)/ 50;

? ? ? ? ? ? card.view.alpha = alpha;

? ? ? ? }else{

? ? ? ? ? ? card.view.alpha = 0;

? ? ? ? }

? ? ? ? card.positionY = positionY;

? ? ? ? if (positionY <= TR_HEIGTH) {

? ? ? ? ? ? if (card.view == nil) {

? ? ? ? ? ? ? ? [self setViewInCard:card atIndex:idx];

? ? ? ? ? ? ? ? [self addCardWithCard:card atIndex:idx];;

? ? ? ? ? ? }

? ? ? ? ? ? [self updateOriginWithView:card.view newOriginY:positionY];

? ? ? ? ? ? /*************設置大小***************/

? ? ? ? ? ? CGFloat scale = 0.70;

? ? ? ? ? ? scale = (positionY * 0.75 + 70) / 1000 + scale >= 0.95?0.95:(positionY * 0.75 + 50) / 1000 + scale;

? ? ? ? ? ? card.view.layer.transform = CATransform3DMakeScale(scale, scale, 1);

? ? ? ? }else{

? ? ? ? ? ? if (card.view != nil) {

? ? ? ? ? ? ? ? [_unUsedCards addObject:card.view];

? ? ? ? ? ? ? ? [card.view removeFromSuperview];

? ? ? ? ? ? ? ? card.view = nil;

? ? ? ? ? ? }

? ? ? ? }

? ? }];

}

- (void)setViewInCard:(TRCard *)card atIndex:(NSInteger)index{

? ?

? ? if (self.trDataSource && [self.trDataSource respondsToSelector:@selector(tr_cardListView:cardAtIndex:)]) {

? ? ? ?

? ? ? ? UIView * view = [self.trDataSource tr_cardListView:self cardAtIndex:index];

? ? ? ? card.view = view;

? ? ? ? if ([_unUsedCards containsObject:view]) {

? ? ? ? ? ? [_unUsedCards removeObject:view];

? ? ? ? }

? ? }else{

? ? ? ? TRLog(@"未實現(xiàn) Method: \"tr_carListView:cardAtIndex:\"");

? ? }

}

- (void)addCardWithCard:(TRCard *)card atIndex:(NSInteger)index{

? ?

? ? if (index == 0) {

? ? ? ? [self.contentView insertSubview:card.view atIndex:0];

? ? }else if (index == self.countOfCard - 1){

? ? ? ? [self.contentView addSubview:card.view];

? ? }else if (self.cards[index + 1].view){

? ? ? ? [self.contentView insertSubview:card.view atIndex:0];

? ? }else if (self.cards[index - 1].view){

? ? ? ? [self.contentView addSubview:card.view];

? ? }

}

- (void)updateOriginWithView:(UIView *)view newOriginY:(CGFloat)originY{

? ?

? ? CGSize size = view.frame.size;

? ? view.frame = CGRectMake(view.frame.origin.x, originY, size.width, size.height);

}

@end//

//? TRCardListView.m

//? 卡片堆疊效果實現(xiàn)

//

//? Created by cry on 2017/6/8.

//? Copyright ? 2017年 egova. All rights reserved.

//


#import "TRCardListView.h"


#define TR_HEIGTH [UIScreen mainScreen].bounds.size.height

#define TR_WIDTH [UIScreen mainScreen].bounds.size.width


#ifndef __OPTIMIZE__

#? ? define TRLog(...) NSLog(__VA_ARGS__)

#else

#? ? define TRLog(...)

#endif


@interface TRCard : NSObject


@property (nonatomic, strong) UIView *view;

@property (nonatomic, assign) CGFloat positionY;


@end


@implementation TRCard


- (instancetype)initWithPositionY:(CGFloat)positionY{

? ?

? ? if (self = [super init]) {

? ? ? ? _positionY = positionY;

? ? ? ? _view = nil;

? ? }

? ? return self;

}


@end


@interface TRCardListView()


@property (nonatomic, strong) UIView *contentView;

//用來存儲card位置

@property (nonatomic, strong) NSMutableArray<TRCard *> * cards;

@property (nonatomic, strong) NSMutableArray<UIView *> * unUsedCards;

@property (nonatomic, assign) NSInteger countOfCard;

@property (nonatomic

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市拭嫁,隨后出現(xiàn)的幾起案子可免,更是在濱河造成了極大的恐慌,老刑警劉巖做粤,帶你破解...
    沈念sama閱讀 218,451評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件浇借,死亡現(xiàn)場離奇詭異,居然都是意外死亡怕品,警方通過查閱死者的電腦和手機妇垢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,172評論 3 394
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來肉康,“玉大人闯估,你說我怎么就攤上這事『鸷停” “怎么了涨薪?”我有些...
    開封第一講書人閱讀 164,782評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長炫乓。 經常有香客問我刚夺,道長,這世上最難降的妖魔是什么末捣? 我笑而不...
    開封第一講書人閱讀 58,709評論 1 294
  • 正文 為了忘掉前任侠姑,我火速辦了婚禮,結果婚禮上箩做,老公的妹妹穿的比我還像新娘莽红。我一直安慰自己,他們只是感情好邦邦,可當我...
    茶點故事閱讀 67,733評論 6 392
  • 文/花漫 我一把揭開白布安吁。 她就那樣靜靜地躺著醉蚁,像睡著了一般。 火紅的嫁衣襯著肌膚如雪柳畔。 梳的紋絲不亂的頭發(fā)上馍管,一...
    開封第一講書人閱讀 51,578評論 1 305
  • 那天,我揣著相機與錄音薪韩,去河邊找鬼确沸。 笑死,一個胖子當著我的面吹牛俘陷,可吹牛的內容都是我干的罗捎。 我是一名探鬼主播,決...
    沈念sama閱讀 40,320評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼拉盾,長吁一口氣:“原來是場噩夢啊……” “哼桨菜!你這毒婦竟也來了?” 一聲冷哼從身側響起捉偏,我...
    開封第一講書人閱讀 39,241評論 0 276
  • 序言:老撾萬榮一對情侶失蹤倒得,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后夭禽,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體霞掺,經...
    沈念sama閱讀 45,686評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,878評論 3 336
  • 正文 我和宋清朗相戀三年讹躯,在試婚紗的時候發(fā)現(xiàn)自己被綠了菩彬。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片波附。...
    茶點故事閱讀 39,992評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡乔遮,死狀恐怖咱筛,靈堂內的尸體忽然破棺而出女轿,到底是詐尸還是另有隱情,我是刑警寧澤堤框,帶...
    沈念sama閱讀 35,715評論 5 346
  • 正文 年R本政府宣布朋蔫,位于F島的核電站找都,受9級特大地震影響萝究,放射性物質發(fā)生泄漏免都。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,336評論 3 330
  • 文/蒙蒙 一糊肤、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧氓鄙,春花似錦馆揉、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,912評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽舷暮。三九已至,卻和暖如春噩茄,著一層夾襖步出監(jiān)牢的瞬間下面,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,040評論 1 270
  • 我被黑心中介騙來泰國打工绩聘, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留沥割,地道東北人。 一個月前我還...
    沈念sama閱讀 48,173評論 3 370
  • 正文 我出身青樓凿菩,卻偏偏與公主長得像机杜,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子衅谷,可洞房花燭夜當晚...
    茶點故事閱讀 44,947評論 2 355

推薦閱讀更多精彩內容