iOS基础 - 瀑布流
一、瀑布流简介
瀑布流,又称瀑布流式布局。是比较流行的一种网站页面布局,视觉表现为参差不齐的多栏布局,随着页面滚动条向下滚动,这种布局还会不断加载数据块并附加至当前尾部。最早采用此布局的网站是Pinterest,逐渐在国内流行开来。国内大多数清新站基本为这类风格
二、瀑布流特点
l 琳琅满目:整版以图片为主,大小不一的图片按照一定的规律排列
l 唯美:图片的风格以唯美的图片为主
l 操作简单:在浏览网站的时候只需要轻轻滑动一下鼠标滚轮,一切的美妙的图片精彩便可呈现在你面前
三、瀑布流应用
瀑布流对于图片的展现,是高效而具有吸引力的,用户一眼扫过的快速阅读模式可以在短时间内获得更多的信息量,而瀑布流里懒加载模式又避免了用户鼠标点击的翻页操作
瀑布流的主要特性便是错落有致,定宽而不定高的设计让页面区别于传统的矩阵式图片布局模式,巧妙的利用视觉层级,视线的任意流动又缓解了视觉疲劳
四、使用瀑布流的网站
l 电商导购,如想去网、蘑菇街和美丽说、好享说,依托于淘宝平台
l 兴趣图谱分享,如知美、花瓣等
l 细分垂直领域,如针对吃货的零食控、针对家居行业的他部落等
五、瀑布流的优缺点
l 优点
有效的降低了界面复杂度,节省了空间:我们不再需要臃肿复杂的页码导航链接或按钮了
对触屏设备来说,交互方式更符合直觉:在移动应用的交互环境当中,通过向上滑动进行滚屏的操作已经成为最基本的用户习惯,而且所需要的操作精准程度远远低于点击链接或按钮
更高的参与度:以上两点所带来的交互便捷性可以使用户将注意力更多的集中在内容而不是操作上,从而让他们更乐于沉浸在探索与浏览当中
l 缺点
有限的用例:无限滚动的方式只适用于某些特定类型产品当中一部分特定类型的内容
额外的复杂度
l SEO:集中在一页当中动态加载数据,不利于SEO,对于网站而言,存在一定的风险
l 页面的数量:如果网站需要通过更多的内容页面展示更多的相关信息(包括广告)是很重要的策略,那么单页无限滚动的方式就不适用了
六、实现瀑布流的思路
使用多个UITableView,控制它们同时滚动,在复杂的用户操作下,会出现滚动不同步的情况;如果需要支持设备的多个方向,不利于增加图片列数及方向切换的动画效果,使用一个UIScrollView,参考UITableView的实现方式,开发一个符合需求的可重用的控件
七、瀑布流数据处理思路
每次通过一个GET方法加载一个JSON数据,数据中包含一组数据信息:图像URL、图像标题等
异步加载JSON数据包中的图像,从左至右,从上至下依次显示
滚动至数据末尾时,加载新的数据
数据加载后,从当前最末一张图像开始追加新的图像
滚动至顶部时,下拉刷新新的数据
新数据加载后,重新填充当前视图中的内容
八、开发步骤
使用沙箱数据:自定义UIScrollView,使用沙箱中的图像模拟瀑布流的实现
集成网络:通过网络加载并处理数据
九、自定义瀑布流控件
自定义UIScrollView(WaterFlowView),模拟UITableView
自定义UIView(WaterFlowViewCell),模拟UITableViewCell
单独负责图像内容及文本标签的显示
使用可重用标示符处理视图的重用
自定义UIViewController(WaterFlowViewController),模拟UITableViewController
处理自定义UIScrollView的数据源及代理方法
十、WaterFlowViewCell的定义
属性
// 可重用标示符
@property (strong, nonatomic) NSString *reuseIdentifier;
// 被选中标记
@property (assign, nonatomic) BOOL selected;
// 图像视图
@property (weak, nonatomic) UIImageView *imageView;
// 文本标签
@property (weak, nonatomic) UILabel *textLabel;
方法:
// 使用可重用标示符实例化视图
- (id)initWithResueIdentifier:(NSString *)reusedIdentifier;
十一、WaterFlowViewCell的实现
利用控件的getter方法实现控件懒加载
重写layoutSubviews方法,调整控件布局
注意:此处不需要调用父类的layoutSubViews方法
十二、WaterFlowView的定义数据源和代理
l 数据源
单元格数量
l 单元格
视图的列数(默认为1,可选方法)
l 代理
指定单元格的高度
单元格被选中
十三、数据源协议
@protocol WaterFlowViewDataSource <NSObject>
// 单元格数量
- (NSInteger)waterFlowViewNumberOfCells:(WaterFlowView *)waterFlowView;
// 单元格
- (WaterFlowViewCell *)waterFlowView:(WaterFlowView *)waterFlowView cellAtIndexPath:(NSIndexPath *)indexPath;
@optional
// 视图的列数(可选,默认1列)
- (NSInteger)waterFlowViewNumberOfColumns:(WaterFlowView *)waterFlowView;
@end
十四、代理协议
@protocol WaterFlowViewDelegate <UIScrollViewDelegate>
// 指定单元格的高度
- (CGFloat)waterFlowView:(WaterFlowView *)waterFlowView heightForCellAtIndexPath:(NSIndexPath *)indexPath;
// 单元格被选中
- (void)waterFlowView:(WaterFlowView *)waterFlowView didSelectedCellAtIndexPath:(NSIndexPath *)indexPath;
@end
十五、WaterFlowViewController中的实例化视图
- (void)loadView
{
_waterFlowView = [[WaterFlowView alloc]initWithFrame:CGRectZero];
[_waterFlowView setDataSource:self];
[_waterFlowView setDelegate:self];
// 根据父视图大小调整自身大小
[_waterFlowView setAutoresizingMask:UIViewAutoresizingFlexibleWidth
| UIViewAutoresizingFlexibleHeight];
self.view = _waterFlowView;
}
十六、编写resetView方法实现瀑布流视图的布局
1. 首先初始化根据数据行数indexPaths数组
2. 布局界面
1) 计算每列宽度
2) 使用一个数组,记录每列的当前Y值
3) 遍历self.indexPaths生成WaterFlowCellView并计算位置
4) 设置scrollView的contentSize
十七、修改WaterFlowViewController增加方向支持
#pragma mark 设备旋转结束
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
[self.waterFlowView reloadData];
}
#pragma mark - 列数
- (NSInteger)numberOfColumnsInWaterFlowView:(WaterFlowView *)waterFlowView
{
// 根据设备方向设定不同的瀑布流列数
if ([UIDevice currentDevice].orientation == UIDeviceOrientationLandscapeLeft || [UIDevice currentDevice].orientation == UIDeviceOrientationLandscapeRight) {
self.numberOfColumns = 4;
} else {
self.numberOfColumns = 3;
}
return self.numberOfColumns;
}
十八、引入缓存策略,利用数据字典记录单元格的位置
#pragma mark - 缓存数据
// 单元格位置数组
@property (strong, nonatomic) NSMutableArray *cellFramesArray;
// 单元格缓存集合
@property (strong, nonatomic) NSMutableSet *reusableCellSet;
// 正在显示单元格字典
@property (strong, nonatomic) NSMutableDictionary *screenCellsDict;
编写方法统一生成缓存数据
// 建立缓存数据
[self generateCacheData];
十九、生成缓存数据
// 1) 获取当前列数
// 2) 建立列索引数组
// 3) 建立列单元格位置数组
// 4) 建立整体索引数组
// 5. 视图缓存字典
// 6. 正在显示的单元格集合
二十、修改resetView方法,仅记录各个视图位置
// 计算出下一列的数值
NSInteger nextCol = (col + 1) % _numberOfColumns;
// 判断当前的行高是否超过下一列的行高
if (currentY[col] > currentY[nextCol]) {
col = nextCol;
}
// 在单元格数组中记录所有单元格的位置(位置&大小)
[self.cellFramesArray addObject:[NSValue valueWithCGRect:CGRectMake(x, y, colW, h)]];
二十一、判断视图是否在屏幕范围之内
#pragma mark 判断视图是否在屏幕范围之内
- (BOOL)isInScreenWithFrame:(CGRect)frame
{
return (frame.origin.y - self.contentOffset.y) < self.bounds.size.height &&
(frame.origin.y + frame.size.height - self.contentOffset.y) > 0;
}
二十二、编写dequeueReusableCellWithReuseIdentifier
#pragma mark 使用可重用标示符获取单元格对象
- (WaterFlowCellView *)dequeueReusableCellWithReuseIdentifier:(NSString *)reuseIdentifier
{
// 需要从一个集合获取可重用单元格
// 从集合中取出任意对象
WaterFlowCellView *cell = [self.reusableCellSet anyObject];
if (cell != nil) {
// 从集合中删除视图
[self.reusableCellSet removeObject:cell];
}
return cell;
}
二十三、手势处理
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView:self];
// 遍历可见视图集合,查找被点击的单元格
NSArray *array = [self.displayCellDict allKeys];
for (NSIndexPath *indexPath in array) {
WaterFlowCellView *view = self.displayCellDict[indexPath];
if (CGRectContainsPoint(view.frame, location)) {
[self.delegate waterFlowView:self didSelectRowAtIndexPath:indexPath];
}
}
}
iOS基础 - 瀑布流的更多相关文章
- ios图片瀑布流代码
ios瀑布流,实现简单的瀑布流视图布局,可以显示网络图片,下拉刷新,上拉加载更多. 下载:http://www.huiyi8.com/sc/9087.html
- iOS横向瀑布流的封装
前段时间, 做一个羡慕, 需要使用到瀑布流! 说道瀑布流, 或许大家都不陌生, 瀑布流的实现也有很多种! 从scrollView 到 tableView 书写的瀑布流, 然后再到2012年iOS6 苹 ...
- iOS - UICollectionView 瀑布流 添加表头视图的坑
UICollectionView 瀑布流 添加表头视图的坑 首先是,需求加了个头视图在顶部,在collectionView中的头视图跟TableView的不一样,TableView的表头只要设置tab ...
- ios开发瀑布流框架的应用
一:瀑布流框架的应用:将封装好的瀑布流框架导入,遵守协议 二:代码: #import "HMShopsViewController.h" #import "HMShopC ...
- ios开发瀑布流框架的封装
一:瀑布流框架封装的实现思路:此瀑布流框架的封装仿照tableView的底层实现,1:每个cell的frame的设置都是找出每列的最大y值,比较每列的最大y值,将下一个cell放在最大y值最小的那一列 ...
- iOS开发瀑布流的实现
//自定义布局,继承于UICollectionViewLayout #import <UIKit/UIKit.h> @class WaterFlowLayout; @protocol W ...
- iOS开发之窥探UICollectionViewController(四) --一款功能强大的自定义瀑布流
在上一篇博客中<iOS开发之窥探UICollectionViewController(三) --使用UICollectionView自定义瀑布流>,自定义瀑布流的列数,Cell的外边距,C ...
- iOS开发之窥探UICollectionViewController(三) --使用UICollectionView自定义瀑布流
上篇博客的实例是自带的UICollectionViewDelegateFlowLayout布局基础上来做的Demo, 详情请看<iOS开发之窥探UICollectionViewControlle ...
- iOS开发笔记15:地图坐标转换那些事、block引用循环/weak–strong dance、UICollectionviewLayout及瀑布流、图层混合
1.地图坐标转换那些事 (1)投影坐标系与地理坐标系 地理坐标系使用三维球面来定义地球上的位置,单位即经纬度.但经纬度无法精确测量距离戒面积,也难以在平面地图戒计算机屏幕上显示数据.通过投影的方式可以 ...
随机推荐
- 探寻宝藏(双向DP)
题目描述 传说HMH大沙漠中有一个M*N迷宫,里面藏有许多宝物.某天,Dr.Kong找到了迷宫的地图,他发现迷宫内处处有宝物,最珍贵的宝物就藏在右下角,迷宫的进出口在左上角.当然,迷宫中的通路不是平坦 ...
- Mule ESB-Content-Based Routing Tutorial(2)
承接 Mule ESB-Content-Based Routing Tutorial(1) 五.执行应用程序 完毕创建,配置.并保存你的新的应用程序,您就能够在嵌入Mule的server上执行(包含 ...
- SAE+Java+jetty
SAE的java执行环境jetty如servlet该容器,和开放几乎完全访问.有效支持各种jar包.但对于jdk的要件的版本号是非常严格格,这里的版本号是jdk1.6 SAE利用上传war该方式配置j ...
- 乘法逆元...Orz
最近打的几场比赛,都出现了有关逆元的题目,今天就整理了一下... 求乘法逆元的几种方法:http://www.cnblogs.com/james47/p/3871782.html 博文转载链接:htt ...
- 初学git && 使用总结
参考文章:http://www.ruanyifeng.com/blog/2014/06/git_remote.html git基础操作 http://www.ruanyifeng.com/blog ...
- jquery选择器基础知识
$("#myELement") 选择id值等于myElement的元素,id值不能重复在文档中只能有一个id值是myElement所以得到的是唯一的元素 $("di ...
- 处理器(CPU)调度问题
因为处理器是最重要的计算机资源,提高利用率并提高系统性能的处理器(吞吐量.响应时间).于处理机调度性能的好坏,因而,处理机调度便成为操作系统设计的中心问题之中的一个. 一.处理机调度的层次 1. ...
- javascript中字符串常用方法总结
字符串是javascript编程中不可或缺的元素,掌握字符串常用的方法也是我们学习过程中的必经之路,下面我们总结一些最常用的的字符串方法. string.charAt(postion) charAt方 ...
- MD5处理图片加密算法
Android MD5加密算与J2SE平台一模一样,由于Android 平台支持 java.security.MessageDigest这个包.实际上与J2SE平台一模一样. 首先: 输入一个Stri ...
- UVA - 11986 Save from Radiation
Description J Save from Radiation Most of you are aware of Nuclear Power Plant Explosion at Fukushim ...