首先要强烈鄙视一下给Nokia S60设计UI接口团队——用到现在最恶心的,文档最不完整的UI框架了。
然后要感谢一下Forum Nokia Wiki 上的 Mayank , 提供了一个鱼眼列表的范例程序,虽然有bug。
http://wiki.forum.nokia.com/index.php/How_to_implement_fisheye_view
源代码可在上面地址下到
这里说一下这个范例里的bug
如果列表很大,超出屏幕,那么最后一个可能没法显示全。
原因是父类的View只能按照等高度的item布局,鱼眼放大效果其实是在绘制过程中的hack方法,实际上view不知道我们放大了某个item。
修复方法是,如果这个焦点在当前屏幕内的最后一行(注意不是全部列表最后一行),那么改变调整逻辑,把列表下移腾出放大空间,改成列表上移。
这个调整后,范例里的Relign方法就没用了,改善了处理效率。
最后改进一下列表的Draw方法。
List控件的Draw方法必调用列表项绘制方法,否则是看不到内容的。
但是没必要全部都绘制一边。只要画当前屏幕开始项目和结束项目就行了。
这些改动,都已经放到wiki上了。不过需要手工覆盖到范例上。
void
CCustomListItemDrawer::DrawActualItem
(
TInt aItemIndex, const
TRect& aActualItemRect,
TBool aItemIsCurrent, TBool /*aViewIsEmphasized*/
,
TBool /*aViewIsDimmed*/
, TBool aItemIsSelected)
const
{
TInt selectedIndex = iListBox.CurrentItemIndex
(
)
;
TInt itemIndex = aItemIndex;
TRect itemRect = aActualItemRect;
if
(
selectedIndex == iListBox.BottomItemIndex
(
)
)
{
// selected item is at the bottom
itemRect.iTl
.iY
-= iItemCellSize.iHeight
;
if
(
itemIndex < selectedIndex )
{
itemRect.iBr
.iY
-= iItemCellSize.iHeight
;
}
}
else
{
if
(
aItemIsCurrent)
{
itemRect.iBr
.iY
+= iItemCellSize.iHeight
;
}
else
if
(
itemIndex > selectedIndex)
{
// Lets move the following entries down to accomodate fish eye window
itemRect.iTl
.iY
+= iItemCellSize.iHeight
;
itemRect.iBr
.iY
+= iItemCellSize.iHeight
;
}
}
// Call the Actual draw function
}
CFishEyeListBox::CFishEyeListBox
(
)
:CAknSingleHeadingStyleListBox(
)
{
}
/**
* Override the default item drawer by our own
*/
void
CFishEyeListBox::CreateItemDrawerL
(
)
{
CColumnListBoxData* columnData = CColumnListBoxData::NewL
(
)
; // CColumnListBoxItemDrawer owns columnData
const
CFont* myFont = CEikonEnv::Static
(
)
->DenseFont(
)
;
iItemDrawer = new
(
ELeave)
CCustomListItemDrawer(
Model(
)
, myFont, columnData, *this
)
;
}
/**
* To handle the item scrolling
*/
TKeyResponse CFishEyeListBox::OfferKeyEventL
(
const
TKeyEvent& aKeyEvent,
TEventCode aType)
{
if
(
EEventKey == aType)
{
switch
(
aKeyEvent.iCode
)
{
// Down arrow
case
EKeyDownArrow: {
ScrollDown(
)
;
DrawDeferred(
)
;
return
EKeyWasConsumed;
}
// Up arrow
case
EKeyUpArrow: {
ScrollUp(
)
;
DrawDeferred(
)
;
return
EKeyWasConsumed;
}
default
:
return
CEikTextListBox::OfferKeyEventL
(
aKeyEvent, aType)
;
}
}
return
EKeyWasNotConsumed;
}
void
CFishEyeListBox::ScrollDown
(
void
)
{
TInt currIndex = CurrentItemIndex(
)
;
if
(
currIndex < Model(
)
->NumberOfItems(
)
- 1
)
{
SetCurrentItemIndex(
currIndex + 1
)
;
}
else
{
// Lets do circular scrolling by setting current index as the first item
SetCurrentItemIndex(
0
)
;
}
ScrollToMakeItemVisible(
CurrentItemIndex(
)
)
;
}
void
CFishEyeListBox::ScrollUp
(
void
)
{
TInt currIndex = CurrentItemIndex(
)
;
if
(
currIndex > 0
)
{
SetCurrentItemIndex(
currIndex - 1
)
;
}
else
if
(
Model(
)
->NumberOfItems(
)
> 0
)
{
// Lets do circular scrolling by setting current index as the last item
SetCurrentItemIndex(
Model(
)
->NumberOfItems(
)
- 1
)
;
}
ScrollToMakeItemVisible(
CurrentItemIndex(
)
)
;
}
/**
* Override the draw function of the list
* Otherwise it will apply a default background instead of transparent
* On s60 3rd mr, there will be bugs when the list is large than default. ( A ugly white bar at the end of list)
*/
void
CFishEyeListBox::Draw
(
const
TRect& aRect)
const
{
CListBoxView* view = View(
)
;
TInt start = view->TopItemIndex(
)
;
TInt end = view->BottomItemIndex(
)
;
for
(
TInt i = start; i <= end; i++ )
{
view->DrawItem(
i)
;
}
}