HXCollectionView.m 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. //
  2. // HXCollectionView.m
  3. // HXPhotoPickerExample
  4. //
  5. // Created by Silence on 17/2/17.
  6. // Copyright © 2017年 Silence. All rights reserved.
  7. //
  8. #import "HXCollectionView.h"
  9. #import "HXPhotoSubViewCell.h"
  10. #import "HXPhotoModel.h"
  11. @interface HXCollectionView ()
  12. @property (weak, nonatomic) UILongPressGestureRecognizer *longPgr;
  13. @property (strong, nonatomic) NSIndexPath *originalIndexPath;
  14. @property (strong, nonatomic) UIView *tempMoveCell;
  15. @property (assign, nonatomic) CGPoint lastPoint;
  16. @property (nonatomic, strong) UICollectionViewCell *dragCell;
  17. @property (nonatomic, strong) NSIndexPath *moveIndexPath;
  18. @property (nonatomic, assign) BOOL isDeleteItem;
  19. @end
  20. @implementation HXCollectionView
  21. @dynamic delegate;
  22. @dynamic dataSource;
  23. - (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout
  24. {
  25. if (self = [super initWithFrame:frame collectionViewLayout:layout]) {
  26. self.layer.masksToBounds = NO;
  27. self.showsHorizontalScrollIndicator = NO;
  28. self.showsVerticalScrollIndicator = NO;
  29. self.editEnabled = YES;
  30. [self addGesture];
  31. }
  32. return self;
  33. }
  34. - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
  35. [super touchesBegan:touches withEvent:event];
  36. [[UIApplication sharedApplication].keyWindow endEditing:YES];
  37. }
  38. - (void)addGesture
  39. {
  40. UILongPressGestureRecognizer *longPgr = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPrgEvent:)];
  41. longPgr.minimumPressDuration = 0.25f;
  42. longPgr.enabled = self.editEnabled;
  43. [self addGestureRecognizer:longPgr];
  44. self.longPgr = longPgr;
  45. }
  46. #pragma mark - 修复iOS13 下滚动异常API
  47. #ifdef __IPHONE_13_0
  48. - (void)scrollToItemAtIndexPath:(NSIndexPath *)indexPath atScrollPosition:(UICollectionViewScrollPosition)scrollPosition animated:(BOOL)animated{
  49. [super scrollToItemAtIndexPath:indexPath atScrollPosition:scrollPosition animated:animated];
  50. //修复13下 Cell滚动位置异常
  51. if (@available(iOS 13.0, *)) {
  52. //顶部
  53. if(self.contentOffset.y < 0){
  54. [self setContentOffset:CGPointZero];
  55. return;
  56. }
  57. //底部
  58. if(self.contentOffset.y > self.contentSize.height){
  59. [self setContentOffset:CGPointMake(0, self.contentSize.height)];
  60. }
  61. }
  62. }
  63. #endif
  64. - (void)setEditEnabled:(BOOL)editEnabled {
  65. _editEnabled = editEnabled;
  66. self.longPgr.enabled = editEnabled;
  67. }
  68. - (void)longPrgEvent:(UILongPressGestureRecognizer *)longPgr
  69. {
  70. if (longPgr.state == UIGestureRecognizerStateBegan) {
  71. self.isDeleteItem = NO;
  72. [self gestureRecognizerBegan:longPgr];
  73. if ([(HXPhotoSubViewCell *)[self cellForItemAtIndexPath:self.originalIndexPath] model].type == HXPhotoModelMediaTypeCamera) {
  74. return;
  75. }
  76. if ([self.delegate respondsToSelector:@selector(collectionView:gestureRecognizerBegan:indexPath:)]) {
  77. [self.delegate collectionView:self gestureRecognizerBegan:longPgr indexPath:self.originalIndexPath];
  78. }
  79. }
  80. if (longPgr.state == UIGestureRecognizerStateChanged) {
  81. if (_originalIndexPath.section != 0 || [(HXPhotoSubViewCell *)[self cellForItemAtIndexPath:self.originalIndexPath] model].type == HXPhotoModelMediaTypeCamera) {
  82. return;
  83. }
  84. if ([self.delegate respondsToSelector:@selector(collectionView:gestureRecognizerChange:indexPath:)]) {
  85. [self.delegate collectionView:self gestureRecognizerChange:longPgr indexPath:self.originalIndexPath];
  86. }
  87. [self gestureRecognizerChange:longPgr];
  88. [self moveCell];
  89. }
  90. if (longPgr.state == UIGestureRecognizerStateCancelled ||
  91. longPgr.state == UIGestureRecognizerStateEnded){
  92. if ([(HXPhotoSubViewCell *)[self cellForItemAtIndexPath:self.originalIndexPath] model].type == HXPhotoModelMediaTypeCamera) {
  93. return;
  94. }
  95. if ([self.delegate respondsToSelector:@selector(collectionView:gestureRecognizerEnded:indexPath:)]) {
  96. [self.delegate collectionView:self gestureRecognizerEnded:longPgr indexPath:self.originalIndexPath];
  97. }
  98. BOOL isRemoveItem = NO;
  99. if ([self.delegate respondsToSelector:@selector(collectionViewShouldDeleteCurrentMoveItem:gestureRecognizer:indexPath:)]) {
  100. isRemoveItem = [self.delegate collectionViewShouldDeleteCurrentMoveItem:self gestureRecognizer:longPgr indexPath:self.originalIndexPath];
  101. }
  102. if (isRemoveItem) {
  103. if ([self.delegate respondsToSelector:@selector(dragCellCollectionViewCellEndMoving:)]) {
  104. [self.delegate dragCellCollectionViewCellEndMoving:self];
  105. }
  106. [UIView animateWithDuration:0.25 animations:^{
  107. self.tempMoveCell.alpha = 0;
  108. } completion:^(BOOL finished) {
  109. [self.tempMoveCell removeFromSuperview];
  110. self.dragCell.hidden = NO;
  111. if ([self.delegate respondsToSelector:@selector(collectionViewNeedReloadData:)]) {
  112. [self.delegate collectionViewNeedReloadData:self];
  113. }
  114. }];
  115. return;
  116. }
  117. if ([(HXPhotoSubViewCell *)[self cellForItemAtIndexPath:self.originalIndexPath] model].type == HXPhotoModelMediaTypeCamera) {
  118. return;
  119. }
  120. [self handelItemInSpace];
  121. if (!self.isDeleteItem) {
  122. [self gestureRecognizerCancelOrEnd:longPgr];
  123. }
  124. }
  125. }
  126. - (void)gestureRecognizerBegan:(UILongPressGestureRecognizer *)longPgr
  127. {
  128. self.originalIndexPath = [self indexPathForItemAtPoint:[longPgr locationOfTouch:0 inView:longPgr.view]];
  129. HXPhotoSubViewCell *cell = (HXPhotoSubViewCell *)[self cellForItemAtIndexPath:self.originalIndexPath];
  130. if (cell.model.type == HXPhotoModelMediaTypeCamera) {
  131. return;
  132. }
  133. UIView *tempMoveCell = [cell snapshotViewAfterScreenUpdates:NO];
  134. self.dragCell = cell;
  135. cell.hidden = YES;
  136. self.tempMoveCell = tempMoveCell;
  137. self.tempMoveCell.frame = cell.frame;
  138. [UIView animateWithDuration:0.2 animations:^{
  139. self.tempMoveCell.alpha = 0.8;
  140. self.tempMoveCell.transform = CGAffineTransformMakeScale(1.15, 1.15);
  141. }];
  142. [self addSubview:self.tempMoveCell];
  143. self.lastPoint = [longPgr locationOfTouch:0 inView:self];
  144. }
  145. - (void)gestureRecognizerChange:(UILongPressGestureRecognizer *)longPgr
  146. {
  147. CGFloat tranX = [longPgr locationOfTouch:0 inView:longPgr.view].x - self.lastPoint.x;
  148. CGFloat tranY = [longPgr locationOfTouch:0 inView:longPgr.view].y - self.lastPoint.y;
  149. self.tempMoveCell.center = CGPointApplyAffineTransform(_tempMoveCell.center, CGAffineTransformMakeTranslation(tranX, tranY));
  150. self.lastPoint = [longPgr locationOfTouch:0 inView:longPgr.view];
  151. }
  152. - (void)gestureRecognizerCancelOrEnd:(UILongPressGestureRecognizer *)longPgr
  153. {
  154. if ([self.delegate respondsToSelector:@selector(dragCellCollectionViewCellEndMoving:)]) {
  155. [self.delegate dragCellCollectionViewCellEndMoving:self];
  156. }
  157. self.userInteractionEnabled = NO;
  158. [UIView animateWithDuration:0.25 animations:^{
  159. self.tempMoveCell.center = self.dragCell.center;
  160. self.tempMoveCell.transform = CGAffineTransformIdentity;
  161. self.tempMoveCell.alpha = 1;
  162. } completion:^(BOOL finished) {
  163. [self.tempMoveCell removeFromSuperview];
  164. self.dragCell.hidden = NO;
  165. self.userInteractionEnabled = YES;
  166. if ([self.delegate respondsToSelector:@selector(collectionViewNeedReloadData:)]) {
  167. [self.delegate collectionViewNeedReloadData:self];
  168. }
  169. }];
  170. }
  171. - (NSArray *)findAllLastIndexPathInVisibleSection {
  172. NSArray *array = [self indexPathsForVisibleItems];
  173. if (!array.count) {
  174. return nil;
  175. }
  176. array = [array sortedArrayUsingComparator:^NSComparisonResult(NSIndexPath * _Nonnull obj1, NSIndexPath * _Nonnull obj2) {
  177. return obj1.section > obj2.section;
  178. }];
  179. NSMutableArray *totalArray = [NSMutableArray arrayWithCapacity:0];
  180. NSInteger tempSection = -1;
  181. NSMutableArray *tempArray = nil;
  182. for (NSIndexPath *indexPath in array) {
  183. if (tempSection != indexPath.section) {
  184. tempSection = indexPath.section;
  185. if (tempArray) {
  186. NSArray *temp = [tempArray sortedArrayUsingComparator:^NSComparisonResult(NSIndexPath * _Nonnull obj1, NSIndexPath * _Nonnull obj2) {
  187. return obj1.row > obj2.row;
  188. }];
  189. [totalArray addObject:temp.lastObject];
  190. }
  191. tempArray = [NSMutableArray arrayWithCapacity:0];
  192. }
  193. [tempArray addObject:indexPath];
  194. }
  195. NSArray *temp = [tempArray sortedArrayUsingComparator:^NSComparisonResult(NSIndexPath * _Nonnull obj1, NSIndexPath * _Nonnull obj2) {
  196. return obj1.row > obj2.row;
  197. }];
  198. if (temp.count) {
  199. [totalArray addObject:temp.lastObject];
  200. }
  201. return totalArray.copy;
  202. }
  203. - (void)handelItemInSpace {
  204. NSArray *totalArray = [self findAllLastIndexPathInVisibleSection];
  205. //找到目标空白区域
  206. // CGRect rect;
  207. _moveIndexPath = nil;
  208. NSMutableArray *sourceArray = nil;
  209. //获取数据源
  210. if ([self.dataSource respondsToSelector:@selector(dataSourceArrayOfCollectionView:)]) {
  211. sourceArray = [NSMutableArray arrayWithArray:[self.dataSource dataSourceArrayOfCollectionView:self]];
  212. }
  213. for (NSIndexPath *indexPath in totalArray) {
  214. HXPhotoSubViewCell *sectionLastCell = (HXPhotoSubViewCell *)[self cellForItemAtIndexPath:indexPath];
  215. CGRect tempRect = CGRectMake(CGRectGetMaxX(sectionLastCell.frame),
  216. CGRectGetMinY(sectionLastCell.frame),
  217. self.frame.size.width - CGRectGetMaxX(sectionLastCell.frame),
  218. CGRectGetHeight(sectionLastCell.frame));
  219. //空白区域小于item款度(实际是item的列间隙)
  220. if (CGRectGetWidth(tempRect) < CGRectGetWidth(sectionLastCell.frame)) {
  221. continue;
  222. }
  223. if (sectionLastCell.model.type == HXPhotoModelMediaTypeCamera) {
  224. continue;
  225. }
  226. if (CGRectContainsPoint(tempRect, _tempMoveCell.center)) {
  227. // rect = tempRect;
  228. _moveIndexPath = indexPath;
  229. break;
  230. }
  231. }
  232. if (_moveIndexPath != nil) {
  233. [self moveItemToIndexPath:_moveIndexPath withSource:sourceArray];
  234. }else{
  235. _moveIndexPath = _originalIndexPath;
  236. UICollectionViewCell *sectionLastCell = [self cellForItemAtIndexPath:_moveIndexPath];
  237. float spaceHeight = (self.frame.size.height - CGRectGetMaxY(sectionLastCell.frame)) > CGRectGetHeight(sectionLastCell.frame)?
  238. (self.frame.size.height - CGRectGetMaxY(sectionLastCell.frame)):0;
  239. CGRect spaceRect = CGRectMake(0,
  240. CGRectGetMaxY(sectionLastCell.frame),
  241. self.frame.size.width,
  242. spaceHeight);
  243. if (spaceHeight != 0 && CGRectContainsPoint(spaceRect, _tempMoveCell.center)) {
  244. [self moveItemToIndexPath:_moveIndexPath withSource:sourceArray];
  245. }
  246. }
  247. }
  248. - (void)moveItemToIndexPath:(NSIndexPath *)indexPath withSource:(NSMutableArray *)array
  249. {
  250. if (_originalIndexPath.section == indexPath.section ){
  251. //同一分组
  252. if (_originalIndexPath.row != indexPath.row) {
  253. [self exchangeItemInSection:indexPath withSource:array];
  254. }else if (_originalIndexPath.row == indexPath.row){
  255. return;
  256. }
  257. }
  258. }
  259. - (void)moveCell{
  260. for (HXPhotoSubViewCell *cell in [self visibleCells]) {
  261. if ([self indexPathForCell:cell] == _originalIndexPath) {
  262. continue;
  263. }
  264. if (cell.model.type == HXPhotoModelMediaTypeCamera) {
  265. continue;
  266. }
  267. //计算中心距
  268. CGFloat spacingX = fabs(_tempMoveCell.center.x - cell.center.x);
  269. CGFloat spacingY = fabs(_tempMoveCell.center.y - cell.center.y);
  270. if (spacingX <= _tempMoveCell.bounds.size.width / 2.0f && spacingY <= _tempMoveCell.bounds.size.height / 2.0f) {
  271. _moveIndexPath = [self indexPathForCell:cell];
  272. if (_moveIndexPath.section != 0) {
  273. return;
  274. }
  275. //更新数据源
  276. [self updateDataSource];
  277. //移动
  278. [self moveItemAtIndexPath:_originalIndexPath toIndexPath:_moveIndexPath];
  279. //通知代理
  280. if ([self.delegate respondsToSelector:@selector(dragCellCollectionView:moveCellFromIndexPath:toIndexPath:)]) {
  281. [self.delegate dragCellCollectionView:self moveCellFromIndexPath:_originalIndexPath toIndexPath:_moveIndexPath];
  282. }
  283. //设置移动后的起始indexPath
  284. _originalIndexPath = _moveIndexPath;
  285. }
  286. }
  287. }
  288. - (void)exchangeItemInSection:(NSIndexPath *)indexPath withSource:(NSMutableArray *)sourceArray{
  289. NSMutableArray *orignalSection = [NSMutableArray arrayWithArray:sourceArray];
  290. NSInteger currentRow = _originalIndexPath.row;
  291. NSInteger toRow = indexPath.row;
  292. [orignalSection exchangeObjectAtIndex:currentRow withObjectAtIndex:toRow];
  293. //将重排好的数据传递给外部
  294. if ([self.delegate respondsToSelector:@selector(dragCellCollectionView:newDataArrayAfterMove:)]) {
  295. [self.delegate dragCellCollectionView:self newDataArrayAfterMove:sourceArray.copy];
  296. }
  297. [self moveItemAtIndexPath:_originalIndexPath toIndexPath:indexPath];
  298. }
  299. - (void)updateDataSource{
  300. NSMutableArray *temp = @[].mutableCopy;
  301. //获取数据源
  302. if ([self.dataSource respondsToSelector:@selector(dataSourceArrayOfCollectionView:)]) {
  303. [temp addObjectsFromArray:[self.dataSource dataSourceArrayOfCollectionView:self]];
  304. }
  305. //判断数据源是单个数组还是数组套数组的多section形式,YES表示数组套数组
  306. BOOL dataTypeCheck = ([self numberOfSections] != 1 || ([self numberOfSections] == 1 && [temp.firstObject isKindOfClass:[NSArray class]]));
  307. if (dataTypeCheck) {
  308. for (int i = 0; i < temp.count; i ++) {
  309. [temp replaceObjectAtIndex:i withObject:[temp[i] mutableCopy]];
  310. }
  311. }
  312. if (_moveIndexPath.section == _originalIndexPath.section) {
  313. NSMutableArray *orignalSection = dataTypeCheck ? temp[_originalIndexPath.section] : temp;
  314. if (_moveIndexPath.item > _originalIndexPath.item) {
  315. for (NSUInteger i = _originalIndexPath.item; i < _moveIndexPath.item ; i ++) {
  316. [orignalSection exchangeObjectAtIndex:i withObjectAtIndex:i + 1];
  317. }
  318. }else{
  319. for (NSUInteger i = _originalIndexPath.item; i > _moveIndexPath.item ; i --) {
  320. [orignalSection exchangeObjectAtIndex:i withObjectAtIndex:i - 1];
  321. }
  322. }
  323. }else{
  324. NSMutableArray *orignalSection = temp[_originalIndexPath.section];
  325. NSMutableArray *currentSection = temp[_moveIndexPath.section];
  326. [currentSection insertObject:orignalSection[_originalIndexPath.item] atIndex:_moveIndexPath.item];
  327. [orignalSection removeObject:orignalSection[_originalIndexPath.item]];
  328. }
  329. //将重排好的数据传递给外部
  330. if ([self.delegate respondsToSelector:@selector(dragCellCollectionView:newDataArrayAfterMove:)]) {
  331. [self.delegate dragCellCollectionView:self newDataArrayAfterMove:temp.copy];
  332. }
  333. }
  334. @end