前段时间由于公司需求,恰好需要做一个CollectionView的Item长按后抖动并且可移动效果。但由于一些原因,当时并没有来得及去处理,所以一直心有遗憾。目前市场上此功能并不少见,而且在github上也有一些类似的开源代码,所以其实总结来说:首先并不能作为一个功能难点,只能说是兴趣至此;其次也是真心希望能帮助一些我能帮助的人,以及希望大家能给些建议。都说不想当将军的士兵不是好士兵,所以我觉得,不能溜溜的马始终都是骡子...嘿嘿...回归正题...(可以复制此链接浏览器下载demo http://git.oschina.net/JHissuperman/CollectionView)
1.首先是UICollectionView的创建:
//创建一个layout布局类
UICollectionViewFlowLayout* layout = [[UICollectionViewFlowLayout alloc]init];
//设置布局方向为垂直流布局
layout.scrollDirection = UICollectionViewScrollDirectionVertical;
//设置每个item的大小为127.5*127.5
layout.itemSize = CGSizeMake(114*kWidth/750.00, 114*kWidth/750.00);
//整体view据上左下右距离
layout.sectionInset = UIEdgeInsetsMake(48*kWidth/750.00, 48*kWidth/750.00, 48*kWidth/750.00,48*kWidth/750.00);
//每个item上下距离
layout.minimumLineSpacing = 90*kWidth/750.00;
//每个item左右距离
layout.minimumInteritemSpacing = 66*kWidth/750.00;
//创建collectionView 通过一个布局策略layout来创建
_vibrate = [[UICollectionView alloc]initWithFrame:CGRectMake(0, 0*kWidth/750.00, kWidth, kHeight) collectionViewLayout:layout];
_vibrate.delegate = self;
_vibrate.dataSource = self;
_vibrate.backgroundColor = [UIColor lightGrayColor];
_vibrate.showsHorizontalScrollIndicator = NO;
_vibrate.showsVerticalScrollIndicator = NO;
_vibrate.userInteractionEnabled = YES;
//注册item类型 这里使用系统的类型
[_vibrate registerClass:[VibrateCollectionViewCell class] forCellWithReuseIdentifier:@"vibrate"];
[self.view addSubview:_vibrate];
2.然后实现collectionview的代理方法:
//返回分区个数
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{
return 1;
}
//返回每个分区的item个数
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
return _collectionArr.count;
}
//返回每个item
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
VibrateCollectionViewCell * cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"vibrate" forIndexPath:indexPath];
// [cell sizeToFit];
if(!cell){
NSLog(@"-----------");
}
NSInteger num = indexPath.row;
cell.nameLable.text = _collectionArr[num];
cell.headImageView.image = [UIImage imageNamed:[NSString stringWithFormat:@"00%@",_collectionArr[num]]];
if(_isBegin == YES ){
[self starLongPress:cell];
}
return cell;
}
3.添加手势
3.1 抖动手势的添加
- (void)addRecognize{
//添加长按抖动手势
if(!_recognize){
_recognize = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPress:)];
}
//长按响应时间
_recognize.minimumPressDuration = 1;
[_vibrate addGestureRecognizer:_recognize];
}
- (void)longPress:(UILongPressGestureRecognizer *)longGesture {
//判断手势状态
switch (longGesture.state) {
case UIGestureRecognizerStateBegan:{
//判断手势落点位置是否在路径上
NSIndexPath *indexPath = [self.vibrate indexPathForItemAtPoint:[longGesture locationInView:self.vibrate]];
if (indexPath.row >= 0) {//第一个不可移动 个人限制
_isBegin = YES;
[_vibrate removeGestureRecognizer:_recognize];
[self addLongGesture];
[self addSureButton];
[_vibrate reloadData];
NSLog(@"1");
}else{
break;
}
}
break;
case UIGestureRecognizerStateChanged:{
NSLog(@"2");
break;
}
case UIGestureRecognizerStateEnded:
NSLog(@"3");
break;
default:
NSLog(@"4");
break;
}
}
//开始抖动
- (void)starLongPress:(VibrateCollectionViewCell*)cell{
CABasicAnimation *animation = (CABasicAnimation *)[cell.layer animationForKey:@"rotation"];
if (animation == nil) {
[self shakeImage:cell];
}else {
[self resume:cell];
}
}
//这个参数的理解比较复杂,我的理解是所在layer的时间与父layer的时间的相对速度,为1时两者速度一样,为2那么父layer过了一秒,而所在layer过了两秒(进行两秒动画),为0则静止。
- (void)pause:(VibrateCollectionViewCell*)cell {
cell.layer.speed = 0.0;
}
- (void)resume:(VibrateCollectionViewCell*)cell {
cell.layer.speed = 1.0;
}
- (void)shakeImage:(VibrateCollectionViewCell*)cell {
//创建动画对象,绕Z轴旋转
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
//设置属性,周期时长
[animation setDuration:0.08];
//抖动角度
animation.fromValue = @(-M_1_PI/2);
animation.toValue = @(M_1_PI/2);
//重复次数,无限大
animation.repeatCount = HUGE_VAL;
//恢复原样
animation.autoreverses = YES;
//锚点设置为图片中心,绕中心抖动
cell.layer.anchorPoint = CGPointMake(0.5, 0.5);
[cell.layer addAnimation:animation forKey:@"rotation"];
}
3.2 移动手势的添加
- (void)addLongGesture{
//此处给其增加长按手势,用此手势触发cell移动效果
if(!_longGesture){
_longGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handlelongGesture:)];
}
_longGesture.minimumPressDuration = 0;
[_vibrate addGestureRecognizer:_longGesture];
}
//监听手势,并设置其允许移动cell和交换资源
- (void)handlelongGesture:(UILongPressGestureRecognizer *)longGesture {
//判断手势状态
switch (longGesture.state) {
case UIGestureRecognizerStateBegan:{
//判断手势落点位置是否在路径上
NSIndexPath *indexPath = [self.vibrate indexPathForItemAtPoint:[longGesture locationInView:self.vibrate]];
if (indexPath.row > 0) {//第一个不可移动 个人限制
[_vibrate beginInteractiveMovementForItemAtIndexPath:indexPath];
}else{
break;
}
}
break;
case UIGestureRecognizerStateChanged:{
NSIndexPath* indexPath = [_vibrate indexPathForItemAtPoint:[longGesture locationInView:_vibrate]];
if(indexPath.row<1){
break;//第一个不可移动 个人限制
}
//移动过程当中随时更新cell位置
[_vibrate updateInteractiveMovementTargetPosition:[longGesture locationInView:_vibrate]];
break;
}
case UIGestureRecognizerStateEnded:
//移动结束后关闭cell移动
[_vibrate endInteractiveMovement];
break;
default:
[_vibrate endInteractiveMovement];
// [_vibrate cancelInteractiveMovement];
break;
}
}
- (BOOL)collectionView:(UICollectionView *)collectionView canMoveItemAtIndexPath:(NSIndexPath *)indexPath{
return YES;
}
- (void)collectionView:(UICollectionView *)collectionView moveItemAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath*)destinationIndexPath {
//取出源item数据
id objc = [_collectionArr objectAtIndex:sourceIndexPath.item];
//从资源数组中移除该数据
[_collectionArr removeObject:objc];
//将数据插入到资源数组中的目标位置上
[_collectionArr insertObject:objc atIndex:destinationIndexPath.item];
// [_vibrate reloadData];
}
具体效果 可以复制此链接浏览器下载demo http://git.oschina.net/JHissuperman/CollectionView
希望能帮助到一些人,也希望大家能够指正一些问题。请大家多多留言发表意见。
(开源中国http://my.oschina.net/JHissuperman/blog/745064)