前言:
很多社交软件,都需要用户上传头像等很多照片,因此上传照片时的交互体验尤为重要,这里就简述一下探探照片拖拽排序的实现方法。
思路:
这里装载图片的控件我们使用UIButton
给每个图片控件UIButton添加滑动手势,在拖拽的过程中通过“碰撞检测”实现两个控件坐标CGPoint和CGRect的交换。
核心代码:
#pragma mark - 拖拽事件
-(void)pan:(UIPanGestureRecognizer*)recognizer{
Button *recognizerView = (Button *)recognizer.view;
//获取移动偏移量
CGPoint recognizerPoint = [recognizer translationInView:self.view];
if (recognizer.state == UIGestureRecognizerStateBegan) {
if (recognizerView.selected == NO) {
}else{
//开始的时候改变拖动view的外观(放大,改变颜色等)
[UIView animateWithDuration:0.2 animations:^{
if (recognizerView.tag == 100) {
recognizerView.transform = CGAffineTransformMakeScale(0.35, 0.35);
}else{
recognizerView.transform = CGAffineTransformMakeScale(0.75, 0.75);
}
recognizerView.alpha = 0.7;
}];
//把拖动view放到最上层
[self.view bringSubviewToFront:recognizerView];
//valuePoint保存最新的移动位置
valuePoint = recognizerView.center;
}
CGFloat btnWidth = (Screen_Width - autolyout(9)) / 4;
CGFloat headericonheight = Screen_Width - btnWidth - autolyout(3);
if (recognizerView.tag == 100) {
valueFrame =CGRectMake(0, 0, headericonheight, headericonheight);
}else{
valueFrame = CGRectMake(0, 0, btnWidth, btnWidth);
}
}else if(recognizer.state == UIGestureRecognizerStateChanged){
//更新pan.view的center
CGFloat x = recognizerView.center.x + recognizerPoint.x;
CGFloat y = recognizerView.center.y + recognizerPoint.y;
if (recognizerView.selected == YES) {
recognizerView.center = CGPointMake(x, y);
}
//因为拖动会持续执行 所以每次结束都要清空
[recognizer setTranslation:CGPointZero inView:self.view];
for (Button * bt in contain.subviews) {
//判断是否移动到另一个view区域
//CGRectContainsPoint(rect,point)
//判断某个点是否被某个frame包含
if (CGRectContainsPoint(bt.frame, recognizerView.center)&&bt!=recognizerView){
//开始位置
NSInteger fromIndex = recognizerView.tag - KBase_tag;
//需要移动到的位置
NSInteger toIndex = bt.tag - KBase_tag;
//往后移动
if ((toIndex-fromIndex)>0) {
//从开始位置移动到结束位置
//把移动view的下一个view移动到记录的view的位置(valuePoint),并把下一view的位置记为新的nextPoint,并把view的tag值-1,依次类推
if (bt.selected == NO||recognizerView.selected == NO) {
}else{
[UIView animateWithDuration:0.2 animations:^{
for (NSInteger i = fromIndex+1; i<=toIndex; i++) {
Button * nextBt = (Button*)[self.view viewWithTag:KBase_tag+i];
nextFrame = nextBt.frame;
nextPoint = nextBt.center;
nextBt.frame = valueFrame;
nextBt.center = valuePoint;
valueFrame = nextFrame;
valuePoint = nextPoint;
nextBt.tag--;
}
recognizerView.tag = KBase_tag + toIndex;
}];
}
}
//往前移动
else{
//从开始位置移动到结束位置
//把移动view的上一个view移动到记录的view的位置(valuePoint),并把上一view的位置记为新的nextPoint,并把view的tag值+1,依次类推
if (bt.selected == NO||recognizerView.selected == NO) {
}else{
[UIView animateWithDuration:0.2 animations:^{
for (NSInteger i = fromIndex-1; i>=toIndex; i--) {
Button * nextBt = (Button*)[self.view viewWithTag:KBase_tag+i];
nextFrame = nextBt.frame;
nextPoint = nextBt.center;
nextBt.frame = valueFrame;
nextBt.center = valuePoint;
valueFrame = nextFrame;
valuePoint = nextPoint;
nextBt.tag++;
}
recognizerView.tag = KBase_tag + toIndex;
}];
}
}
}
}
}else if(recognizer.state == UIGestureRecognizerStateEnded){
if (recognizerView.selected == YES) {
//结束时候恢复view的外观(放大,改变颜色等)
[UIView animateWithDuration:0.2 animations:^{
recognizerView.transform = CGAffineTransformMakeScale(1.0, 1.0);
recognizerView.alpha = 1;
recognizerView.frame = valueFrame;
recognizerView.center = valuePoint;
[self photosDataRanking];
}];
}
}
}
这样就完成了控件之间的拖拽后的互换,但是新的问题又来了,如果涉及到网络上传,空间上的图片肯定是放到一个数组里面,如何在控件互换的时候数组里面的图片索引页跟着互换呢?如果涉及到删除空间上的图片并且依次重新排序怎么实现呢?
有些新入行的同学一定会这样想,给每个UIButton控件编号,控件交换的过程中,通过编号联系到数组索引,同步数组中图片也交换,删除某个编号控件上的图片,数组就删除哪一个索引的图片。
但是这样数组的联动,未免太过于复杂,而且代码似乎并不好看,这里给大家分享下我的思路,不喜勿喷。
第一步:
自定义一个UIButton 带有UIImage属性
#import@interface Button : UIButton
@property (nonatomic,strong)UIImage *image;
@end
第二步:
每一次拖拽互换的时候调用排序方法
#pragma mark - 图片数据重新排列
-(void)photosDataRanking{
[photos removeAllObjects];
for (int i = 0; i < PhotosNum; i ++) {
Button *btn = [self.view viewWithTag:100 + i];
[photos addObject:btn.image];
}
}
完成这两步,图片控件拖拽同时图片数组的重新排序的需求就完成了。
还差最后一步就是删除时候 图片数组的重新排序:
因为我写代码是考虑到本身控件有占位图片的,所以单独又写了一个方法,如果没有占位图片,可以在上面排序的方法中 实现逻辑
//删除照片
[photos removeObject:sender.image];
//重新排序
[self photosRanking];
#pragma mark - 图片UI重新排列(删除照片 添加照片的时候调用)
-(void)photosRanking{
for (int i = 0; i < 8; i ++) {
Button *btn = [self.view viewWithTag:100 + i];
if (i < photos.count) {//有照片的 按钮状态变成有照片
btn.image = photos[i];
[btn setImage:photos[i] forState:UIControlStateNormal];
btn.selected = YES;
}else{//没照片 按钮状态变成没照片
if (i == 0) {
btn.selected = NO;
[btn setImage:[UIImage imageNamed:@"headerUpdata"] forState:UIControlStateNormal];
}else{
btn.selected = NO;
[btn setImage:[UIImage imageNamed:@"photoAdd"] forState:UIControlStateNormal];
}
}
}
}
总结
我在github上面上传了demo,有需求的同学可以自己下载研究,代码简单,清晰易懂。----》》 JimmyPicEditor