当我们使用iphone手机通讯录,手机qq的时候。有一个细节大家可能已经忽略,即“分组”控件在向屏幕上方滑动时,超过屏幕的高度,就冻结到屏幕最上端。方便用户确定当前浏览的是哪个分组。当下面的分组上来时候,又会当前冻结的窗口顶上去,它自己又实现冻结!这就是分组冻结功能。
这篇两年前都应该写的博客,直到今天才写出来,才发现当初的设计和思路已经模糊,只能看代码来分析了。所以这篇文章只是回忆一下当初踊跃的思路。
为了能够说明白这个东西,再举一个例子。在使用excel的时候,冻结窗口的功能:固定了第一行(通常是标题行)方便用户对照标题和数据。下面这个gif图片展示了冻结分组的效果。注意“测试”这个分组的效果,当cell移动的时候,它并没有移动,而是定在哪儿了!
2012年,笔者在Symbian平台上实现了分组冻结的功能(纯自绘的);以iOS平台中tableview为例,在使用它的使用,我们必定要实现下面两个函数,分别用来设置section和cell的view。其中section就具备冻结功能:
tableView: viewForHeaderInSection:
tableView: cellForRowAtIndexPath:
笔者还不太清楚iOS 中的tableview是如何实现分组冻结的,因为iOS已经做的很完善了。
既然section能够冻结,那么section在UI层次中的顺序关系就是:section高于cell,这样section冻结的时候,section才能正常显示;或者说将section的控件最后add到view的控件数组中。下面我们看看在绘制控件的时候的先后层次:
上面这个图是飞信塞班版本中UI的层次结构,主要说明UI的绘制是分层的。
设定一个Y值,冻结分组的时候,最上端是多少,这也是主要的参数了。例如下面的代码
iFreezeEngine = FreezeEngine::NewL(this);
iFreezeEngine->SetFreezeLine(Area().iTl.iY);//topLeft.Y
tableview由FreezeEngine和多个cell组成。FreezeEngine管理这多个CCanFreezeControl。cell和CCanFreezeControl都继承自Control基类。如果把FreezeEngine去掉就是正常的view和control的关系了。
FreezeEngine类中两个重要属性是:冻结线,可冻结控件数组。
TInt iFreezeLine;
RPointerArray<CCanFreezeControl> iCanFreezeControlArray;
● CCanFreezeControl类
该类中有三个重要参数,根据这三个参数可以计算出:何时需要冻结?何时从冻结的地方回来。
TInt iFreezeOffset; //是一个负数,在这个区间 [-iGroupItemHeight,0]还有一个最重要的函数TBool CCanFreezeControl::CalcFreezeOffset(const TRect & aSrcRect,TRect& aDesRect)负责计算,当分组接近冻结时候的计算,已经冻结时候的计算。
由于冻结的分组扔需要响应事件,所以,当屏幕点击到“冻结分组”的时候,需要转换成分组实际的坐标进行匹配,才能确定是否响应这个点击。
最后,由于笔者正致力于iOS开发,这些UI基础功能,iOS系统已经做到极致了,所以。这篇博文只是来回忆一下symbian的代码。
原文地址:http://blog.csdn.net/hherima/article/details/38757853