IOS开发之瀑布流照片墙实现
来源:互联网 发布:windows纸牌怎么玩 编辑:程序博客网 时间:2024/04/27 22:53
想必大家已经对互联网传统的照片布局方式司空见惯了,这种行列分明的布局虽然对用户来说简洁明了,但是长久的使用难免会产生审美疲劳。现在网上流行一种叫做“瀑布流”的照片布局样式,这种行与列参差不齐的状态着实给用户眼前一亮的感觉,这种不规则的方式也吸引着我,现在我们就来一起实现它吧 :)
首先我们来看一下这种样式布局是如何体现的,请看示意图:
别看这种界面的布局好像毫无规律,其实它的排列还是很有规则的。我们拿手机屏幕举个例子,我们把屏幕等宽的划分为几个区域,由于手机屏幕比较小,我们就按照网上
最普遍的把屏幕分为等宽的三列,然后将图片加载在每一列中,在加入到列之前,要先判断哪一列的高度最低,然后把图片加到列高度最低的那列中。听起来是不是有些拗口,说简单点就是“哪列高度低就加哪”,这样听我一说是不是觉得原理其实很简单嘛!
下面我们就来用程序去实现他吧!首先看一张效果图。
新建一个Xcode工程,名字随便取吧(或者叫Album都可以),然后新建三个类,分别是:MainViewController用于控制主界面, MyScrollView继承自UIScrollView用于控制界面滚动,以及图片的管理类ImageLoader。
我们先来看一下ImageLoader类,它是一个图片的处理类,负责对取到的图片进行等比例压缩,以至于加载到UImageView中时不会失真,代码如下:
#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的代码片段:
#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(2 * 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,代码如下:
#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来获取点击图片的名字,然后将名字传递给该类,完成对相应图片的显示,当然这里也要做对图片的压缩处理,使它显示的时候不失真。(由于本人有点懒,这个类的界面美观什么的就懒得调了,多多包涵)示意图如下:
以上就是这个例子的大部分代码了,如果要下载完整工程的话,请到我的上传中下载。
现在看一下整个效果;
7 0
- IOS开发之瀑布流照片墙实现
- IOS开发之瀑布流照片墙实现
- IOS开发之瀑布流照片墙实现
- 瀑布流照片墙实现
- iOS开发学习之实现瀑布流
- 3、IOS开发之瀑布流实现
- 瀑布流照片实现
- Android瀑布流照片墙实现
- Android瀑布流照片墙实现
- iOS开发之瀑布流
- iOS开发之瀑布流
- JQuery实现照片瀑布流
- iOS开发之瀑布流的实现(UICollectionView与UIScrollView)
- IOS开发之瀑布流的实现(UICollectionView与UIScrollView)
- LruCache之Android瀑布流照片墙实现,体验不规则排列的美感
- android 瀑布流照片墙
- iOS开发-进阶:瀑布流基本实现
- iOS开发-UICollectionView实现瀑布流
- 初识Comet技术
- Navicat中查询的用法
- 密码加密处理
- 自制N32926U1DN开发板,搞定无线wifi接入, 并且可以通过有线上网。相当于一个路由器了 ^_^
- 爱加密宣战山寨App!安卓应用安全加密!!!
- IOS开发之瀑布流照片墙实现
- Android系统常用隐藏命令大全
- CUIT CTF WriteUp-最简单的题目
- ios--截屏--UIGraphicsBeginImageContext(CGSize)
- 滕旭死于微信也
- xx_ops,callback
- Linux AIO机制
- 【文件管理】从路径名到目标节点
- 电感电容 1