欢迎使用CSDN-markdown编辑器

来源:互联网 发布:mac版flashplayer 编辑:程序博客网 时间:2024/04/30 02:14

想必大家已经对互联网传统的照片布局方式司空见惯了,这种行列分明的布局虽然对用户来说简洁明了,但是长久的使用难免会产生审美疲劳。现在网上流行一种叫做“瀑布流”的照片布局样式,这种行与列参差不齐的状态着实给用户眼前一亮的感觉,这种不规则的方式也吸引着我,现在我们就来一起实现它吧 :)
首先我们来看一下这种样式布局是如何体现的,请看示意图:

别看这种界面的布局好像毫无规律,其实它的排列还是很有规则的。我们拿手机屏幕举个例子,我们把屏幕等宽的划分为几个区域,由于手机屏幕比较小,我们就按照网上
最普遍的把屏幕分为等宽的三列,然后将图片加载在每一列中,在加入到列之前,要先判断哪一列的高度最低,然后把图片加到列高度最低的那列中。听起来是不是有些拗口,说简单点就是“哪列高度低就加哪”,这样听我一说是不是觉得原理其实很简单嘛!
下面我们就来用程序去实现他吧!首先看一张效果图。

新建一个Xcode工程,名字随便取吧(或者叫Album都可以),然后新建三个类,分别是:MainViewController用于控制主界面, MyScrollView继承自UIScrollView用于控制界面滚动,以及图片的管理类ImageLoader。
我们先来看一下ImageLoader类,它是一个图片的处理类,负责对取到的图片进行等比例压缩,以至于加载到UImageView中时不会失真,代码如下:
[objc] view plaincopy在CODE上查看代码片派生到我的代码片

import “ImageLoader.h”

@interface ImageLoader ()

@end

@implementation ImageLoader
@synthesize imagesArray = _imagesArray;

  • (ImageLoader *)shareInstance{
    static ImageLoader *loader = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
    loader = [[ImageLoader alloc] init];
    });
    return loader;
    }

  • (id)initWithNibName:(NSString )nibNameOrNil bundle:(NSBundle )nibBundleOrNil
    {
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
    // Custom initialization
    }
    return self;
    }

  • (void)viewDidLoad
    {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    }

/加载图片/
- (void)loadImage:(NSMutableArray *)array{
self.imagesArray = array;
}

/*
压缩图片,根据图片的大小按比例压缩
width:每列试图的宽度
返回一个UIImageView
*/
- (UIImageView )compressImage:(float)width imageName:(NSString )name{
UIImageView *imgView = [[UIImageView alloc] init];
imgView.image = [UIImage imageNamed:name];

float orgi_width = [imgView image].size.width;  float orgi_height = [imgView image].size.height;  //按照每列的宽度,以及图片的宽高来按比例压缩  float new_width = width - 5;  float new_height = (width * orgi_height)/orgi_width;  //重置imageView的尺寸  [imgView setFrame:CGRectMake(0, 0, new_width, new_height)];  return imgView;  

}

  • (void)didReceiveMemoryWarning
    {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
    }

  • (void)dealloc{
    [self.imagesArray release];
    [super dealloc];
    }

@end
这里将ImageLoader类设置成了单例,以便于在MainViewContrioller和MyScrollView中获取。
下面是MyScrollView的代码片段:
[objc] view plaincopy在CODE上查看代码片派生到我的代码片

import “MyScrollView.h”

define COORDINATE_X_LEFT 5

define COORDINATE_X_MIDDLE MY_WIDTH/3 + 5

define COORDINATE_X_RIGHT MY_WIDTH/3 * 2 + 5

define PAGESIZE 21

@interface MyScrollView ()

@end

@implementation MyScrollView
@synthesize mainScroll = _mainScroll;
@synthesize isOnce = _isOnce;
@synthesize imagesName = _imagesName;
@synthesize loadedImageDic = _loadedImageDic;
@synthesize leftColumHeight = _leftColumHeight;
@synthesize midColumHeight = _midColumHeight;
@synthesize rightColumHeight = _rightColumHeight;
@synthesize loadedImageArray = _loadedImageArray;
@synthesize imgTag = _imgTag;
@synthesize imgTagDic = _imgTagDic;
@synthesize imageLoad = _imageLoad;
@synthesize page = _page;

  • (MyScrollView *)shareInstance{
    static MyScrollView *instance;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
    instance = [[self alloc] initWithFrame:CGRectMake(0, 0, MY_WIDTH, MY_HEIGHT)];
    });

    return instance;
    }

/*
初始化scrollView的委托以及背景颜色,不显示它的水平,垂直显示条
*/
- (id)initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
if(self){
self.delegate = self;
self.backgroundColor = [UIColor blackColor];
self.pagingEnabled = NO;
self.showsHorizontalScrollIndicator = NO;
self.showsVerticalScrollIndicator = NO;

    self.isOnce = YES;      self.loadedImageDic = [[NSMutableDictionary alloc] init];      self.loadedImageArray = [[NSMutableArray alloc] init];      self.imgTagDic = [[NSMutableDictionary alloc] init];      //初始化列的高度      self.leftColumHeight = 3.0f;      self.midColumHeight = 3.0f;      self.rightColumHeight = 3.0f;      self.imgTag = 10086;      self.page = 1;      [self initWithPhotoBox];  }  return self;  

}

/*
将scrollView界面分为大小相等的3个部分,每个部分为一个UIView, 并设置每一个UIView的tag
*/
- (void)initWithPhotoBox{
UIView *leftView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, MY_WIDTH/3, self.frame.size.height)];
UIView *middleView = [[UIView alloc] initWithFrame:CGRectMake(leftView.frame.origin.x + MY_WIDTH/3, 0, MY_WIDTH/3,
self.frame.size.height)];
UIView *rightView = [[UIView alloc] initWithFrame:CGRectMake(middleView.frame.origin.x + MY_WIDTH/3, 0, MY_WIDTH/3,
self.frame.size.height)];
//设置三个部分的tag
leftView.tag = 100;
middleView.tag = 101;
rightView.tag = 102;

//设置背景颜色  [leftView setBackgroundColor:[UIColor clearColor]];  [middleView setBackgroundColor:[UIColor clearColor]];  [rightView setBackgroundColor:[UIColor clearColor]];  [self addSubview:leftView];  [self addSubview:middleView];  [self addSubview:rightView];  //第一次加载图片  self.imageLoad = [ImageLoader shareInstance];  for(int i = 0; i < PAGESIZE; i++){      NSString *imageName = [self.imageLoad.imagesArray objectAtIndex:i];      UIImageView *imgView = [self.imageLoad compressImage:MY_WIDTH/3 imageName:imageName];      [self addImage:imgView name:imageName];      [self checkImageIsVisible];  }  //第一页  self.page = 1;  [self adjustContentSize:NO];  

}

/调整scrollview/
- (void)adjustContentSize:(BOOL)isEnd{
UIView *leftView = [self viewWithTag:100];
UIView *middleView = [self viewWithTag:101];
UIView *rightView = [self viewWithTag:102];

if(_leftColumHeight >= _midColumHeight && _leftColumHeight >= _rightColumHeight){      self.contentSize = leftView.frame.size;  }else{      if(_midColumHeight >= _rightColumHeight){          self.contentSize = middleView.frame.size;      }else{          self.contentSize = rightView.frame.size;      }  }  

}

/*
得到最短列的高度
*/
- (float)getTheShortColum{
if(_leftColumHeight <= _midColumHeight && _leftColumHeight <= _rightColumHeight){
return _leftColumHeight;
}else{
if(_midColumHeight <= _rightColumHeight){
return _midColumHeight;
}else{
return _rightColumHeight;
}
}
}

/*
添加一张图片
规则:根据每一列的高度来决定,优先加载列高度最短的那列
重新设置图片的x,y坐标
imageView:图片视图
imageName:图片名
*/
- (void)addImage:(UIImageView )imageView name:(NSString )imageName{
//图片是否加载
if([self.loadedImageDic objectForKey:imageName]){
return;
}

//若图片还未加载则保存  [self.loadedImageDic setObject:imageView forKey:imageName];  [self.loadedImageArray addObject:imageView];  [self imageTagWithAction:imageView name:imageName];  float width = imageView.frame.size.width;  float height = imageView.frame.size.height;  //判断哪一列的高度最低  if(_leftColumHeight <= _midColumHeight && _leftColumHeight <= _rightColumHeight){      UIView *leftView = [self viewWithTag:100];      [leftView addSubview:imageView];      //重新设置坐标      [imageView setFrame:CGRectMake(2, _leftColumHeight, width, height)];      _leftColumHeight = _leftColumHeight + height + 3;      [leftView setFrame:CGRectMake(0, 0, MY_WIDTH/3, _leftColumHeight)];  }else{      if(_midColumHeight <= _rightColumHeight){          UIView *middleView = [self viewWithTag:101];          [middleView addSubview:imageView];          [imageView setFrame:CGRectMake(2, _midColumHeight, width, height)];          _midColumHeight = _midColumHeight + height + 3;          [middleView setFrame:CGRectMake(MY_WIDTH/3, 0, MY_WIDTH/3, _midColumHeight)];      }else{          UIView *rightView = [self viewWithTag:102];          [rightView addSubview:imageView];          [imageView setFrame:CGRectMake(2, _rightColumHeight, width, height)];          _rightColumHeight = _rightColumHeight + height + 3;          [rightView setFrame:CGRectMake(22 * MY_WIDTH/3, 0, MY_WIDTH/3, _rightColumHeight)];      }  }  

}

/*
将图片tag保存,以及为UIImageView添加事件响应
*/
- (void)imageTagWithAction:(UIImageView )imageView name:(NSString )imageName{
//将要显示图片的tag保存
imageView.tag = self.imgTag;
[self.imgTagDic setObject:imageName forKey:[NSString stringWithFormat:@”%d”, imageView.tag]];
self.imgTag++;

//图片添加事件响应  UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(imageClickWithTag:)];  tapRecognizer.delegate = self;  imageView.userInteractionEnabled = YES;  [imageView addGestureRecognizer:tapRecognizer];  [tapRecognizer release];  

}

/*
//若三列中最短列距离底部高度超过30像素,则请求加载新的图片
*/
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
//可视检查
[self checkImageIsVisible];
if((self.contentOffset.y + self.frame.size.height) - [self getTheShortColum] > 30){
[self pullRefreshImages];
}
}

/*
上拉时加载新的图片
*/
- (void)pullRefreshImages{
int index = self.page *PAGESIZE;
int imgNum = [self.imageLoad.imagesArray count];

if(index >= imgNum){      //图片加载完毕      [self adjustContentSize:YES];      [MyToast showWithText:@"没有更多图片"];  }else{      if((imgNum - self.page*PAGESIZE) > PAGESIZE){          for (int i = index; i < PAGESIZE; i++) {              NSString *imageName = [self.imageLoad.imagesArray objectAtIndex:i];              UIImageView *imgView = [self.imageLoad compressImage:MY_WIDTH/3 imageName:imageName];              [self addImage:imgView name:imageName];              [self checkImageIsVisible];          }      }else{          for (int i = index; i < imgNum; i++) {              NSString *imageName = [self.imageLoad.imagesArray objectAtIndex:i];              UIImageView *imgView = [self.imageLoad compressImage:MY_WIDTH/3 imageName:imageName];              [self addImage:imgView name:imageName];              [self checkImageIsVisible];          }      }      self.page++;  }  [self adjustContentSize:NO];  

}

/*
检查图片是否可见,如果不在可见视线内,则把图片替换为nil
*/
- (void)checkImageIsVisible{
for (int i = 0; i < [self.loadedImageArray count]; i++) {
UIImageView *imgView = [self.loadedImageArray objectAtIndex:i];

    if((self.contentOffset.y - imgView.frame.origin.y) > imgView.frame.size.height ||         imgView.frame.origin.y > (self.frame.size.height + self.contentOffset.y)){          //不显示图片          imgView.image = nil;      }else{          //重新根据tag值显示图片          NSString *imageName = [self.imgTagDic objectForKey:[NSString stringWithFormat:@"%d", imgView.tag]];          if((NSNull *)imageName == [NSNull null]){              return;          }          UIImageView *view = [self.imageLoad compressImage:MY_WIDTH/3 imageName:imageName];          imgView.image = view.image;      }  }  

}

//点击图片事件响应
- (void)imageClickWithTag:(UITapGestureRecognizer *)sender{
UIImageView view = (UIImageView )sender.view;
NSString *imageName = [self.imgTagDic objectForKey:[NSString stringWithFormat:@”%d”, view.tag]];
NSLog(@”%@”, imageName);

PhotoViewController *photoView = [[PhotoViewController alloc] init];  photoView.imageName = imageName;  [self addSubview:photoView.view];  

}

  • (void)dealloc{
    [self.imagesName release];
    [self.imgTagDic release];
    [self.loadedImageArray release];
    [super dealloc];
    }

@end
在这个类中,我将三列等宽的UIView加入到ScrollView中,每次加入一张图片的时候都会去判断一下哪一列的高度最低。为了避免手机被图片的占用内存过高导致程序
崩溃的问题,我还作了一个照片可见性的逻辑判断,具体函数名为checkImageIsVisible,当照片不可见时,将imageView中的image设为nil,一旦照片出现了就根据照片的tag
获取到照片名重新设置image。
最后,当照片加载出来以后当然不能少了点击查看相册的功能啊!于是新建一个UIViewController类取名为:PhotoViewController,代码如下:
[objc] view plaincopy在CODE上查看代码片派生到我的代码片

import “PhotoViewController.h”

@interface PhotoViewController ()

@end

@implementation PhotoViewController
@synthesize headView = _headView;
@synthesize mainView = _mainView;

  • (id)initWithNibName:(NSString )nibNameOrNil bundle:(NSBundle )nibBundleOrNil
    {
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
    // Custom initialization
    }
    return self;
    }

  • (void)viewDidLoad
    {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    [self.view setFrame:CGRectMake(0, 0, MY_WIDTH, MY_HEIGHT)];
    [self.view setBackgroundColor:[UIColor blackColor]];

    self.headView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, MY_WIDTH, 50)];
    UIButton *cancelBtn = [[UIButton alloc] initWithFrame:CGRectMake(0, 20, 40, 30)];
    [cancelBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
    [cancelBtn setTitle:@”取消” forState:UIControlStateNormal];
    [self.headView addSubview:cancelBtn];
    [cancelBtn addTarget:self action:@selector(closePhotoView) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:self.headView];

    self.mainView = [[UIView alloc] initWithFrame:CGRectMake(0, 80, MY_WIDTH, MY_HEIGHT)];
    [self.view addSubview:self.mainView];
    }

  • (void)viewWillAppear:(BOOL)animated{
    UIImageView *imageV = [self compressImage:MY_WIDTH imageName:_imageName];
    [self.mainView addSubview:imageV];
    }

  • (UIImageView )compressImage:(float)width imageName:(NSString )name{
    UIImageView *imgView = [[UIImageView alloc] init];
    imgView.image = [UIImage imageNamed:name];

    float orgi_width = [imgView image].size.width;
    float orgi_height = [imgView image].size.height;

    //按照每列的宽度,以及图片的宽高来按比例压缩
    float new_width = width - 5;
    float new_height = (width * orgi_height)/orgi_width;

    //重置imageView的尺寸
    [imgView setFrame:CGRectMake(0, 0, new_width, new_height)];

    return imgView;
    }

  • (void)didReceiveMemoryWarning
    {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
    }

//关闭
- (void)closePhotoView{

[self.view removeFromSuperview];  

}

  • (void)dealloc{
    [self.headView release];
    [self.mainView release];

    [super dealloc];
    }

@end
这个类主要是用于显示大图片所用,用户点击小图片后,程序根据图片的tag来获取点击图片的名字,然后将名字传递给该类,完成对相应图片的显示,当然这里也要做对图片的压缩处理,使它显示的时候不失真。(由于本人有点懒,这个类的界面美观什么的就懒得调了,多多包涵)示意图如下:

以上就是这个例子的大部分代码了,如果要下载完整工程的话,请到我的上传中下载。
现在看一下整个效果;
http://img.blog.csdn.net/20140522175128953?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2hlbmppZTEyMzQ1Njc4/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast

0 0
原创粉丝点击