在iOS上实现瀑布流界面

简介:

前阵子需要做一个需求,在iPhone上实现瀑布流效果。

第一眼看到这个需求,我想到的两种解决方案分别是:

1. 使用多个UITableView,然后控制它们同时滚动;

 2. 使用一个UIScrollView,然后参考UITableView的实现自己做一个符合需求并且以后可以重用的控件。


我首先尝试了第一个方案,并且Google过控制多个UITableView同时滚动的代码,在StackOverflow里面找到一段蛮详细的代码了,不过在复杂的用户操作下,仍然会出现滚动不同步的情况。

最终,我放弃了这个方案。


而第二个方案的关键点就在于参考UITableView实现时,如何重用单元格。

下面是我实现的重用代码:

- (void)onScroll
{
    for (int i = 0; i < self.columns; ++i) {
        NSUInteger basicVisibleRow = 0;
        WaterFlowViewCell *cell = nil;
        CGRect cellRect = CGRectZero;
        
        NSMutableArray *singleRectArray = [self.cellRectArray objectAtIndex:i];
        NSMutableArray *singleVisibleArray = [self.visibleCells objectAtIndex:i];
        
        if (0 == [singleVisibleArray count]) {
            // There is no visible cells in current column now, find one.
            for (int j = 0; j < [singleRectArray count]; ++j) {
                cellRect = [(NSValue *)[singleRectArray objectAtIndex:j] CGRectValue];
                if (![self canRemoveCellForRect:cellRect]) {
                    WFIndexPath *indexPath = [WFIndexPath indexPathForRow:j inColumn:i];
                    basicVisibleRow = j;
                    
                    cell = [self.waterFlowDataSource waterFlowView:self cellForRowAtIndexPath:indexPath]; // nil ?
                    cell.indexPath = indexPath;
                    cell.frame = cellRect;
                    if (!cell.superview) [self addSubview:cell];
                    NSLog(@"Cell Info : %@\n", cell);
                    
                    [singleVisibleArray insertObject:cell atIndex:0];
                    break;
                }
            }
        } else {
            cell = [singleVisibleArray objectAtIndex:0];
            basicVisibleRow = cell.indexPath.row;
        }
        
        // Look back to load visible cells
        for (int j = basicVisibleRow - 1; j >= 0; --j) {
            cellRect = [(NSValue *)[singleRectArray objectAtIndex:j] CGRectValue];
            if (![self canRemoveCellForRect:cellRect]) {
                WFIndexPath *indexPath = [WFIndexPath indexPathForRow:j inColumn:i];
                if ([self containVisibleCellForIndexPath:indexPath]) {
                    continue ;
                }
                
                cell = [self.waterFlowDataSource waterFlowView:self cellForRowAtIndexPath:indexPath]; // nil ?
                cell.indexPath = indexPath;
                cell.frame = cellRect;
                if (!cell.superview) [self addSubview:cell];
                NSLog(@"Cell Info : %@\n", cell);
                
                [singleVisibleArray insertObject:cell atIndex:0];
            } else {
                break;
            }
        }
        
        // Look forward to load visible cells
        for (int j = basicVisibleRow + 1; j < [singleRectArray count]; ++j) {
            cellRect = [(NSValue *)[singleRectArray objectAtIndex:j] CGRectValue];
            if (![self canRemoveCellForRect:cellRect]) {
                WFIndexPath *indexPath = [WFIndexPath indexPathForRow:j inColumn:i];
                if ([self containVisibleCellForIndexPath:indexPath]) {
                    continue ;
                }
                
                cell = [self.waterFlowDataSource waterFlowView:self cellForRowAtIndexPath:indexPath]; // nil ?
                cell.indexPath = indexPath;
                cell.frame = cellRect;
                if (!cell.superview) [self addSubview:cell];
                NSLog(@"Cell Info : %@\n", cell);
                
                [singleVisibleArray insertObject:cell atIndex:0];
            } else {
                break;
            }
        }
        
        // Recycle invisible cells
        for (int j = 0; j < [singleVisibleArray count]; ++j) {
            cell = [singleVisibleArray objectAtIndex:j];
            if ([self canRemoveCellForRect:cell.frame]) {
                [cell removeFromSuperview];
                [self addReusableCell:cell];
                [singleVisibleArray removeObject:cell];
                --j;
                NSLog(@"Removable Cell Info : %@\n", cell);
            }
        }
    }
}

主要思想就是,1. 找到一个需要展示的Cell;2. 以这个Cell开始,向前、向后推进,为需要展现出来的Cell分配;3. 遍历可见Cell,回收不可见的对象。

最后,把代码稍微做了抽离,弄了个小Demo,放到GitHub:https://github.com/siqin/WaterFlow


目录
相关文章
|
1月前
|
安全 Swift iOS开发
Swift 与 UIKit 在 iOS 应用界面开发中的关键技术和实践方法
本文深入探讨了 Swift 与 UIKit 在 iOS 应用界面开发中的关键技术和实践方法。Swift 以其简洁、高效和类型安全的特点,结合 UIKit 丰富的组件和功能,为开发者提供了强大的工具。文章从 Swift 的语法优势、类型安全、编程模型以及与 UIKit 的集成,到 UIKit 的主要组件和功能,再到构建界面的实践技巧和实际案例分析,全面介绍了如何利用这些技术创建高质量的用户界面。
33 2
|
4月前
|
Android开发 iOS开发 C#
Xamarin.Forms:从零开始的快速入门指南——打造你的首个跨平台移动应用,轻松学会用C#和XAML构建iOS与Android通用界面的每一个步骤
【8月更文挑战第31天】Xamarin.Forms 是一个强大的框架,让开发者通过单一共享代码库构建跨平台移动应用,支持 iOS、Android 和 Windows。使用 C# 和 XAML,它简化了多平台开发流程并保持一致的用户体验。本指南通过创建一个简单的 “HelloXamarin” 应用演示了 Xamarin.Forms 的基本功能和工作原理。
112 0
|
6月前
|
编解码 安全 Android开发
探索iOS与Android开发的差异:从界面到性能
【6月更文挑战第10天】在移动应用开发的广阔天地中,iOS和Android两大平台各占山头,它们在设计理念、用户体验、性能优化等方面展现出独特的魅力。本文将深入探讨这两大系统在开发过程中的主要差异,从用户界面设计到性能调优,揭示各自背后的技术逻辑与创新策略,为开发者提供全面的视角和实用的开发指南。
|
7月前
|
安全 Swift iOS开发
【Swift 开发专栏】Swift 与 UIKit:构建 iOS 应用界面
【4月更文挑战第30天】本文探讨了Swift和UIKit在构建iOS应用界面的关键技术和实践方法。Swift的简洁语法、类型安全和高效编程模型,加上与UIKit的紧密集成,使开发者能便捷地创建用户界面。UIKit提供视图、控制器、布局、动画和事件处理等功能,支持灵活的界面设计。实践中,遵循设计原则,合理组织视图层次,运用布局和动画,以及实现响应式设计,能提升界面质量和用户体验。文章通过登录、列表和详情界面的实际案例展示了Swift与UIKit的结合应用。
316 1
|
安全 数据安全/隐私保护 iOS开发
iOS小技能:【发红包】使用tweak和lua脚本结合进行实现
我们开发的大部分越狱程序,都是编译成动态链接库(`例如:介绍的越狱程序(Tweak)开发,就是动态链接库。`),然后通过越狱平台的MobileSubstrate(iOS7上叫CydiaSubstrate)来加载进入目标程序(Target),通过对目标程序的挂钩(Hook),来实现相应的功能。
347 0
|
Android开发 iOS开发
iOS开发 - 商品详情页两种分页模式,只提供思路和实现方式。
iOS开发 - 商品详情页两种分页模式,只提供思路和实现方式。
428 0
iOS开发 - 商品详情页两种分页模式,只提供思路和实现方式。
|
存储 安全 iOS开发
iOS开发 - 继udid,Mac地址等一系列唯一标识无效后,如何用KeyChain来实现设备唯一性
iOS开发 - 继udid,Mac地址等一系列唯一标识无效后,如何用KeyChain来实现设备唯一性
486 0
iOS开发 - 继udid,Mac地址等一系列唯一标识无效后,如何用KeyChain来实现设备唯一性
|
Swift 数据安全/隐私保护 iOS开发
iOS开发 - swift通过Alamofire实现https通信
iOS开发 - swift通过Alamofire实现https通信
448 0
iOS开发 - swift通过Alamofire实现https通信
|
开发者 iOS开发
iOS开发 - 用AFNetworking实现https单向验证,双向验证
iOS开发 - 用AFNetworking实现https单向验证,双向验证
449 0
iOS开发 - 用AFNetworking实现https单向验证,双向验证
|
iOS开发
iOS小技能:自动布局实现兄弟控件N等分且宽高比例是1:N(xib 上实现)
本文为 iOS视图约束专题的第三篇:xib上使用自动布局教程
188 0