千字文 bada
应用程序开发教程
概述:
“
千字文
”
是一个电子书应用程序,将中国传统的《千字文》做到了
bada
平台上,方便广大的
bada
手机用户随时随地阅读学习。
“
千字文
”
应用程序能显示汉字,拼音和汉字
+
拼音三种形式的内容,还配有相应的译文显示和朗读功能。
这篇教程就是给大家演示这个程序是如何开发出来的,主要包括应用程序中的设计模式、界面部分、播放功能部分和事件处理模块的实现。
1
, ”
千字文 ”
中的设计模式
Provider
模式
在这个程序中可以通过点击 ”
内容切换 ”
按钮来分别显示汉字,拼音和汉字 +
拼音三种形式的内容。利用 bada
平台提供的接口很容易就能够采用 Provider
模式来实现这个功能。 Provider
模式被用于提供不同的数据模式,这样可以将不同的
Osp::Ui::Controls::ListView
中通过
SetItemProvider(const
IListViewItemProvider &provider)函数来为ListView设置显示内容的Provider。这样可以将UI显示和数据部分分开,我们可以利用IListViewItemProvider来实现Provider模式。分别用3个类QianZiWenHanZiContentProvier,QianZiWenPinYinContentProvider和QianZiWenAllContentProvider来分别提供汉字,拼音和汉字+拼音三种内容,每个类都是继承实现了IListViewItemProvider接口类的。这样每次只需要通过调用SetItemProvider(const IListViewItemProvider &provider)来设置不同的Provider然后刷新ListView就可以了。后续如果还有其它形式的内容需要添加的话,只需要继承实现IListViewItemProvider就可以了。
拿提供汉字的
Provider
举例,其它的
Provider
和它类似。
class
QianZiWenHanZiContentProvider
:
public
Osp::Ui::Controls::
IListViewItemProvider
{
public
:
QianZiWenHanZiContentProvider();
virtual
~QianZiWenHanZiContentProvider();
public
:
virtual
int
GetItemCount(
void
);
virtual
Osp::Ui::Controls::
ListItemBase
* CreateItem(
int
index,
int
itemWidth);
virtual
bool
DeleteItem(
int
index, Osp::Ui::Controls::
ListItemBase
* pItem,
int
itemWidth);
};
在监听到 ”
切换内容 ”
事件时替换 Provider
并刷新界面就可以了。
void
QianZiWenDisplayForm::ChangeContentType
()
{
if
(
__contentStyle
==
CONTENT_STYLE_HANZHI
)
{
delete
__pContentProvider
;
__pContentProvider
= NULL;
__pContentProvider
=
new
QianZiWenPinYinContentProvider();
__pListPanel
->SetContentProvider(
__pContentProvider
);
__pListPanel
->UpdateDisplayPanel();
__contentStyle
=
CONTENT_STYLE_PINYIN
;
}
else
if
(
__contentStyle
==
CONTENT_STYLE_PINYIN
)
{
delete
__pContentProvider
;
__pContentProvider
= NULL;
__pContentProvider
=
new
QianZiWenAllContentProvider();
__pListPanel->SetContentProvider(
__pContentProvider
);
__pListPanel
->UpdateDisplayPanel();
__contentStyle
=
CONTENT_STYLE_ALL
;
}
else
if
(
__contentStyle
==
CONTENT_STYLE_ALL
)
{
delete
__pContentProvider
;
__pContentProvider
= NULL;
__pContentProvider
=
new
QianZiWenHanZiContentProvider();
__pListPanel
->SetContentProvider(
__pContentProvider
);
__pListPanel
->UpdateDisplayPanel();
__contentStyle
=
CONTENT_STYLE_HANZHI
;
}
}
2
, ”
千字文 ”
中的界面实现
(1) Footer
创建 Footer,
void
QianZiWenDisplayForm::CreateFooter
()
{
//Creat the footer items
Footer
* pFooter =
GetFooter
();
pFooter->
SetStyle
(
FOOTER_STYLE_BUTTON_TEXT
);
FooterItem
switchItem;
switchItem.
Construct
(ID_BUTTON_SWITCH);
switchItem.
SetText
(L
"
切换内容
"
);
pFooter->
InsertItemAt
(INDEX_BUTTON_SWITCH,switchItem);
FooterItem
playItem;
playItem.
Construct
(ID_BUTTON_PLAY);
playItem.
SetText
(L
"
播放
"
);
pFooter->
InsertItemAt
(INDEX_BUTTON_PLAYER,playItem);
FooterItem
helpItem;
helpItem.
Construct
(ID_BUTTON_HELP);
helpItem.
SetText
(L
"
帮助
"
);
pFooter->
InsertItemAt
(INDEX_BUTTON_HELP,helpItem);
pFooter->
AddActionEventListener
(*
this
);
}
其中用于控制播放器的
”
播放
”
和
”
暂停
”
按钮需要进行状态的改变,由播放转变成暂停,再由暂停转变成播放。这时需要进行改变和更新。
void
QianZiWenDisplayForm::ChangeToPause
()
{
//Change the footer item
Footer
* pFooter =
GetFooter
();
FooterItem
pauseItem;
pauseItem.
Construct
(ID_BUTTON_PAUSE);
pauseItem.
SetText
(L
"
暂停
"
);
pFooter->
SetItemAt
(INDEX_BUTTON_PLAYER,pauseItem);
pFooter->
RequestRedraw
();
}
void
QianZiWenDisplayForm::ChangeToPlay
()
{
//Change the item
Footer
* pFooter =
GetFooter
();
FooterItem
playItem;
playItem.
Construct
(ID_BUTTON_PLAY);
playItem.
SetText
(L
"
播放
"
);
pFooter->
SetItemAt
(INDEX_BUTTON_PLAYER,playItem);
pFooter->
RequestRedraw
();
}
(2)
Panel
和
ListView
“
千字文 ”
程序中没有直接将 ListView
添加到 Form
当中,而是根据 Form
的客户区域创建了一个 Panel
并添加到 Form
当中,然后在 Panel
中创建 ListView
并将 Panel
设置为其容器类控件。
创建 Panel
class
QianZiWenDisplayPanel
:
public
Osp::Ui::Controls::
Panel
{
public
:
QianZiWenDisplayPanel(Osp::Ui::Controls::
IListViewItemEventListener
* pListener,Osp::Ui::
ITouchEventListener
* pTouchListener);
virtual
~QianZiWenDisplayPanel();
public
:
virtual
result
OnInitializing(
void
);
virtual
result
OnTerminating(
void
);
virtual
result
OnDraw();
public
:
void
SetContentProvider(Osp::Ui::Controls::
IListViewItemProvider
* pProvider);
void
UpdateDisplayPanel();
int
GetItemIndexFromPosition(
const
Osp::Graphics::
Point
& position);
private
:
//Own
Osp::Graphics::
Bitmap
*
__pBgBmp
;
Osp::Ui::Controls::
ListView
*
__pContentList
;
//Not Own
Osp::Ui::Controls::
IListViewItemProvider
*
__pContentProvider
;
//Not Own
Osp::Ui::Controls::
IListViewItemEventListener
*
__pListListener
;
//Not Own
Osp::Ui::
ITouchEventListener
*
__pTouchListener
;
};
在 Panel
中创建 ListView
result
QianZiWenDisplayPanel::OnInitializing(
void
)
{
result
r = E_SUCCESS;
SetBackgroundColor
(
Color
::
COLOR_WHITE
);
//Get the background bitmap
AppResource
* pAppRes =
Application
::
GetInstance
()->
GetAppResource
();
__pBgBmp
= pAppRes->
GetBitmapN
(L
"bg.png"
);
//Create the List
__pContentList
=
new
ListView
();
Rectangle
rec =
GetBounds
();
__pContentList
->
Construct
(rec,
true
,
false
);
__pContentList
->
SetItemProvider
(*
__pContentProvider
);
__pContentList
->
AddListViewItemEventListener
(*
__pListListener
);
__pContentList
->
AddTouchEventListener
(*
__pTouchListener
);
AddControl
(*
__pContentList
);
return
r;
}
3
, ”
千字文 ”
中的播放功能
“
千字文 ”
中一个重要的功能就是当长按某一项时,播放器就从这一项开始播放。这个功能的实现是利用了 Osp::Media::Player
的
SeekTo
函数,调用SeekTo()
函数跳转到对应的播放点开始播放就可以了。所以实现这个功能最麻烦的地方就是要在音频文件中通过手工的方式找到每项的播放时间,记住转换为毫秒。 (long msTime)
这就是每项的句子对应的起始时间点:
//The starting positon of each sentence in the audio file
//Change the positon value(hh:mm:ss) to milliseconds
const
int
StartPosition[ListItemCount] =
{
3000,
//1
8000,
13000,
18000,
……
};
看一下代码实现:
void
QianZiWenDisplayForm::OnListViewItemLongPressed
(Osp::Ui::Controls::
ListView
&listView,
int
index,
int
elementId,
bool
& invokeListViewItemCallback)
{
int
position = StartPosition[index];
__pAudioPlayer
->
SeekTo
(position);
}
由于
SeetkTo
是一个异步调用的过程,所以需要在相应的完成回调函数中调用
Player
进行播放。
void
QianZiWenDisplayForm::OnPlayerSeekCompleted
(
result
r )
{
AppLog(
"OnPlayerSeekCompleted"
);
if
(r == E_SUCCESS)
{
AppLog(
"OnPlayerSeekCompleted Success"
);
if
(
__pAudioPlayer
->
GetState
() ==
PLAYER_STATE_PAUSED
)
{
__pAudioPlayer
->
Play
();
//Change the item
ChangeToPause();
}
}
}
4
,
”
千字文
”
中的事件处理
程序中用
QianZiWenDisplayForm
类继承实现了所有的接口了,包括有
Osp::Ui::IActionEventListener,Osp::Ui::Controls::IListViewItemEventListener,Osp::Media::IPlayerEventListener,Osp::Ui::ITouchEventListener,
这样做的好处就是可以将事件处理和
UI
的现实部分进行分离,单独拿出一个类来进行事件处理,比起将事件处理分散在各个类分别进行处理更易于管理。也符合
MVC
中的
View
和
Controller
分离的原则。所以
QianZiWenDisplayForm
扮演了一个
Controller
的角色。
详细的技术点大家可以参考源代码。