├── GXCardView.gif ├── GXCardView.podspec ├── GXCardView ├── GXCardView.h └── GXCardView.m ├── GXCardViewSample ├── GXCardViewDemo.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ ├── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ │ └── xcuserdata │ │ │ ├── Gin.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ │ │ ├── guoshengyong.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ │ │ ├── jason.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ │ │ └── shengyongguo.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ └── xcuserdata │ │ ├── Gin.xcuserdatad │ │ ├── xcdebugger │ │ │ └── Breakpoints_v2.xcbkptlist │ │ └── xcschemes │ │ │ └── xcschememanagement.plist │ │ ├── guoshengyong.xcuserdatad │ │ ├── xcdebugger │ │ │ └── Breakpoints_v2.xcbkptlist │ │ └── xcschemes │ │ │ └── xcschememanagement.plist │ │ ├── jason.xcuserdatad │ │ ├── xcdebugger │ │ │ └── Breakpoints_v2.xcbkptlist │ │ └── xcschemes │ │ │ └── xcschememanagement.plist │ │ └── shengyongguo.xcuserdatad │ │ └── xcschemes │ │ └── xcschememanagement.plist ├── GXCardViewDemo │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ └── Contents.json │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── GXCardItemDemoCell.h │ ├── GXCardItemDemoCell.m │ ├── GXCardItemDemoCell.xib │ ├── Info.plist │ ├── ViewController.h │ ├── ViewController.m │ └── main.m ├── GXCardViewDemoTests │ ├── GXCardViewDemoTests.m │ └── Info.plist └── GXCardViewDemoUITests │ ├── GXCardViewDemoUITests.m │ └── Info.plist ├── LICENSE └── README.md /GXCardView.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gsyhei/GXCardView/e11971246f4f1476d55e31571d5818c6647ff31a/GXCardView.gif -------------------------------------------------------------------------------- /GXCardView.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # Be sure to run `pod spec lint GXCardView.podspec' to ensure this is a 3 | # valid spec and to remove all comments including this before submitting the spec. 4 | # 5 | # To learn more about Podspec attributes see http://docs.cocoapods.org/specification.html 6 | # To see working Podspecs in the CocoaPods repo see https://github.com/CocoaPods/Specs/ 7 | # 8 | 9 | Pod::Spec.new do |s| 10 | 11 | s.name = "GXCardView" 12 | s.version = "0.1.5" 13 | s.summary = "一个卡片式布局,类似(探探附近/QQ颜值匹配)等..." 14 | s.homepage = "https://github.com/gsyhei/GXCardView" 15 | s.license = "MIT" 16 | s.author = { "Gin" => "279694479@qq.com" } 17 | s.platform = :ios, "7.0" 18 | s.source = { :git => "https://github.com/gsyhei/GXCardView.git", :tag => "0.1.5" } 19 | s.requires_arc = true 20 | s.source_files = "GXCardView/GXCardView*.{h,m}" 21 | s.frameworks = "Foundation","UIKit" 22 | 23 | end 24 | -------------------------------------------------------------------------------- /GXCardView/GXCardView.h: -------------------------------------------------------------------------------- 1 | // 2 | // GXCardView.h 3 | // GXCardViewDemo 4 | // 5 | // Created by Gin on 2018/7/31. 6 | // Copyright © 2018年 gin. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | typedef NS_ENUM(NSInteger,GXCardCellSwipeDirection) { 12 | GXCardCellSwipeDirectionNone = 0, 13 | GXCardCellSwipeDirectionLeft, 14 | GXCardCellSwipeDirectionRight, 15 | }; 16 | 17 | NS_ASSUME_NONNULL_BEGIN 18 | 19 | @interface GXCardViewCell : UIView 20 | /** 重用标识 */ 21 | @property (nonatomic, copy) NSString *reuseIdentifier; 22 | /** 指定初始化方法 */ 23 | - (instancetype)initWithReuseIdentifier:(NSString *)reuseIdentifier; 24 | /** 移除cell */ 25 | - (void)removeFromSuperviewSwipe:(GXCardCellSwipeDirection)direction; 26 | @end 27 | 28 | //////////////////////////////////////////////////////////////////////////////////////////////////////// 29 | 30 | @class GXCardView; 31 | @protocol GXCardViewDataSource 32 | @required 33 | - (NSInteger)numberOfCountInCardView:(GXCardView *)cardView; 34 | 35 | - (GXCardViewCell *)cardView:(GXCardView *)cardView cellForRowAtIndex:(NSInteger)index; 36 | 37 | @end 38 | 39 | @protocol GXCardViewDelegate 40 | @optional 41 | 42 | - (void)cardView:(GXCardView *)cardView didRemoveCell:(GXCardViewCell *)cell forRowAtIndex:(NSInteger)index direction:(GXCardCellSwipeDirection)direction; 43 | 44 | - (void)cardView:(GXCardView *)cardView didRemoveLastCell:(GXCardViewCell *)cell forRowAtIndex:(NSInteger)index; 45 | 46 | - (void)cardView:(GXCardView *)cardView didDisplayCell:(GXCardViewCell *)cell forRowAtIndex:(NSInteger)index; 47 | 48 | - (void)cardView:(GXCardView *)cardView didMoveCell:(GXCardViewCell *)cell forMovePoint:(CGPoint)point direction:(GXCardCellSwipeDirection)direction; 49 | 50 | @end 51 | 52 | @interface GXCardView : UIView 53 | 54 | /** 当前可视cells */ 55 | @property (nonatomic, readonly) NSArray<__kindof GXCardViewCell *> *visibleCells; 56 | /** 当前显示最上层索引 */ 57 | @property (nonatomic, readonly) NSInteger currentFirstIndex; 58 | /** 数据源 */ 59 | @property (nonatomic, weak) id dataSource; 60 | /** 代理 */ 61 | @property (nonatomic, weak) id delegate; 62 | /** 卡片可见数量(默认3) */ 63 | @property (nonatomic, assign) NSInteger visibleCount; 64 | /** 行间距(默认10.0,可自行计算scale比例来做间距) */ 65 | @property (nonatomic, assign) CGFloat lineSpacing; 66 | /** 列间距(默认10.0,可自行计算scale比例来做间距) */ 67 | @property (nonatomic, assign) CGFloat interitemSpacing; 68 | /** 侧滑最大角度(默认15°) */ 69 | @property (nonatomic, assign) CGFloat maxAngle; 70 | /** 最大移除距离(默认屏幕的1/4) */ 71 | @property (nonatomic, assign) CGFloat maxRemoveDistance; 72 | /** 是否重复(默认NO) */ 73 | @property (nonatomic, assign) BOOL isRepeat; 74 | 75 | /** 重载数据 */ 76 | - (void)reloadData; 77 | - (void)reloadDataAnimated:(BOOL)animated; 78 | /** 加载更多数据 */ 79 | - (void)reloadMoreData; 80 | - (void)reloadMoreDataAnimated:(BOOL)animated; 81 | /** 从index开始加载 */ 82 | - (void)reloadDataFormIndex:(NSInteger)index; 83 | - (void)reloadDataFormIndex:(NSInteger)index animated:(BOOL)animated; 84 | /** 注册cell */ 85 | - (void)registerNib:(nullable UINib *)nib forCellReuseIdentifier:(NSString *)identifier; 86 | - (void)registerClass:(nullable Class)cellClass forCellReuseIdentifier:(NSString *)identifier; 87 | /** 获取缓存cell */ 88 | - (__kindof GXCardViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier; 89 | /** 获取index对应的cell */ 90 | - (nullable __kindof GXCardViewCell *)cellForRowAtIndex:(NSInteger)index; 91 | /** 获取cell对应的index */ 92 | - (NSInteger)indexForCell:(GXCardViewCell *)cell; 93 | /** 移除最上层cell */ 94 | - (void)removeTopCardViewFromSwipe:(GXCardCellSwipeDirection)direction; 95 | 96 | @end 97 | 98 | NS_ASSUME_NONNULL_END 99 | -------------------------------------------------------------------------------- /GXCardView/GXCardView.m: -------------------------------------------------------------------------------- 1 | // 2 | // GXCardView.m 3 | // GXCardViewDemo 4 | // 5 | // Created by Gin on 2018/7/31. 6 | // Copyright © 2018年 gin. All rights reserved. 7 | // 8 | 9 | #import "GXCardView.h" 10 | 11 | #define SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width 12 | #define SCREEN_HEIGHT [UIScreen mainScreen].bounds.size.height 13 | #define GX_DEGREES_TO_RADIANS(angle) (angle / 180.0 * M_PI) 14 | 15 | static CGFloat const GX_DefaultDuration = 0.25f; 16 | static CGFloat const GX_SpringDuration = 0.5f; 17 | static CGFloat const GX_SpringWithDamping = 0.5f; 18 | static CGFloat const GX_SpringVelocity = 0.8f; 19 | 20 | @class GXCardViewCell; 21 | @protocol GXCardViewCellDelagate 22 | @optional 23 | - (void)cardViewCellDidRemoveFromSuperView:(GXCardViewCell *)cell withDirection:(GXCardCellSwipeDirection)direction; 24 | - (void)cardViewCellDidMoveFromSuperView:(GXCardViewCell*)cell forMovePoint:(CGPoint)point; 25 | @end 26 | 27 | @interface GXCardViewCell() 28 | @property (nonatomic, assign) CGFloat maxAngle; 29 | @property (nonatomic, assign) CGFloat maxRemoveDistance; 30 | @property (nonatomic, assign) CGPoint currentPoint; 31 | @property (nonatomic, assign) NSInteger index; 32 | @property (nonatomic, weak) id cell_delegate; 33 | 34 | @end 35 | 36 | @implementation GXCardViewCell 37 | 38 | - (void)awakeFromNib { 39 | [super awakeFromNib]; 40 | [self setupView]; 41 | } 42 | 43 | - (instancetype)initWithReuseIdentifier:(NSString *)reuseIdentifier { 44 | self = [super init]; 45 | if (self) { 46 | self.reuseIdentifier = reuseIdentifier; 47 | [self setupView]; 48 | } 49 | return self; 50 | } 51 | 52 | - (void)setupView { 53 | UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGestureRecognizer:)]; 54 | [self addGestureRecognizer:pan]; 55 | } 56 | 57 | - (void)panGestureRecognizer:(UIPanGestureRecognizer*)pan { 58 | switch (pan.state) { 59 | case UIGestureRecognizerStateBegan: 60 | self.currentPoint = CGPointZero; 61 | break; 62 | case UIGestureRecognizerStateChanged: { 63 | CGPoint movePoint = [pan translationInView:pan.view]; 64 | self.currentPoint = CGPointMake(self.currentPoint.x + movePoint.x , self.currentPoint.y + movePoint.y); 65 | 66 | CGFloat moveScale = self.currentPoint.x / self.maxRemoveDistance; 67 | if (ABS(moveScale) > 1.0) { 68 | moveScale = (moveScale > 0) ? 1.0 : -1.0; 69 | } 70 | CGFloat angle = GX_DEGREES_TO_RADIANS(self.maxAngle) * moveScale; 71 | CGAffineTransform transRotation = CGAffineTransformMakeRotation(angle); 72 | self.transform = CGAffineTransformTranslate(transRotation, self.currentPoint.x, self.currentPoint.y); 73 | 74 | if (self.cell_delegate && [self.cell_delegate respondsToSelector:@selector(cardViewCellDidMoveFromSuperView:forMovePoint:)]) { 75 | [self.cell_delegate cardViewCellDidMoveFromSuperView:self forMovePoint:self.currentPoint]; 76 | } 77 | [pan setTranslation:CGPointZero inView:pan.view]; 78 | } 79 | break; 80 | case UIGestureRecognizerStateEnded: 81 | [self didPanStateEnded]; 82 | break; 83 | case UIGestureRecognizerStateCancelled: 84 | case UIGestureRecognizerStateFailed: 85 | [self restoreCellLocation]; 86 | break; 87 | default: 88 | break; 89 | } 90 | } 91 | 92 | // 手势结束操作(不考虑上下位移) 93 | - (void)didPanStateEnded { 94 | // 右滑移除 95 | if (self.currentPoint.x > self.maxRemoveDistance) { 96 | __block UIView *snapshotView = [self snapshotViewAfterScreenUpdates:NO]; 97 | snapshotView.transform = self.transform; 98 | [self.superview.superview addSubview:snapshotView]; 99 | [self didCellRemoveFromSuperviewWithDirection:GXCardCellSwipeDirectionRight]; 100 | 101 | CGFloat endCenterX = SCREEN_WIDTH/2 + self.frame.size.width * 1.5; 102 | [UIView animateWithDuration:GX_DefaultDuration animations:^{ 103 | CGPoint center = self.center; 104 | center.x = endCenterX; 105 | snapshotView.center = center; 106 | } completion:^(BOOL finished) { 107 | [snapshotView removeFromSuperview]; 108 | }]; 109 | } 110 | // 左滑移除 111 | else if (self.currentPoint.x < -self.maxRemoveDistance) { 112 | __block UIView *snapshotView = [self snapshotViewAfterScreenUpdates:NO]; 113 | snapshotView.transform = self.transform; 114 | [self.superview.superview addSubview:snapshotView]; 115 | [self didCellRemoveFromSuperviewWithDirection:GXCardCellSwipeDirectionLeft]; 116 | 117 | CGFloat endCenterX = -(SCREEN_WIDTH/2 + self.frame.size.width); 118 | [UIView animateWithDuration:GX_DefaultDuration animations:^{ 119 | CGPoint center = self.center; 120 | center.x = endCenterX; 121 | snapshotView.center = center; 122 | } completion:^(BOOL finished) { 123 | [snapshotView removeFromSuperview]; 124 | }]; 125 | } 126 | // 滑动距离不够归位 127 | else { 128 | [self restoreCellLocation]; 129 | } 130 | } 131 | 132 | // 还原卡片位置 133 | - (void)restoreCellLocation { 134 | [UIView animateWithDuration:GX_SpringDuration delay:0 135 | usingSpringWithDamping:GX_SpringWithDamping 136 | initialSpringVelocity:GX_SpringVelocity 137 | options:UIViewAnimationOptionCurveEaseOut 138 | animations:^{ 139 | self.transform = CGAffineTransformIdentity; 140 | } completion:NULL]; 141 | } 142 | 143 | // 卡片移除处理 144 | - (void)didCellRemoveFromSuperviewWithDirection:(GXCardCellSwipeDirection)direction { 145 | self.transform = CGAffineTransformIdentity; 146 | [self removeFromSuperview]; 147 | if ([self.cell_delegate respondsToSelector:@selector(cardViewCellDidRemoveFromSuperView:withDirection:)]) { 148 | [self.cell_delegate cardViewCellDidRemoveFromSuperView:self withDirection:direction]; 149 | } 150 | } 151 | 152 | - (void)removeFromSuperviewSwipe:(GXCardCellSwipeDirection)direction { 153 | switch (direction) { 154 | case GXCardCellSwipeDirectionLeft: { 155 | [self removeFromSuperviewLeft]; 156 | } 157 | break; 158 | case GXCardCellSwipeDirectionRight: { 159 | [self removeFromSuperviewRight]; 160 | } 161 | break; 162 | default: 163 | break; 164 | } 165 | } 166 | 167 | // 向左边移除动画 168 | - (void)removeFromSuperviewLeft { 169 | __block UIView *snapshotView = [self snapshotViewAfterScreenUpdates:NO]; 170 | [self.superview.superview addSubview:snapshotView]; 171 | [self didCellRemoveFromSuperviewWithDirection:GXCardCellSwipeDirectionLeft]; 172 | 173 | CGAffineTransform transRotation = CGAffineTransformMakeRotation(-GX_DEGREES_TO_RADIANS(self.maxAngle)); 174 | CGAffineTransform transform = CGAffineTransformTranslate(transRotation, 0, self.frame.size.height/4.0); 175 | CGFloat endCenterX = -(SCREEN_WIDTH/2 + self.frame.size.width); 176 | [UIView animateWithDuration:GX_DefaultDuration animations:^{ 177 | CGPoint center = self.center; 178 | center.x = endCenterX; 179 | snapshotView.center = center; 180 | snapshotView.transform = transform; 181 | } completion:^(BOOL finished) { 182 | [snapshotView removeFromSuperview]; 183 | }]; 184 | } 185 | 186 | // 向右边移除动画 187 | - (void)removeFromSuperviewRight { 188 | __block UIView *snapshotView = [self snapshotViewAfterScreenUpdates:NO]; 189 | snapshotView.frame = self.frame; 190 | [self.superview.superview addSubview:snapshotView]; 191 | [self didCellRemoveFromSuperviewWithDirection:GXCardCellSwipeDirectionRight]; 192 | 193 | CGAffineTransform transRotation = CGAffineTransformMakeRotation(GX_DEGREES_TO_RADIANS(self.maxAngle)); 194 | CGAffineTransform transform = CGAffineTransformTranslate(transRotation, 0, self.frame.size.height/4.0); 195 | CGFloat endCenterX = SCREEN_WIDTH/2 + self.frame.size.width * 1.5; 196 | [UIView animateWithDuration:GX_DefaultDuration animations:^{ 197 | CGPoint center = self.center; 198 | center.x = endCenterX; 199 | snapshotView.center = center; 200 | snapshotView.transform = transform; 201 | } completion:^(BOOL finished) { 202 | [snapshotView removeFromSuperview]; 203 | }]; 204 | } 205 | 206 | @end 207 | 208 | //////////////////////////////////////////////////////////////////////////////////////////////////////// 209 | 210 | @interface GXCardView() 211 | /** cell容器 */ 212 | @property (nonatomic, strong) UIView *containerView; 213 | /** 注册cell相关 */ 214 | @property (nonatomic, strong) UINib *nib; 215 | @property (nonatomic, copy) Class cellClass; 216 | @property (nonatomic, copy) NSString *identifier; 217 | /** 当前索引(已显示的最大索引) */ 218 | @property (nonatomic, assign) NSInteger currentIndex; 219 | /** 当前可视cells */ 220 | @property (nonatomic, strong) NSArray<__kindof GXCardViewCell *> *visibleCells; 221 | /** 重用卡片数组 */ 222 | @property (nonatomic, strong) NSMutableArray<__kindof GXCardViewCell *> *reusableCells; 223 | 224 | @end 225 | 226 | @implementation GXCardView 227 | 228 | - (void)awakeFromNib { 229 | [super awakeFromNib]; 230 | [self configCardView]; 231 | } 232 | 233 | - (instancetype)initWithFrame:(CGRect)frame { 234 | self = [super initWithFrame:frame]; 235 | if (self) { 236 | [self configCardView]; 237 | } 238 | return self; 239 | } 240 | 241 | - (void)configCardView { 242 | _visibleCount = 3; 243 | _lineSpacing = 10.0; 244 | _interitemSpacing = 10.0; 245 | _maxAngle = 15; 246 | _maxRemoveDistance = SCREEN_WIDTH / 4.0; 247 | _reusableCells = [NSMutableArray array]; 248 | _isRepeat = NO; 249 | } 250 | 251 | - (UIView *)containerView { 252 | if (!_containerView) { 253 | _containerView = [[UIView alloc] initWithFrame:self.bounds]; 254 | _containerView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight; 255 | [self addSubview:_containerView]; 256 | } 257 | return _containerView; 258 | } 259 | 260 | - (void)reloadData { 261 | [self reloadDataAnimated:NO]; 262 | } 263 | 264 | - (void)reloadDataAnimated:(BOOL)animated { 265 | self.currentIndex = 0; 266 | [self.reusableCells removeAllObjects]; 267 | [self.containerView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)]; 268 | 269 | NSInteger maxCount = [self.dataSource numberOfCountInCardView:self]; 270 | maxCount = self.isRepeat ? (maxCount + self.visibleCount - 1) : maxCount; 271 | NSInteger showNumber = MIN(maxCount, self.visibleCount); 272 | for (int i = 0; i < showNumber; i++) { 273 | [self createCardViewCellWithIndex:i]; 274 | } 275 | [self updateLayoutVisibleCellsWithAnimated:animated]; 276 | } 277 | 278 | - (void)reloadDataRepeatAnimated:(BOOL)animated { 279 | self.currentIndex = 0; 280 | [self.reusableCells removeAllObjects]; 281 | [self.containerView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)]; 282 | 283 | NSInteger maxCount = [self.dataSource numberOfCountInCardView:self]; 284 | maxCount = self.isRepeat ? (maxCount + self.visibleCount - 1) : maxCount; 285 | NSInteger showNumber = MIN(maxCount, self.visibleCount); 286 | for (int i = 0; i < showNumber; i++) { 287 | [self createRepeatCardViewCellWithIndex:i]; 288 | } 289 | [self updateLayoutVisibleCellsWithAnimated:animated]; 290 | } 291 | 292 | - (void)reloadMoreData { 293 | [self reloadMoreDataAnimated:NO]; 294 | } 295 | 296 | - (void)reloadMoreDataAnimated:(BOOL)animated { 297 | NSAssert(!self.isRepeat, @"isRepeat为YES不允许加载更多数据!"); 298 | [self.reusableCells removeAllObjects]; 299 | NSInteger loadMoreCount = self.visibleCount - self.visibleCells.count; 300 | NSInteger loadMaxLength = self.currentIndex + loadMoreCount; 301 | for (NSInteger i = self.currentIndex + 1; i < loadMaxLength; i++) { 302 | [self createCardViewCellWithIndex:i]; 303 | } 304 | [self updateLayoutVisibleCellsWithAnimated:animated]; 305 | } 306 | 307 | - (void)reloadDataFormIndex:(NSInteger)index { 308 | [self reloadDataFormIndex:index animated:NO]; 309 | } 310 | 311 | - (void)reloadDataFormIndex:(NSInteger)index animated:(BOOL)animated { 312 | NSAssert(!self.isRepeat, @"isRepeat为YES不允许从索引处加载!"); 313 | NSInteger maxCount = [self.dataSource numberOfCountInCardView:self]; 314 | NSAssert(index < maxCount, @"index不能大于等于cell的数量!"); 315 | 316 | [self.reusableCells removeAllObjects]; 317 | [self.containerView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)]; 318 | NSInteger loadMaxLength = index + self.visibleCount; 319 | loadMaxLength = MIN(loadMaxLength, maxCount); 320 | for (NSInteger i = index; i < loadMaxLength; i++) { 321 | [self createCardViewCellWithIndex:i]; 322 | } 323 | [self updateLayoutVisibleCellsWithAnimated:animated]; 324 | } 325 | 326 | /** 创建新的cell */ 327 | - (void)createCardViewCellWithIndex:(NSInteger)index { 328 | GXCardViewCell *cell = [self.dataSource cardView:self cellForRowAtIndex:index]; 329 | cell.index = index; 330 | cell.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight; 331 | cell.maxRemoveDistance = self.maxRemoveDistance; 332 | cell.maxAngle = self.maxAngle; 333 | cell.cell_delegate = self; 334 | cell.userInteractionEnabled = NO; 335 | NSInteger showCount = self.visibleCount - 1; 336 | CGFloat width = self.frame.size.width; 337 | CGFloat height = self.frame.size.height - (showCount * self.interitemSpacing); 338 | cell.frame = CGRectMake(0, 0, width, height); 339 | [self.containerView insertSubview:cell atIndex:0]; 340 | [self.containerView layoutIfNeeded]; 341 | self.currentIndex = index; 342 | 343 | CGFloat minWidth = self.frame.size.width - 2 * self.lineSpacing * showCount; 344 | CGFloat minHeight = self.frame.size.height - 2 * self.interitemSpacing * showCount; 345 | CGFloat minWScale = minWidth / self.frame.size.width; 346 | CGFloat minHScale = minHeight / self.frame.size.height; 347 | CGFloat yOffset = (self.interitemSpacing / minHScale) * 2 *showCount; 348 | CGAffineTransform scaleTransform = CGAffineTransformMakeScale(minWScale, minHScale); 349 | CGAffineTransform transform = CGAffineTransformTranslate(scaleTransform, 0, yOffset); 350 | cell.transform = transform; 351 | } 352 | 353 | /** repeat为YES创建新的cell */ 354 | - (void)createRepeatCardViewCellWithIndex:(NSInteger)index { 355 | GXCardViewCell *cell = [self.dataSource cardView:self cellForRowAtIndex:index]; 356 | cell.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight; 357 | cell.maxRemoveDistance = self.maxRemoveDistance; 358 | cell.maxAngle = self.maxAngle; 359 | cell.cell_delegate = self; 360 | cell.userInteractionEnabled = NO; 361 | NSInteger showCount = self.visibleCount; 362 | CGFloat width = self.frame.size.width; 363 | CGFloat height = self.frame.size.height - (showCount * self.interitemSpacing); 364 | cell.frame = CGRectMake(0, 0, width, height); 365 | [self.containerView insertSubview:cell atIndex:0]; 366 | [self.containerView layoutIfNeeded]; 367 | self.currentIndex = index; 368 | 369 | CGFloat minWidth = self.frame.size.width - 2 * self.lineSpacing * showCount; 370 | CGFloat minHeight = self.frame.size.height - 2 * self.interitemSpacing * showCount; 371 | CGFloat minWScale = minWidth / self.frame.size.width; 372 | CGFloat minHScale = minHeight / self.frame.size.height; 373 | CGFloat yOffset = (self.interitemSpacing / minHScale) * 2 *showCount; 374 | CGAffineTransform scaleTransform = CGAffineTransformMakeScale(minWScale, minHScale); 375 | CGAffineTransform transform = CGAffineTransformTranslate(scaleTransform, 0, yOffset); 376 | cell.transform = transform; 377 | } 378 | 379 | /** 更新布局(动画) */ 380 | - (void)updateLayoutVisibleCellsWithAnimated:(BOOL)animated { 381 | NSInteger showCount = self.visibleCount - 1; 382 | CGFloat minWidth = self.frame.size.width - 2 * self.lineSpacing * showCount; 383 | CGFloat minHeight = self.frame.size.height - 2 * self.interitemSpacing * showCount; 384 | CGFloat minWScale = minWidth / self.frame.size.width; 385 | CGFloat minHScale = minHeight / self.frame.size.height; 386 | CGFloat itemWScale = (1.0 - minWScale) / showCount; 387 | CGFloat itemHScale = (1.0 - minHScale) / showCount; 388 | NSInteger count = self.visibleCells.count; 389 | for (NSInteger i = 0; i < count; i ++) { 390 | // 计算出最终效果的transform 391 | NSInteger showIndex = count - i - 1; 392 | CGFloat wScale = 1.0 - showIndex * itemWScale; 393 | CGFloat hScale = 1.0 - showIndex * itemHScale; 394 | CGFloat y = (self.interitemSpacing / hScale) * 2 * showIndex; 395 | CGAffineTransform scaleTransform = CGAffineTransformMakeScale(wScale, hScale); 396 | CGAffineTransform transform = CGAffineTransformTranslate(scaleTransform, 0, y); 397 | // 获取当前要显示的的cells 398 | GXCardViewCell *cell = self.visibleCells[i]; 399 | // 判断是不是当前显示的最后一个(最上层显示) 400 | BOOL isLast = (i == (count - 1)); 401 | if (isLast) { 402 | cell.userInteractionEnabled = YES; 403 | if ([self.delegate respondsToSelector:@selector(cardView:didDisplayCell:forRowAtIndex:)]) { 404 | [self.delegate cardView:self didDisplayCell:cell forRowAtIndex:cell.index]; 405 | } 406 | } 407 | if (animated) { 408 | [self updateConstraintsCell:cell transform:transform]; 409 | } else { 410 | cell.transform = transform; 411 | } 412 | } 413 | } 414 | 415 | - (void)updateConstraintsCell:(GXCardViewCell*)cell transform:(CGAffineTransform)transform { 416 | [UIView animateWithDuration:GX_DefaultDuration animations:^{ 417 | cell.transform = transform; 418 | } completion:NULL]; 419 | } 420 | 421 | /** 当前最上层索引 */ 422 | - (NSInteger)currentFirstIndex { 423 | NSInteger index = self.currentIndex - self.visibleCells.count + 1; 424 | if (self.isRepeat) { 425 | if (index < 0) { 426 | index = index + [self.dataSource numberOfCountInCardView:self]; 427 | } 428 | } 429 | return index; 430 | } 431 | 432 | /** 数据源索引转换为对应的显示索引 */ 433 | - (NSInteger)visibleIndexAtIndex:(NSInteger)index { 434 | if (self.isRepeat) { 435 | if (index < self.currentFirstIndex) { 436 | return index + [self.dataSource numberOfCountInCardView:self] - self.currentFirstIndex; 437 | } 438 | } 439 | NSInteger visibleIndex = index - self.currentFirstIndex; 440 | return visibleIndex; 441 | } 442 | 443 | /** 可视cells */ 444 | - (NSArray *)visibleCells { 445 | return self.containerView.subviews; 446 | } 447 | 448 | /** 注册cell */ 449 | - (void)registerNib:(nullable UINib *)nib forCellReuseIdentifier:(NSString *)identifier { 450 | self.nib = nib; 451 | self.identifier = identifier; 452 | } 453 | 454 | - (void)registerClass:(nullable Class)cellClass forCellReuseIdentifier:(NSString *)identifier { 455 | self.cellClass = cellClass; 456 | self.identifier = identifier; 457 | } 458 | 459 | /** 获取缓存cell */ 460 | - (__kindof GXCardViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier { 461 | for (GXCardViewCell *cell in self.reusableCells) { 462 | if ([cell.reuseIdentifier isEqualToString:identifier]) { 463 | [self.reusableCells removeObject:cell]; 464 | 465 | return cell; 466 | } 467 | } 468 | if (self.nib) { 469 | GXCardViewCell *cell = [[self.nib instantiateWithOwner:nil options:nil] lastObject]; 470 | cell.reuseIdentifier = identifier; 471 | 472 | return cell; 473 | } else if (self.cellClass) { // 注册class 474 | GXCardViewCell *cell = [[self.cellClass alloc] initWithReuseIdentifier:identifier]; 475 | cell.reuseIdentifier = identifier; 476 | 477 | return cell; 478 | } 479 | NSLog(@"请先注册cardCell!"); 480 | return nil; 481 | } 482 | 483 | /** 获取index对应的cell */ 484 | - (nullable __kindof GXCardViewCell *)cellForRowAtIndex:(NSInteger)index { 485 | NSInteger visibleIndex = [self visibleIndexAtIndex:index]; 486 | if (visibleIndex >= 0 && visibleIndex < self.visibleCells.count) { 487 | GXCardViewCell *cell = [self.visibleCells objectAtIndex:visibleIndex]; 488 | return cell; 489 | } 490 | return nil; 491 | } 492 | 493 | /** 获取cell对应的index */ 494 | - (NSInteger)indexForCell:(GXCardViewCell *)cell { 495 | return cell.index; 496 | } 497 | 498 | /** 移除最上层cell */ 499 | - (void)removeTopCardViewFromSwipe:(GXCardCellSwipeDirection)direction { 500 | if(self.visibleCells.count == 0) return; 501 | GXCardViewCell *topcell = [self.visibleCells lastObject]; 502 | [topcell removeFromSuperviewSwipe:direction]; 503 | } 504 | 505 | #pragma mark - GXCardViewCellDelagate 506 | 507 | - (void)cardViewCellDidRemoveFromSuperView:(GXCardViewCell *)cell withDirection:(GXCardCellSwipeDirection)direction { 508 | // 当cell被移除时重新刷新视图 509 | [self.reusableCells addObject:cell]; 510 | 511 | // 通知代理 移除了当前cell 512 | if ([self.delegate respondsToSelector:@selector(cardView:didRemoveCell:forRowAtIndex:direction:)]) { 513 | [self.delegate cardView:self didRemoveCell:cell forRowAtIndex:cell.index direction:direction]; 514 | } 515 | 516 | NSInteger count = [self.dataSource numberOfCountInCardView:self]; 517 | // 移除后的卡片是最后一张(没有更多) 518 | if(self.visibleCells.count == 0) { // 只有最后一张卡片的时候 519 | if ([self.delegate respondsToSelector:@selector(cardView:didRemoveLastCell:forRowAtIndex:)]) { 520 | [self.delegate cardView:self didRemoveLastCell:cell forRowAtIndex:cell.index]; 521 | } 522 | return; 523 | } 524 | if (self.isRepeat) { 525 | NSInteger reCount = self.isRepeat ? (count + self.visibleCount - 1) : count; 526 | if (self.currentIndex < reCount - 1) { 527 | // 当前数据源还有数据 继续创建cell 528 | [self createCardViewCellWithIndex:(self.currentIndex + 1) % count]; 529 | } else { 530 | // 如果是重复的情况下需要加载到最后一张就重载 531 | [self reloadDataRepeatAnimated:YES]; 532 | } 533 | } 534 | else { 535 | // 当前数据源还有数据 继续创建cell 536 | if (self.currentIndex < count - 1) { 537 | [self createCardViewCellWithIndex:(self.currentIndex + 1)]; 538 | } 539 | } 540 | // 更新布局 541 | [self updateLayoutVisibleCellsWithAnimated:YES]; 542 | } 543 | 544 | - (void)cardViewCellDidMoveFromSuperView:(GXCardViewCell *)cell forMovePoint:(CGPoint)point { 545 | if ([self.delegate respondsToSelector:@selector(cardView:didMoveCell:forMovePoint:direction:)]) { 546 | // 右滑中 547 | if (cell.currentPoint.x > cell.maxRemoveDistance) { 548 | [self.delegate cardView:self didMoveCell:cell forMovePoint:point direction:GXCardCellSwipeDirectionRight]; 549 | } 550 | // 左滑中 551 | else if (cell.currentPoint.x < -cell.maxRemoveDistance) { 552 | [self.delegate cardView:self didMoveCell:cell forMovePoint:point direction:GXCardCellSwipeDirectionLeft]; 553 | } 554 | // 滑动距离不够 555 | else { 556 | [self.delegate cardView:self didMoveCell:cell forMovePoint:point direction:GXCardCellSwipeDirectionNone]; 557 | } 558 | } 559 | } 560 | 561 | @end 562 | 563 | 564 | -------------------------------------------------------------------------------- /GXCardViewSample/GXCardViewDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 33CCF00321172A0D00F57890 /* GXCardView.m in Sources */ = {isa = PBXBuildFile; fileRef = 33CCF00121172A0D00F57890 /* GXCardView.m */; }; 11 | 33E5C8B6210F7998000BDF6A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 33E5C8B5210F7998000BDF6A /* AppDelegate.m */; }; 12 | 33E5C8B9210F7998000BDF6A /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 33E5C8B8210F7998000BDF6A /* ViewController.m */; }; 13 | 33E5C8BC210F7998000BDF6A /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 33E5C8BA210F7998000BDF6A /* Main.storyboard */; }; 14 | 33E5C8BE210F799A000BDF6A /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33E5C8BD210F799A000BDF6A /* Assets.xcassets */; }; 15 | 33E5C8C1210F799A000BDF6A /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 33E5C8BF210F799A000BDF6A /* LaunchScreen.storyboard */; }; 16 | 33E5C8C4210F799A000BDF6A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 33E5C8C3210F799A000BDF6A /* main.m */; }; 17 | 33E5C8CE210F799A000BDF6A /* GXCardViewDemoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 33E5C8CD210F799A000BDF6A /* GXCardViewDemoTests.m */; }; 18 | 33E5C8D9210F799A000BDF6A /* GXCardViewDemoUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = 33E5C8D8210F799A000BDF6A /* GXCardViewDemoUITests.m */; }; 19 | 33F40956211490160011A844 /* GXCardItemDemoCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 33F40954211490160011A844 /* GXCardItemDemoCell.m */; }; 20 | 33F40957211490160011A844 /* GXCardItemDemoCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33F40955211490160011A844 /* GXCardItemDemoCell.xib */; }; 21 | /* End PBXBuildFile section */ 22 | 23 | /* Begin PBXContainerItemProxy section */ 24 | 33E5C8CA210F799A000BDF6A /* PBXContainerItemProxy */ = { 25 | isa = PBXContainerItemProxy; 26 | containerPortal = 33E5C8A9210F7998000BDF6A /* Project object */; 27 | proxyType = 1; 28 | remoteGlobalIDString = 33E5C8B0210F7998000BDF6A; 29 | remoteInfo = GXCardViewDemo; 30 | }; 31 | 33E5C8D5210F799A000BDF6A /* PBXContainerItemProxy */ = { 32 | isa = PBXContainerItemProxy; 33 | containerPortal = 33E5C8A9210F7998000BDF6A /* Project object */; 34 | proxyType = 1; 35 | remoteGlobalIDString = 33E5C8B0210F7998000BDF6A; 36 | remoteInfo = GXCardViewDemo; 37 | }; 38 | /* End PBXContainerItemProxy section */ 39 | 40 | /* Begin PBXFileReference section */ 41 | 33CCEFFF21172A0D00F57890 /* GXCardView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GXCardView.h; sourceTree = ""; }; 42 | 33CCF00121172A0D00F57890 /* GXCardView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GXCardView.m; sourceTree = ""; }; 43 | 33E5C8B1210F7998000BDF6A /* GXCardViewDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = GXCardViewDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 44 | 33E5C8B4210F7998000BDF6A /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 45 | 33E5C8B5210F7998000BDF6A /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 46 | 33E5C8B7210F7998000BDF6A /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 47 | 33E5C8B8210F7998000BDF6A /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 48 | 33E5C8BB210F7998000BDF6A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 49 | 33E5C8BD210F799A000BDF6A /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 50 | 33E5C8C0210F799A000BDF6A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 51 | 33E5C8C2210F799A000BDF6A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 52 | 33E5C8C3210F799A000BDF6A /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 53 | 33E5C8C9210F799A000BDF6A /* GXCardViewDemoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = GXCardViewDemoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 54 | 33E5C8CD210F799A000BDF6A /* GXCardViewDemoTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GXCardViewDemoTests.m; sourceTree = ""; }; 55 | 33E5C8CF210F799A000BDF6A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 56 | 33E5C8D4210F799A000BDF6A /* GXCardViewDemoUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = GXCardViewDemoUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 57 | 33E5C8D8210F799A000BDF6A /* GXCardViewDemoUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GXCardViewDemoUITests.m; sourceTree = ""; }; 58 | 33E5C8DA210F799A000BDF6A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 59 | 33F40953211490160011A844 /* GXCardItemDemoCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GXCardItemDemoCell.h; sourceTree = ""; }; 60 | 33F40954211490160011A844 /* GXCardItemDemoCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GXCardItemDemoCell.m; sourceTree = ""; }; 61 | 33F40955211490160011A844 /* GXCardItemDemoCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = GXCardItemDemoCell.xib; sourceTree = ""; }; 62 | /* End PBXFileReference section */ 63 | 64 | /* Begin PBXFrameworksBuildPhase section */ 65 | 33E5C8AE210F7998000BDF6A /* Frameworks */ = { 66 | isa = PBXFrameworksBuildPhase; 67 | buildActionMask = 2147483647; 68 | files = ( 69 | ); 70 | runOnlyForDeploymentPostprocessing = 0; 71 | }; 72 | 33E5C8C6210F799A000BDF6A /* Frameworks */ = { 73 | isa = PBXFrameworksBuildPhase; 74 | buildActionMask = 2147483647; 75 | files = ( 76 | ); 77 | runOnlyForDeploymentPostprocessing = 0; 78 | }; 79 | 33E5C8D1210F799A000BDF6A /* Frameworks */ = { 80 | isa = PBXFrameworksBuildPhase; 81 | buildActionMask = 2147483647; 82 | files = ( 83 | ); 84 | runOnlyForDeploymentPostprocessing = 0; 85 | }; 86 | /* End PBXFrameworksBuildPhase section */ 87 | 88 | /* Begin PBXGroup section */ 89 | 33CCEFFD21172A0D00F57890 /* GXCardView */ = { 90 | isa = PBXGroup; 91 | children = ( 92 | 33CCEFFF21172A0D00F57890 /* GXCardView.h */, 93 | 33CCF00121172A0D00F57890 /* GXCardView.m */, 94 | ); 95 | name = GXCardView; 96 | path = ../../GXCardView; 97 | sourceTree = ""; 98 | }; 99 | 33E5C8A8210F7998000BDF6A = { 100 | isa = PBXGroup; 101 | children = ( 102 | 33E5C8B3210F7998000BDF6A /* GXCardViewDemo */, 103 | 33E5C8CC210F799A000BDF6A /* GXCardViewDemoTests */, 104 | 33E5C8D7210F799A000BDF6A /* GXCardViewDemoUITests */, 105 | 33E5C8B2210F7998000BDF6A /* Products */, 106 | ); 107 | sourceTree = ""; 108 | }; 109 | 33E5C8B2210F7998000BDF6A /* Products */ = { 110 | isa = PBXGroup; 111 | children = ( 112 | 33E5C8B1210F7998000BDF6A /* GXCardViewDemo.app */, 113 | 33E5C8C9210F799A000BDF6A /* GXCardViewDemoTests.xctest */, 114 | 33E5C8D4210F799A000BDF6A /* GXCardViewDemoUITests.xctest */, 115 | ); 116 | name = Products; 117 | sourceTree = ""; 118 | }; 119 | 33E5C8B3210F7998000BDF6A /* GXCardViewDemo */ = { 120 | isa = PBXGroup; 121 | children = ( 122 | 33CCEFFD21172A0D00F57890 /* GXCardView */, 123 | 33F40953211490160011A844 /* GXCardItemDemoCell.h */, 124 | 33F40954211490160011A844 /* GXCardItemDemoCell.m */, 125 | 33F40955211490160011A844 /* GXCardItemDemoCell.xib */, 126 | 33E5C8B7210F7998000BDF6A /* ViewController.h */, 127 | 33E5C8B8210F7998000BDF6A /* ViewController.m */, 128 | 33E5C8B4210F7998000BDF6A /* AppDelegate.h */, 129 | 33E5C8B5210F7998000BDF6A /* AppDelegate.m */, 130 | 33E5C8BA210F7998000BDF6A /* Main.storyboard */, 131 | 33E5C8BF210F799A000BDF6A /* LaunchScreen.storyboard */, 132 | 33E5C8BD210F799A000BDF6A /* Assets.xcassets */, 133 | 33E5C8C2210F799A000BDF6A /* Info.plist */, 134 | 33E5C8C3210F799A000BDF6A /* main.m */, 135 | ); 136 | path = GXCardViewDemo; 137 | sourceTree = ""; 138 | }; 139 | 33E5C8CC210F799A000BDF6A /* GXCardViewDemoTests */ = { 140 | isa = PBXGroup; 141 | children = ( 142 | 33E5C8CD210F799A000BDF6A /* GXCardViewDemoTests.m */, 143 | 33E5C8CF210F799A000BDF6A /* Info.plist */, 144 | ); 145 | path = GXCardViewDemoTests; 146 | sourceTree = ""; 147 | }; 148 | 33E5C8D7210F799A000BDF6A /* GXCardViewDemoUITests */ = { 149 | isa = PBXGroup; 150 | children = ( 151 | 33E5C8D8210F799A000BDF6A /* GXCardViewDemoUITests.m */, 152 | 33E5C8DA210F799A000BDF6A /* Info.plist */, 153 | ); 154 | path = GXCardViewDemoUITests; 155 | sourceTree = ""; 156 | }; 157 | /* End PBXGroup section */ 158 | 159 | /* Begin PBXNativeTarget section */ 160 | 33E5C8B0210F7998000BDF6A /* GXCardViewDemo */ = { 161 | isa = PBXNativeTarget; 162 | buildConfigurationList = 33E5C8DD210F799A000BDF6A /* Build configuration list for PBXNativeTarget "GXCardViewDemo" */; 163 | buildPhases = ( 164 | 33E5C8AD210F7998000BDF6A /* Sources */, 165 | 33E5C8AE210F7998000BDF6A /* Frameworks */, 166 | 33E5C8AF210F7998000BDF6A /* Resources */, 167 | ); 168 | buildRules = ( 169 | ); 170 | dependencies = ( 171 | ); 172 | name = GXCardViewDemo; 173 | productName = GXCardViewDemo; 174 | productReference = 33E5C8B1210F7998000BDF6A /* GXCardViewDemo.app */; 175 | productType = "com.apple.product-type.application"; 176 | }; 177 | 33E5C8C8210F799A000BDF6A /* GXCardViewDemoTests */ = { 178 | isa = PBXNativeTarget; 179 | buildConfigurationList = 33E5C8E0210F799A000BDF6A /* Build configuration list for PBXNativeTarget "GXCardViewDemoTests" */; 180 | buildPhases = ( 181 | 33E5C8C5210F799A000BDF6A /* Sources */, 182 | 33E5C8C6210F799A000BDF6A /* Frameworks */, 183 | 33E5C8C7210F799A000BDF6A /* Resources */, 184 | ); 185 | buildRules = ( 186 | ); 187 | dependencies = ( 188 | 33E5C8CB210F799A000BDF6A /* PBXTargetDependency */, 189 | ); 190 | name = GXCardViewDemoTests; 191 | productName = GXCardViewDemoTests; 192 | productReference = 33E5C8C9210F799A000BDF6A /* GXCardViewDemoTests.xctest */; 193 | productType = "com.apple.product-type.bundle.unit-test"; 194 | }; 195 | 33E5C8D3210F799A000BDF6A /* GXCardViewDemoUITests */ = { 196 | isa = PBXNativeTarget; 197 | buildConfigurationList = 33E5C8E3210F799A000BDF6A /* Build configuration list for PBXNativeTarget "GXCardViewDemoUITests" */; 198 | buildPhases = ( 199 | 33E5C8D0210F799A000BDF6A /* Sources */, 200 | 33E5C8D1210F799A000BDF6A /* Frameworks */, 201 | 33E5C8D2210F799A000BDF6A /* Resources */, 202 | ); 203 | buildRules = ( 204 | ); 205 | dependencies = ( 206 | 33E5C8D6210F799A000BDF6A /* PBXTargetDependency */, 207 | ); 208 | name = GXCardViewDemoUITests; 209 | productName = GXCardViewDemoUITests; 210 | productReference = 33E5C8D4210F799A000BDF6A /* GXCardViewDemoUITests.xctest */; 211 | productType = "com.apple.product-type.bundle.ui-testing"; 212 | }; 213 | /* End PBXNativeTarget section */ 214 | 215 | /* Begin PBXProject section */ 216 | 33E5C8A9210F7998000BDF6A /* Project object */ = { 217 | isa = PBXProject; 218 | attributes = { 219 | LastUpgradeCheck = 0940; 220 | ORGANIZATIONNAME = gin; 221 | TargetAttributes = { 222 | 33E5C8B0210F7998000BDF6A = { 223 | CreatedOnToolsVersion = 9.4; 224 | }; 225 | 33E5C8C8210F799A000BDF6A = { 226 | CreatedOnToolsVersion = 9.4; 227 | TestTargetID = 33E5C8B0210F7998000BDF6A; 228 | }; 229 | 33E5C8D3210F799A000BDF6A = { 230 | CreatedOnToolsVersion = 9.4; 231 | TestTargetID = 33E5C8B0210F7998000BDF6A; 232 | }; 233 | }; 234 | }; 235 | buildConfigurationList = 33E5C8AC210F7998000BDF6A /* Build configuration list for PBXProject "GXCardViewDemo" */; 236 | compatibilityVersion = "Xcode 9.3"; 237 | developmentRegion = en; 238 | hasScannedForEncodings = 0; 239 | knownRegions = ( 240 | en, 241 | Base, 242 | ); 243 | mainGroup = 33E5C8A8210F7998000BDF6A; 244 | productRefGroup = 33E5C8B2210F7998000BDF6A /* Products */; 245 | projectDirPath = ""; 246 | projectRoot = ""; 247 | targets = ( 248 | 33E5C8B0210F7998000BDF6A /* GXCardViewDemo */, 249 | 33E5C8C8210F799A000BDF6A /* GXCardViewDemoTests */, 250 | 33E5C8D3210F799A000BDF6A /* GXCardViewDemoUITests */, 251 | ); 252 | }; 253 | /* End PBXProject section */ 254 | 255 | /* Begin PBXResourcesBuildPhase section */ 256 | 33E5C8AF210F7998000BDF6A /* Resources */ = { 257 | isa = PBXResourcesBuildPhase; 258 | buildActionMask = 2147483647; 259 | files = ( 260 | 33F40957211490160011A844 /* GXCardItemDemoCell.xib in Resources */, 261 | 33E5C8C1210F799A000BDF6A /* LaunchScreen.storyboard in Resources */, 262 | 33E5C8BE210F799A000BDF6A /* Assets.xcassets in Resources */, 263 | 33E5C8BC210F7998000BDF6A /* Main.storyboard in Resources */, 264 | ); 265 | runOnlyForDeploymentPostprocessing = 0; 266 | }; 267 | 33E5C8C7210F799A000BDF6A /* Resources */ = { 268 | isa = PBXResourcesBuildPhase; 269 | buildActionMask = 2147483647; 270 | files = ( 271 | ); 272 | runOnlyForDeploymentPostprocessing = 0; 273 | }; 274 | 33E5C8D2210F799A000BDF6A /* Resources */ = { 275 | isa = PBXResourcesBuildPhase; 276 | buildActionMask = 2147483647; 277 | files = ( 278 | ); 279 | runOnlyForDeploymentPostprocessing = 0; 280 | }; 281 | /* End PBXResourcesBuildPhase section */ 282 | 283 | /* Begin PBXSourcesBuildPhase section */ 284 | 33E5C8AD210F7998000BDF6A /* Sources */ = { 285 | isa = PBXSourcesBuildPhase; 286 | buildActionMask = 2147483647; 287 | files = ( 288 | 33E5C8B9210F7998000BDF6A /* ViewController.m in Sources */, 289 | 33CCF00321172A0D00F57890 /* GXCardView.m in Sources */, 290 | 33F40956211490160011A844 /* GXCardItemDemoCell.m in Sources */, 291 | 33E5C8C4210F799A000BDF6A /* main.m in Sources */, 292 | 33E5C8B6210F7998000BDF6A /* AppDelegate.m in Sources */, 293 | ); 294 | runOnlyForDeploymentPostprocessing = 0; 295 | }; 296 | 33E5C8C5210F799A000BDF6A /* Sources */ = { 297 | isa = PBXSourcesBuildPhase; 298 | buildActionMask = 2147483647; 299 | files = ( 300 | 33E5C8CE210F799A000BDF6A /* GXCardViewDemoTests.m in Sources */, 301 | ); 302 | runOnlyForDeploymentPostprocessing = 0; 303 | }; 304 | 33E5C8D0210F799A000BDF6A /* Sources */ = { 305 | isa = PBXSourcesBuildPhase; 306 | buildActionMask = 2147483647; 307 | files = ( 308 | 33E5C8D9210F799A000BDF6A /* GXCardViewDemoUITests.m in Sources */, 309 | ); 310 | runOnlyForDeploymentPostprocessing = 0; 311 | }; 312 | /* End PBXSourcesBuildPhase section */ 313 | 314 | /* Begin PBXTargetDependency section */ 315 | 33E5C8CB210F799A000BDF6A /* PBXTargetDependency */ = { 316 | isa = PBXTargetDependency; 317 | target = 33E5C8B0210F7998000BDF6A /* GXCardViewDemo */; 318 | targetProxy = 33E5C8CA210F799A000BDF6A /* PBXContainerItemProxy */; 319 | }; 320 | 33E5C8D6210F799A000BDF6A /* PBXTargetDependency */ = { 321 | isa = PBXTargetDependency; 322 | target = 33E5C8B0210F7998000BDF6A /* GXCardViewDemo */; 323 | targetProxy = 33E5C8D5210F799A000BDF6A /* PBXContainerItemProxy */; 324 | }; 325 | /* End PBXTargetDependency section */ 326 | 327 | /* Begin PBXVariantGroup section */ 328 | 33E5C8BA210F7998000BDF6A /* Main.storyboard */ = { 329 | isa = PBXVariantGroup; 330 | children = ( 331 | 33E5C8BB210F7998000BDF6A /* Base */, 332 | ); 333 | name = Main.storyboard; 334 | sourceTree = ""; 335 | }; 336 | 33E5C8BF210F799A000BDF6A /* LaunchScreen.storyboard */ = { 337 | isa = PBXVariantGroup; 338 | children = ( 339 | 33E5C8C0210F799A000BDF6A /* Base */, 340 | ); 341 | name = LaunchScreen.storyboard; 342 | sourceTree = ""; 343 | }; 344 | /* End PBXVariantGroup section */ 345 | 346 | /* Begin XCBuildConfiguration section */ 347 | 33E5C8DB210F799A000BDF6A /* Debug */ = { 348 | isa = XCBuildConfiguration; 349 | buildSettings = { 350 | ALWAYS_SEARCH_USER_PATHS = NO; 351 | CLANG_ANALYZER_NONNULL = YES; 352 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 353 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 354 | CLANG_CXX_LIBRARY = "libc++"; 355 | CLANG_ENABLE_MODULES = YES; 356 | CLANG_ENABLE_OBJC_ARC = YES; 357 | CLANG_ENABLE_OBJC_WEAK = YES; 358 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 359 | CLANG_WARN_BOOL_CONVERSION = YES; 360 | CLANG_WARN_COMMA = YES; 361 | CLANG_WARN_CONSTANT_CONVERSION = YES; 362 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 363 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 364 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 365 | CLANG_WARN_EMPTY_BODY = YES; 366 | CLANG_WARN_ENUM_CONVERSION = YES; 367 | CLANG_WARN_INFINITE_RECURSION = YES; 368 | CLANG_WARN_INT_CONVERSION = YES; 369 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 370 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 371 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 372 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 373 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 374 | CLANG_WARN_STRICT_PROTOTYPES = YES; 375 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 376 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 377 | CLANG_WARN_UNREACHABLE_CODE = YES; 378 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 379 | CODE_SIGN_IDENTITY = "iPhone Developer"; 380 | COPY_PHASE_STRIP = NO; 381 | DEBUG_INFORMATION_FORMAT = dwarf; 382 | ENABLE_STRICT_OBJC_MSGSEND = YES; 383 | ENABLE_TESTABILITY = YES; 384 | GCC_C_LANGUAGE_STANDARD = gnu11; 385 | GCC_DYNAMIC_NO_PIC = NO; 386 | GCC_NO_COMMON_BLOCKS = YES; 387 | GCC_OPTIMIZATION_LEVEL = 0; 388 | GCC_PREPROCESSOR_DEFINITIONS = ( 389 | "DEBUG=1", 390 | "$(inherited)", 391 | ); 392 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 393 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 394 | GCC_WARN_UNDECLARED_SELECTOR = YES; 395 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 396 | GCC_WARN_UNUSED_FUNCTION = YES; 397 | GCC_WARN_UNUSED_VARIABLE = YES; 398 | IPHONEOS_DEPLOYMENT_TARGET = 11.4; 399 | MTL_ENABLE_DEBUG_INFO = YES; 400 | ONLY_ACTIVE_ARCH = YES; 401 | SDKROOT = iphoneos; 402 | }; 403 | name = Debug; 404 | }; 405 | 33E5C8DC210F799A000BDF6A /* Release */ = { 406 | isa = XCBuildConfiguration; 407 | buildSettings = { 408 | ALWAYS_SEARCH_USER_PATHS = NO; 409 | CLANG_ANALYZER_NONNULL = YES; 410 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 411 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 412 | CLANG_CXX_LIBRARY = "libc++"; 413 | CLANG_ENABLE_MODULES = YES; 414 | CLANG_ENABLE_OBJC_ARC = YES; 415 | CLANG_ENABLE_OBJC_WEAK = YES; 416 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 417 | CLANG_WARN_BOOL_CONVERSION = YES; 418 | CLANG_WARN_COMMA = YES; 419 | CLANG_WARN_CONSTANT_CONVERSION = YES; 420 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 421 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 422 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 423 | CLANG_WARN_EMPTY_BODY = YES; 424 | CLANG_WARN_ENUM_CONVERSION = YES; 425 | CLANG_WARN_INFINITE_RECURSION = YES; 426 | CLANG_WARN_INT_CONVERSION = YES; 427 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 428 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 429 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 430 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 431 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 432 | CLANG_WARN_STRICT_PROTOTYPES = YES; 433 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 434 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 435 | CLANG_WARN_UNREACHABLE_CODE = YES; 436 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 437 | CODE_SIGN_IDENTITY = "iPhone Developer"; 438 | COPY_PHASE_STRIP = NO; 439 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 440 | ENABLE_NS_ASSERTIONS = NO; 441 | ENABLE_STRICT_OBJC_MSGSEND = YES; 442 | GCC_C_LANGUAGE_STANDARD = gnu11; 443 | GCC_NO_COMMON_BLOCKS = YES; 444 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 445 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 446 | GCC_WARN_UNDECLARED_SELECTOR = YES; 447 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 448 | GCC_WARN_UNUSED_FUNCTION = YES; 449 | GCC_WARN_UNUSED_VARIABLE = YES; 450 | IPHONEOS_DEPLOYMENT_TARGET = 11.4; 451 | MTL_ENABLE_DEBUG_INFO = NO; 452 | SDKROOT = iphoneos; 453 | VALIDATE_PRODUCT = YES; 454 | }; 455 | name = Release; 456 | }; 457 | 33E5C8DE210F799A000BDF6A /* Debug */ = { 458 | isa = XCBuildConfiguration; 459 | buildSettings = { 460 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 461 | CODE_SIGN_STYLE = Automatic; 462 | DEVELOPMENT_TEAM = L54KZN9KMH; 463 | INFOPLIST_FILE = GXCardViewDemo/Info.plist; 464 | LD_RUNPATH_SEARCH_PATHS = ( 465 | "$(inherited)", 466 | "@executable_path/Frameworks", 467 | ); 468 | PRODUCT_BUNDLE_IDENTIFIER = com.xfq.GXCardViewDemo; 469 | PRODUCT_NAME = "$(TARGET_NAME)"; 470 | TARGETED_DEVICE_FAMILY = "1,2"; 471 | }; 472 | name = Debug; 473 | }; 474 | 33E5C8DF210F799A000BDF6A /* Release */ = { 475 | isa = XCBuildConfiguration; 476 | buildSettings = { 477 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 478 | CODE_SIGN_STYLE = Automatic; 479 | DEVELOPMENT_TEAM = L54KZN9KMH; 480 | INFOPLIST_FILE = GXCardViewDemo/Info.plist; 481 | LD_RUNPATH_SEARCH_PATHS = ( 482 | "$(inherited)", 483 | "@executable_path/Frameworks", 484 | ); 485 | PRODUCT_BUNDLE_IDENTIFIER = com.xfq.GXCardViewDemo; 486 | PRODUCT_NAME = "$(TARGET_NAME)"; 487 | TARGETED_DEVICE_FAMILY = "1,2"; 488 | }; 489 | name = Release; 490 | }; 491 | 33E5C8E1210F799A000BDF6A /* Debug */ = { 492 | isa = XCBuildConfiguration; 493 | buildSettings = { 494 | BUNDLE_LOADER = "$(TEST_HOST)"; 495 | CODE_SIGN_STYLE = Automatic; 496 | INFOPLIST_FILE = GXCardViewDemoTests/Info.plist; 497 | LD_RUNPATH_SEARCH_PATHS = ( 498 | "$(inherited)", 499 | "@executable_path/Frameworks", 500 | "@loader_path/Frameworks", 501 | ); 502 | PRODUCT_BUNDLE_IDENTIFIER = com.gin.GXCardViewDemoTests; 503 | PRODUCT_NAME = "$(TARGET_NAME)"; 504 | TARGETED_DEVICE_FAMILY = "1,2"; 505 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/GXCardViewDemo.app/GXCardViewDemo"; 506 | }; 507 | name = Debug; 508 | }; 509 | 33E5C8E2210F799A000BDF6A /* Release */ = { 510 | isa = XCBuildConfiguration; 511 | buildSettings = { 512 | BUNDLE_LOADER = "$(TEST_HOST)"; 513 | CODE_SIGN_STYLE = Automatic; 514 | INFOPLIST_FILE = GXCardViewDemoTests/Info.plist; 515 | LD_RUNPATH_SEARCH_PATHS = ( 516 | "$(inherited)", 517 | "@executable_path/Frameworks", 518 | "@loader_path/Frameworks", 519 | ); 520 | PRODUCT_BUNDLE_IDENTIFIER = com.gin.GXCardViewDemoTests; 521 | PRODUCT_NAME = "$(TARGET_NAME)"; 522 | TARGETED_DEVICE_FAMILY = "1,2"; 523 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/GXCardViewDemo.app/GXCardViewDemo"; 524 | }; 525 | name = Release; 526 | }; 527 | 33E5C8E4210F799A000BDF6A /* Debug */ = { 528 | isa = XCBuildConfiguration; 529 | buildSettings = { 530 | CODE_SIGN_STYLE = Automatic; 531 | INFOPLIST_FILE = GXCardViewDemoUITests/Info.plist; 532 | LD_RUNPATH_SEARCH_PATHS = ( 533 | "$(inherited)", 534 | "@executable_path/Frameworks", 535 | "@loader_path/Frameworks", 536 | ); 537 | PRODUCT_BUNDLE_IDENTIFIER = com.gin.GXCardViewDemoUITests; 538 | PRODUCT_NAME = "$(TARGET_NAME)"; 539 | TARGETED_DEVICE_FAMILY = "1,2"; 540 | TEST_TARGET_NAME = GXCardViewDemo; 541 | }; 542 | name = Debug; 543 | }; 544 | 33E5C8E5210F799A000BDF6A /* Release */ = { 545 | isa = XCBuildConfiguration; 546 | buildSettings = { 547 | CODE_SIGN_STYLE = Automatic; 548 | INFOPLIST_FILE = GXCardViewDemoUITests/Info.plist; 549 | LD_RUNPATH_SEARCH_PATHS = ( 550 | "$(inherited)", 551 | "@executable_path/Frameworks", 552 | "@loader_path/Frameworks", 553 | ); 554 | PRODUCT_BUNDLE_IDENTIFIER = com.gin.GXCardViewDemoUITests; 555 | PRODUCT_NAME = "$(TARGET_NAME)"; 556 | TARGETED_DEVICE_FAMILY = "1,2"; 557 | TEST_TARGET_NAME = GXCardViewDemo; 558 | }; 559 | name = Release; 560 | }; 561 | /* End XCBuildConfiguration section */ 562 | 563 | /* Begin XCConfigurationList section */ 564 | 33E5C8AC210F7998000BDF6A /* Build configuration list for PBXProject "GXCardViewDemo" */ = { 565 | isa = XCConfigurationList; 566 | buildConfigurations = ( 567 | 33E5C8DB210F799A000BDF6A /* Debug */, 568 | 33E5C8DC210F799A000BDF6A /* Release */, 569 | ); 570 | defaultConfigurationIsVisible = 0; 571 | defaultConfigurationName = Release; 572 | }; 573 | 33E5C8DD210F799A000BDF6A /* Build configuration list for PBXNativeTarget "GXCardViewDemo" */ = { 574 | isa = XCConfigurationList; 575 | buildConfigurations = ( 576 | 33E5C8DE210F799A000BDF6A /* Debug */, 577 | 33E5C8DF210F799A000BDF6A /* Release */, 578 | ); 579 | defaultConfigurationIsVisible = 0; 580 | defaultConfigurationName = Release; 581 | }; 582 | 33E5C8E0210F799A000BDF6A /* Build configuration list for PBXNativeTarget "GXCardViewDemoTests" */ = { 583 | isa = XCConfigurationList; 584 | buildConfigurations = ( 585 | 33E5C8E1210F799A000BDF6A /* Debug */, 586 | 33E5C8E2210F799A000BDF6A /* Release */, 587 | ); 588 | defaultConfigurationIsVisible = 0; 589 | defaultConfigurationName = Release; 590 | }; 591 | 33E5C8E3210F799A000BDF6A /* Build configuration list for PBXNativeTarget "GXCardViewDemoUITests" */ = { 592 | isa = XCConfigurationList; 593 | buildConfigurations = ( 594 | 33E5C8E4210F799A000BDF6A /* Debug */, 595 | 33E5C8E5210F799A000BDF6A /* Release */, 596 | ); 597 | defaultConfigurationIsVisible = 0; 598 | defaultConfigurationName = Release; 599 | }; 600 | /* End XCConfigurationList section */ 601 | }; 602 | rootObject = 33E5C8A9210F7998000BDF6A /* Project object */; 603 | } 604 | -------------------------------------------------------------------------------- /GXCardViewSample/GXCardViewDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /GXCardViewSample/GXCardViewDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /GXCardViewSample/GXCardViewDemo.xcodeproj/project.xcworkspace/xcuserdata/Gin.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gsyhei/GXCardView/e11971246f4f1476d55e31571d5818c6647ff31a/GXCardViewSample/GXCardViewDemo.xcodeproj/project.xcworkspace/xcuserdata/Gin.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /GXCardViewSample/GXCardViewDemo.xcodeproj/project.xcworkspace/xcuserdata/guoshengyong.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gsyhei/GXCardView/e11971246f4f1476d55e31571d5818c6647ff31a/GXCardViewSample/GXCardViewDemo.xcodeproj/project.xcworkspace/xcuserdata/guoshengyong.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /GXCardViewSample/GXCardViewDemo.xcodeproj/project.xcworkspace/xcuserdata/jason.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gsyhei/GXCardView/e11971246f4f1476d55e31571d5818c6647ff31a/GXCardViewSample/GXCardViewDemo.xcodeproj/project.xcworkspace/xcuserdata/jason.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /GXCardViewSample/GXCardViewDemo.xcodeproj/project.xcworkspace/xcuserdata/shengyongguo.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gsyhei/GXCardView/e11971246f4f1476d55e31571d5818c6647ff31a/GXCardViewSample/GXCardViewDemo.xcodeproj/project.xcworkspace/xcuserdata/shengyongguo.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /GXCardViewSample/GXCardViewDemo.xcodeproj/xcuserdata/Gin.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | -------------------------------------------------------------------------------- /GXCardViewSample/GXCardViewDemo.xcodeproj/xcuserdata/Gin.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | GXCardViewDemo.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | GXCardViewDemo.xcscheme_^#shared#^_ 13 | 14 | orderHint 15 | 0 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /GXCardViewSample/GXCardViewDemo.xcodeproj/xcuserdata/guoshengyong.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /GXCardViewSample/GXCardViewDemo.xcodeproj/xcuserdata/guoshengyong.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | GXCardViewDemo.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /GXCardViewSample/GXCardViewDemo.xcodeproj/xcuserdata/jason.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | -------------------------------------------------------------------------------- /GXCardViewSample/GXCardViewDemo.xcodeproj/xcuserdata/jason.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | GXCardViewDemo.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /GXCardViewSample/GXCardViewDemo.xcodeproj/xcuserdata/shengyongguo.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | GXCardViewDemo.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /GXCardViewSample/GXCardViewDemo/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // GXCardViewDemo 4 | // 5 | // Created by Gin on 2018/7/31. 6 | // Copyright © 2018年 gin. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /GXCardViewSample/GXCardViewDemo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // GXCardViewDemo 4 | // 5 | // Created by Gin on 2018/7/31. 6 | // Copyright © 2018年 gin. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | 24 | - (void)applicationWillResignActive:(UIApplication *)application { 25 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 26 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 27 | } 28 | 29 | 30 | - (void)applicationDidEnterBackground:(UIApplication *)application { 31 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 32 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 33 | } 34 | 35 | 36 | - (void)applicationWillEnterForeground:(UIApplication *)application { 37 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 38 | } 39 | 40 | 41 | - (void)applicationDidBecomeActive:(UIApplication *)application { 42 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 43 | } 44 | 45 | 46 | - (void)applicationWillTerminate:(UIApplication *)application { 47 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 48 | } 49 | 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /GXCardViewSample/GXCardViewDemo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /GXCardViewSample/GXCardViewDemo/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /GXCardViewSample/GXCardViewDemo/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /GXCardViewSample/GXCardViewDemo/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 39 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /GXCardViewSample/GXCardViewDemo/GXCardItemDemoCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // GXCardItemDemoCell.h 3 | // GXCardViewDemo 4 | // 5 | // Created by Gin on 2018/8/3. 6 | // Copyright © 2018年 gin. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "GXCardView.h" 11 | 12 | @interface GXCardItemDemoCell : GXCardViewCell 13 | 14 | @property (nonatomic, weak) IBOutlet UILabel *numberLabel; 15 | @property (nonatomic, weak) IBOutlet UILabel *leftLabel; 16 | @property (nonatomic, weak) IBOutlet UILabel *rightLabel; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /GXCardViewSample/GXCardViewDemo/GXCardItemDemoCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // GXCardItemDemoCell.m 3 | // GXCardViewDemo 4 | // 5 | // Created by Gin on 2018/8/3. 6 | // Copyright © 2018年 gin. All rights reserved. 7 | // 8 | 9 | #import "GXCardItemDemoCell.h" 10 | 11 | @implementation GXCardItemDemoCell 12 | 13 | - (void)awakeFromNib { 14 | [super awakeFromNib]; 15 | // Initialization code 16 | 17 | self.layer.cornerRadius = 10.0; 18 | self.layer.borderColor = [UIColor grayColor].CGColor; 19 | self.layer.borderWidth = 1.0; 20 | // self.layer.shadowOffset = CGSizeMake(1.0, 3.0); 21 | // self.layer.shadowRadius = 4.0; 22 | // self.layer.shadowOpacity = 0.4; 23 | // self.layer.shadowColor = [UIColor grayColor].CGColor; 24 | } 25 | 26 | - (IBAction)buttonClicked:(id)sender { 27 | 28 | } 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /GXCardViewSample/GXCardViewDemo/GXCardItemDemoCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 33 | 42 | 52 | 62 | 73 | 80 | 91 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | -------------------------------------------------------------------------------- /GXCardViewSample/GXCardViewDemo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /GXCardViewSample/GXCardViewDemo/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // GXCardViewDemo 4 | // 5 | // Created by Gin on 2018/7/31. 6 | // Copyright © 2018年 gin. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /GXCardViewSample/GXCardViewDemo/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // GXCardViewDemo 4 | // 5 | // Created by Gin on 2018/7/31. 6 | // Copyright © 2018年 gin. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "GXCardView.h" 11 | #import "GXCardItemDemoCell.h" 12 | 13 | @interface ViewController () 14 | @property (nonatomic, weak) IBOutlet GXCardView *cardView; 15 | @property (nonatomic, assign) NSInteger cellCount; 16 | @end 17 | 18 | @implementation ViewController 19 | 20 | - (void)viewDidLoad { 21 | [super viewDidLoad]; 22 | // self.view.backgroundColor = [UIColor colorWithWhite:0.94 alpha:1]; 23 | self.cellCount = 10; // card总数 24 | 25 | self.cardView.dataSource = self; 26 | self.cardView.delegate = self; 27 | self.cardView.visibleCount = 5; 28 | self.cardView.lineSpacing = 15.0; 29 | self.cardView.interitemSpacing = 10.0; 30 | self.cardView.maxAngle = 15.0; 31 | self.cardView.maxRemoveDistance = 100.0; 32 | self.cardView.isRepeat = YES; // cellCount < visibleCount的情况下不能为YES 33 | [self.cardView registerNib:[UINib nibWithNibName:NSStringFromClass([GXCardItemDemoCell class]) bundle:nil] forCellReuseIdentifier:@"GXCardViewCell"]; 34 | [self.cardView reloadData]; 35 | } 36 | 37 | - (void)didReceiveMemoryWarning { 38 | [super didReceiveMemoryWarning]; 39 | // Dispose of any resources that can be recreated. 40 | } 41 | 42 | #pragma mark - GXCardViewDataSource 43 | 44 | - (GXCardViewCell *)cardView:(GXCardView *)cardView cellForRowAtIndex:(NSInteger)index { 45 | GXCardItemDemoCell *cell = [cardView dequeueReusableCellWithIdentifier:@"GXCardViewCell"]; 46 | cell.numberLabel.text = [NSString stringWithFormat:@"%ld", (long)index]; 47 | cell.leftLabel.hidden = YES; 48 | cell.rightLabel.hidden = YES; 49 | cell.layer.cornerRadius = 12.0; 50 | 51 | return cell; 52 | } 53 | 54 | - (NSInteger)numberOfCountInCardView:(UITableView *)cardView { 55 | return self.cellCount; 56 | } 57 | 58 | #pragma mark - GXCardViewDelegate 59 | 60 | - (void)cardView:(GXCardView *)cardView didRemoveLastCell:(GXCardViewCell *)cell forRowAtIndex:(NSInteger)index { 61 | if (!cardView.isRepeat) { 62 | [cardView reloadDataAnimated:YES]; 63 | } 64 | } 65 | 66 | - (void)cardView:(GXCardView *)cardView didRemoveCell:(GXCardViewCell *)cell forRowAtIndex:(NSInteger)index direction:(GXCardCellSwipeDirection)direction { 67 | NSLog(@"didRemoveCell forRowAtIndex = %ld, direction = %ld", index, direction); 68 | 69 | if (!cardView.isRepeat && index == 8) { 70 | self.cellCount = 15; 71 | [cardView reloadMoreDataAnimated:YES]; 72 | } 73 | } 74 | 75 | - (void)cardView:(GXCardView *)cardView didDisplayCell:(GXCardViewCell *)cell forRowAtIndex:(NSInteger)index { 76 | NSLog(@"didDisplayCell forRowAtIndex = %ld", index); 77 | } 78 | 79 | - (void)cardView:(GXCardView *)cardView didMoveCell:(GXCardViewCell *)cell forMovePoint:(CGPoint)point direction:(GXCardCellSwipeDirection)direction { 80 | GXCardItemDemoCell *dcell = (GXCardItemDemoCell*)cell; 81 | 82 | dcell.leftLabel.hidden = !(direction == GXCardCellSwipeDirectionRight); 83 | dcell.rightLabel.hidden = !(direction == GXCardCellSwipeDirectionLeft); 84 | 85 | NSLog(@"move point = %@, direction = %ld", NSStringFromCGPoint(point), direction); 86 | } 87 | 88 | #pragma mark - 89 | 90 | - (IBAction)leftButtonClick:(id)sender { 91 | [self.cardView removeTopCardViewFromSwipe:GXCardCellSwipeDirectionLeft]; 92 | // [self.cardView reloadDataFormIndex:2 animated:YES]; 93 | } 94 | 95 | - (IBAction)rightButtonClick:(id)sender { 96 | [self.cardView removeTopCardViewFromSwipe:GXCardCellSwipeDirectionRight]; 97 | } 98 | 99 | @end 100 | -------------------------------------------------------------------------------- /GXCardViewSample/GXCardViewDemo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // GXCardViewDemo 4 | // 5 | // Created by Gin on 2018/7/31. 6 | // Copyright © 2018年 gin. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /GXCardViewSample/GXCardViewDemoTests/GXCardViewDemoTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // GXCardViewDemoTests.m 3 | // GXCardViewDemoTests 4 | // 5 | // Created by Gin on 2018/7/31. 6 | // Copyright © 2018年 gin. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface GXCardViewDemoTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation GXCardViewDemoTests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | // Put setup code here. This method is called before the invocation of each test method in the class. 20 | } 21 | 22 | - (void)tearDown { 23 | // Put teardown code here. This method is called after the invocation of each test method in the class. 24 | [super tearDown]; 25 | } 26 | 27 | - (void)testExample { 28 | // This is an example of a functional test case. 29 | // Use XCTAssert and related functions to verify your tests produce the correct results. 30 | } 31 | 32 | - (void)testPerformanceExample { 33 | // This is an example of a performance test case. 34 | [self measureBlock:^{ 35 | // Put the code you want to measure the time of here. 36 | }]; 37 | } 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /GXCardViewSample/GXCardViewDemoTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /GXCardViewSample/GXCardViewDemoUITests/GXCardViewDemoUITests.m: -------------------------------------------------------------------------------- 1 | // 2 | // GXCardViewDemoUITests.m 3 | // GXCardViewDemoUITests 4 | // 5 | // Created by Gin on 2018/7/31. 6 | // Copyright © 2018年 gin. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface GXCardViewDemoUITests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation GXCardViewDemoUITests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | 22 | // In UI tests it is usually best to stop immediately when a failure occurs. 23 | self.continueAfterFailure = NO; 24 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. 25 | [[[XCUIApplication alloc] init] launch]; 26 | 27 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 28 | } 29 | 30 | - (void)tearDown { 31 | // Put teardown code here. This method is called after the invocation of each test method in the class. 32 | [super tearDown]; 33 | } 34 | 35 | - (void)testExample { 36 | // Use recording to get started writing UI tests. 37 | // Use XCTAssert and related functions to verify your tests produce the correct results. 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /GXCardViewSample/GXCardViewDemoUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Gin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GXCardView 2 | 卡片式布局(探探附近/QQ配对),可以设置卡片堆叠效果,可以设置循环效果。 3 | 有建议可以联系QQ交流群:1101980843,喜欢就给个star哦,谢谢关注! 4 |

5 | 6 |

7 | 8 | 先上demo菜单效果 9 | -- 10 |

11 | 12 |

13 | 14 | Requirements 15 | -- 16 |

17 | 18 | 19 | 20 |

21 | 22 | Usage in you Podfile: 23 | -- 24 | 25 | ``` 26 | pod 'GXCardView' 27 | ``` 28 | * 其它版本 [Swift版本](https://github.com/gsyhei/GXCardView-Swift) 29 | ``` 30 | pod 'GXCardView-Swift' 31 | ``` 32 | 33 | GXCardViewDataSource 34 | -- 35 | 36 | ```objc 37 | - (NSInteger)numberOfCountInCardView:(GXCardView *)cardView; 38 | 39 | - (GXCardViewCell *)cardView:(GXCardView *)cardView cellForRowAtIndex:(NSInteger)index; 40 | ``` 41 | 42 | GXCardViewDelegate 43 | -- 44 | 45 | ```objc 46 | - (void)cardView:(GXCardView *)cardView didRemoveCell:(GXCardViewCell *)cell forRowAtIndex:(NSInteger)index direction:(GXCardCellSwipeDirection)direction; 47 | 48 | - (void)cardView:(GXCardView *)cardView didRemoveLastCell:(GXCardViewCell *)cell forRowAtIndex:(NSInteger)index; 49 | 50 | - (void)cardView:(GXCardView *)cardView didDisplayCell:(GXCardViewCell *)cell forRowAtIndex:(NSInteger)index; 51 | 52 | - (void)cardView:(GXCardView *)cardView didMoveCell:(GXCardViewCell *)cell forMovePoint:(CGPoint)point direction:(GXCardCellSwipeDirection)direction; 53 | ``` 54 | 55 | 重载数据 56 | -- 57 | 58 | ```objc 59 | - (void)reloadData; 60 | - (void)reloadDataAnimated:(BOOL)animated; 61 | ``` 62 | 63 | 加载更多数据 64 | -- 65 | 66 | ```objc 67 | - (void)reloadMoreData; 68 | - (void)reloadMoreDataAnimated:(BOOL)animated; 69 | ``` 70 | 71 | 从index开始加载 72 | -- 73 | 74 | ```objc 75 | - (void)reloadDataFormIndex:(NSInteger)index; 76 | - (void)reloadDataFormIndex:(NSInteger)index animated:(BOOL)animated; 77 | ``` 78 | 79 | 80 | 可以设置参数 81 | -- 82 | 83 | ```objc 84 | /** 卡片可见数量(默认3) */ 85 | @property (nonatomic, assign) NSInteger visibleCount; 86 | /** 行间距(默认10.0,可自行计算scale比例来做间距) */ 87 | @property (nonatomic, assign) CGFloat lineSpacing; 88 | /** 列间距(默认10.0,可自行计算scale比例来做间距) */ 89 | @property (nonatomic, assign) CGFloat interitemSpacing; 90 | /** 侧滑最大角度(默认15°) */ 91 | @property (nonatomic, assign) CGFloat maxAngle; 92 | /** 最大移除距离(默认屏幕的1/4) */ 93 | @property (nonatomic, assign) CGFloat maxRemoveDistance; 94 | /** 是否重复(默认NO) */ 95 | @property (nonatomic, assign) BOOL isRepeat; 96 | ``` 97 | 98 | License 99 | -- 100 | MIT 101 | 102 | 103 | --------------------------------------------------------------------------------