如何创建定制的 BlackBerry UI Field

作者: 杨江

 

  概述

 

Bla ckBe rr y 台为 员提供 准的 UI 组件, 程序 快速开发 手机应 奠定 基础。 但大量 机软 是消费类 娱乐 软件 这些软件 UI 界面 要独 众不同 能抓 用户的 眼球。

 

标准的 UI 件经 满足开 商和 独特 要求, 多时 开发人员 需要发 其想 力去创 造和定 出新的 UI 。所幸 Bla c kBerr y 台上 面创建 制的 UI 一件比 简单 事情。

 

  Bla ckBer r y U I Fi e ld

Bla ckB erry AP I J a v a d o c 中我们 到, 们常 UI 组件 Fi eld 如文本框 Bu tt o n Fi eld

L ab elFi eld T ex tFi eld 都是扩展   n et .r i m .d ev ic e.a p i.u i. Fi eld 而来。

 

 

 

更高级的 Bla ckB erry UI 件,比 管理器 M an ag er 和窗口 Scr ee n 继承 F ield 类。

 

 

 

创建定 U I Fi e ld 的方法

创建自 义字 ,编写一 Fi eld ,通 至少需要 实现 lay o u t() p ain t() 个方法 以设置 Fi eld 宽度和 度, UI 件的界 。其 方法可选 ,具体 表如

 

Fi eld UI 的最 单元 这个最 单元 面不能放

其他 Fi eld 但是 M an ag e r 类可以 M an ag er 类里面 可以嵌 放置 M an ag er M an ag er Fi eld 在屏 幕上的 放位

extends Field 并实现相 应的方 或者是 extends 有的 Fi eld 类,比如 LabelField ListFiel d

Fi eld 在手机 幕上显示 为一个 方形 区域,有高

实现   layout() :调用   set Ex te nt () 方法设


 

度,宽度

  Field   的宽 和高

Fi eld 长方 的区域中 更改背 / 字,

加边框等

实现     paint() 使   Gr a ph ic s   对象的

drawLine drawRect d ra wT ex t 等方法 来绘制 Field

Fi eld 可以选 是否要处 理和如 处理 / 球事

件,例 用户 下“黑莓 退出键 ,你 以选择弹 对话框 D ial o g ,让用户确 认需要退

实现   keyChar()

trackwheelClick()

invokeAction() 等方

Fi eld 需要告诉 M an ag er 它的 p refer ed 和高

以便   M an ag er 包含 各个   Fi eld

ov err i d e getPreferre dWidth

getPreferredHeight 方法

Field   被选中, on   f ocu s 的时候 以选 重新绘制

段。

 

注:用 希望 Field / 非选中 态显 的界 不一 样,比 选中 时候 亮度显 ,加 框; 就低亮 显示 可。

实现   drawFocus   (): 使   Graphics   对象

setBackgroundColor() 方法改 背景 色, drawLine dr aw Re c t drawText 方法来 Field

Fi eld 可以选 是否要处 理和如 处理 F o cus/ selec te d

事件

实现 onFocus ()

 

 

 

 

 

下面让 们通 实现一组 自定义 Fi eld 让我们的 应用程 用户 面更加丰 富多彩。

 

3.1 Hy pe r lin k But t o nFi e l d

 

缺省的 Bu t to n Fi eld     个有边 形的按钮 ,按钮 度比 钮文字长 度稍宽。 在某些 息处 应用中, 如果 UI 里面 操作太 ,用 会觉得按 钮多而 息少 为什么

不考虑 文字 息内容和 文字相 (按   混合 示呢?

 

或者是 超文 链接 按钮代替传 Bu tt o n Fi eld 呢?


 

 

我们不 从头 一个这样 的控 --e xt end s Fi eld 实现 Fi eld 的很多方 法。我 大可 找一个

和我们 要的 面相似的 一个已 存在的   Fi eld 行扩展。

 

下面, 们扩展 Bl ackB err y 提供的 L ab elFi eld 来实现 们的 H y p erlin kB u tto n Fi eld ,这样就不需 要管基 的文 的显 ,而只 要扩 实现 能:

 

1 .     H y p erlin kButt o n Fi eld 的文字 有下 线,并且 被选中 没有 择的字体 颜色要 背景色 不同。

 

2 .     用户按 轨迹 ,或者安 装键盘 Ent er 要触发 H y p erlin kButt o n Fi eld 的动 具体实 计划:

H y p erlin kButt o n Fi eld

extends   现有的 LabelFi el d

Fi eld 在手机 幕上显示 为一个 方形 区域,有高

度,宽度

不去实 了,   La be lF ie ld  

layout()

显示带 划线 文字

实现     paint() 改该 景色 改字

色,然 借用 La be lF ie ld paint()

方法显 文字

Fi eld 可以选 是否要处 理和如 处理 / 球事

件,例 用户 下“黑莓 退出键 ,你 以选择弹 对话框 D ial o g ,让用户确 认需要退

实现   keyChar()

trackwheelClick()

invokeAction() 等方

Fi eld 需要告诉 M an ag er 它的 p refer ed 和高

以便   M an ag er 包含 各个   Fi eld

ov err i d e getPreferre dWidth

getPreferredHeight 方法

Field   被选中, on   f ocu s 的时候 以选 重新绘制

段。

 

注:用 希望 Field / 非选中 态显 的界 不一 样,比 选中 时候 亮度显 ,加 框; 就低亮 显示 可。

实现   drawFocus   (): 使   Graphics   对象

setBackgroundColor() 方法改 背景 色, drawLine dr aw Re c t drawText 方法来 Field


 

H y p erlin kButt o n Fi eld .jav a   ex te nd s L ab elFi eld ,通 三个 color 来记录和 控制字 的颜

public class HyperlinkButtonField extends LabelField

{

private int _textColour ;

private int _textColourFocus ;

private int _highlightColour ;

 

private XYRect _tmpRect = new XYRect();

 

public HyperlinkButtonField( String text, int textColour, int textColourFocus, int

highlightColour, int menuOrdinal, int menuPriority, long style )

{

super ( text, Field. FOCUSABLE | style ); // 这个 Field 需要 FOCUSABLE st y le 以让用 能够

 

_textColour = textColour;

_textColourFocus = textColourFocus;

_highlightColour = highlightColour;

}

 

 

实现 applyFont() 设置 使用带 划线 Font. UNDERLINED 看上 象一个 hyper   link

 

 

 

public void applyFont()

{

Font underlineFont = getFont().derive( Font. UNDERLINED   );

setFont( underlineFont );

}

 

 

 

 

 

实现     paint()     段的   M an ag er   将调用     paint() 以在 个字 区域 为无效 重新 制字

段。调用   graphics.s et Co lo r () 来设置当 Fi el d 在没有 ( Focus) 状态时 的字 颜色 在修改 字体 色参 调用 super.paint() LabelField.paint() 方法来 制显 这个 Field

 

 

protected void paint ( Graphics g )

{

int oldColour = g.getColor();

try {

if (g.isDrawingStyleSet( Graphics. DRAWSTYLE_FOCUS ) ) {

g.setColor( _textColourFocus );

} else {

g.setColor( _textColour );

}

super .paint( g );   // 修改了 体以 ,调 父类 LabelField paint() 新画指 颜色 文字

} finally {

g.setColor( oldColour );  // 这里用临时变 量来恢复 Graphics 原来 颜色

}

}

 

实现   drawFocus   ()     段的管 器将   dr aw Fo cu s   () ,以在 个字 选中造 在被

为无效 重新 制字 g.setBackgroundColor( ) 来设置当 Field 被选中 (Focus) 态时 的画布 背景 ;调用 pa i nt () 重新画 个字 paint() 里面 调用 su pe r. pa in t( ) 也就是 LabelField.paint() 法来绘 显示 Field


protected void drawFocus ( Graphics g, boolean on )

{

getFocusRect( _tmpRect ); //Retrieves this field's current focus region.

 

boolean oldDrawStyleFocus = g.isDrawingStyleSet( Graphics. DRAWSTYLE_FOCUS );

int oldBackgroundColour = g.getBackgroundColor();

 

boolean notEmpty = g.pushContext( _tmpRect . x , _tmpRect . y , _tmpRect . width ,

_tmpRect . height , 0, 0 );

try {

if ( notEmpty ) {

if ( on ) {

g.setDrawingStyle( Graphics. DRAWSTYLE_FOCUS , true );

g.setBackgroundColor( _highlightColour );


 

 

 

下划线


}

g.clear();

paint( g );  // 修改了 景色 ,调用 Hy pe rl in kB ut to nF ie ld .paint() 来重新 ,以 示背 色,

 

}


} finally {

g.popContext();

g.setBackgroundColor( oldBackgroundColour ); // 这里用 时变 来恢 Graphics 原来的 景色

 

g.setDrawingStyle( Graphics. DRAWSTYLE_FOCUS , oldDrawStyleFocus );

}

}

 

 

实现   keyChar   () trackwheelClick () invokeAction () 等方法 用户按 按钮

 

 

protected boolean keyChar( char character, int status, int time )

{

if ( character == Characters. ENTER ) {

fieldChangeNotify ( 0 );

return true ;  //return ture 是告诉 Ma na ge r ,这个 件我 经处 了,你不 需要再 由别 处理

}

return super .keyChar( character, status, time );

}

 

protected boolean trackwheelClick( int status, int time ) {

keyChar(Characters. ENTER , status, time );

return true ;   //return ture 是告诉 Manager ,这个 件我 经处 了, 要再交 别人

 

}

 

protected boolean invokeAction( int action )

{

switch ( action ) {

case ACTION_INVOKE : {

fieldChangeNotify( 0 );

return true ; //return ture 是告诉 Ma n ag er ,这个 件我 经处 你不需 再交 别人

}

}

return super .invokeAction ( action );

}

 

HyperlinkButtonField 的使用 意要 Fi el dC ha ng eL is te ne r

 

 

HyperlinkButtonField link = new HyperlinkButtonField (“Colour     Picker”, 0x0000FF, 0xFFFFFF,

0x0000FF, 0, 0);

link.setChangeListener( new FieldChangeListener( ) {

public void fieldChanged( Field field, int context ) {

//do something here

}

} );


 

 

小结:

 

HyperlinkButtonField .java 代码中 我们 ex te nd s La be lF ie ld   paint() 方法 了界面 用户 择按 候, 我们 drawFocus() 改字体 景和 景色 重绘界 ,同 用户 click 按钮后 触发 Fi el dC ha ng e 事件。

 

HyperlinkButtonField 字段的 面重 还是相对 简单的 是借 su pe r. pa in t() 方法也

LabelField.paint() 行绘图 示文

 

其他某些 Field 的定制要 求就没 这么 单了 者需要 己调用 Gr ap hi c s 对象的 drawLine

drawRect drawText   等方法来   Field   线 、边框 文字 显示内容

 

 

 

 

3.2 Bi t ma p B u tt o nFi e l d M e d iaC o n t rol S t y l e F iel d

 

 

 

 

让我们 一下 复杂的媒 播放器 界面。

 

 

 

 

 

 

用户可 在播 器四个按 钮之间 向滚 ,按钮选 中的时 第二个播 放按钮 按钮 高亮

度显示。

 

在这个 M edi aC o n tr o lS ty l e Fi eld 实现中 Fi eld 包含了 4 Bit m ap Bu t to n Fi eld 字段, 面裹上 圆的边 于最底层 Fi eld 是不 包含其他 字段的 所以 M edi aC o n tr o lS ty l eField 实际上 扩展 M an ag er 面包含 4 Bit m ap Bu t to n Fi eld 本字段。

   

 

让我们 实现 片按钮   Bi t ma pB ut to nF ie ld

 

 

首先, 两张 Bitmap   作为参 给其 造方


public class BitmapButtonField extends Field {

 

public BitmapButtonField( Bitmap normalState, Bitmap focusState, long style )

{

super ( Field. FOCUSABLE | style ); // 必须使 Field. FOCUSABLE style ,以让这 按钮 够被

 

if ( (normalState.getWidth() != focusState.getWidth())

|| (normalState.getHeight() != focusState.getHeight()) ){

 

throw new IllegalArgumentException( "Image sizes don't match" );

}

 

_bitmaps = new Bitmap[] { normalState, focusState };  // 把两张 Bitmap 图片保 在缓

}

 

 

  layout() 方法   setExtent() 方法设置 自己的 度和 度。 段的高 和宽 实际

Bitmap 的高度和宽度 。在 getPreferredWidt h () getPreferredHeight() 方法中

Manager 自己希 的的 度和宽

 

protected void layout( int width, int height ) {

setExtent( _bitmaps [ NORMAL ].getWidth(), _bitmaps [ NORMAL ].getHeight() );

}

 

public int getPreferredWidth() {

return _bitmaps [ NORMAL ].getWidth();

}

 

public int getPreferredHeight() {

return _bitmaps [ NORMAL ].getHeight();

}

 

 

 

当黑莓 机屏 显示 钮的时 ,在   paint() 法中根 其是   Focus   状态, 出要 示的

的索引 index 字,然后 使用 Graphic.drawBitm ap (bitmaps[index] ) 法把这 图片

 

当黑莓 机屏 上这 处于 Focus 的时候, drawFocus( ) 方法中设 draw style 并调用

paint() 方法重 屏幕,显 Focus 时候 要显示的 图片。

 

 

protected void paint( Graphics g ) {

int index = g.isDrawingStyleSet( Graphics. DRAWSTYLE_FOCUS ) ? FOCUS : NORMAL ;

g.drawBitmap( 0, 0, _bitmaps [index].getWidth(), _bitmaps [index].getHeight(),

_bitmaps [index], 0, 0 );

}

 

protected void drawFocus( Graphics g, boolean on ) {

// Paint() handles it all

g.setDrawingStyle( Graphics. DRAWSTYLE_FOCUS , true );

paintBackground( g );  // 修改过 选中 背景 ,重绘 景色

paint( g );   // 调用上 paint() 重绘屏幕 ,显示 Focus 候需 显示 图片

}

 

 

实现了 以根据 Focus 自动显 不同 图片 组件, 下的 作就

 

MediaControlStyleField 扩展 HorizontalField Manager ,在 Horizontal FieldManager 里面放 四个可以 focus 的图 ,然 setPadding() 按钮之 HorizontalFi eldManager 边角的间 距, setMargin() Ho ri zo nt al Fi el dM an ag er 外面的 paintBac kground () 方法中画实 心的圆 的矩形 个颜 画圆角的 框。 样, 体播放 就算 现了。


class MediaControlStyleField extends HorizontalFieldManager

{

MediaControlStyleField()

{

super (Manager. FIELD_HCENTER );

// 横向放 个图 按钮

add( new BitmapButtonField (Bitmap.getBitmapResource("prev.png"), Bitmap.getBitmapResource("prev_focus.png" ) ));

add( new BitmapButtonField (Bitmap.getBitmapResource("play.png"), Bitmap.getBitmapResource("play_focus.png" ) )); add( new BitmapButtonField (Bitmap.getBitmapResource("stop.png"), Bitmap.getBitmapResource("stop_focus.png" ) )); add( new BitmapButtonField (Bitmap.getBitmapResource("next.png"), Bitmap.getBitmapResource("next_focus.png" ) ));

setPadding(5,5,5,5);       //OS 5.0 未公开的 API

setMargin( 10, 10, 10, 10 );  //OS 5.0 未公开的 API

}

 

protected void paintBackground( Graphics g )

{

int oldColor = g.getColor();

try {

g.setColor( 0x222222 );

g.fillRoundRect( 0, 0, getWidth(), getHeight(), 20, 20 ); // 画实心的圆 的矩形

g.setColor( 0x000000 );

g.drawRoundRect( 0, 0, getWidth(), getHeight(), 20 ,20 ); // 换个颜色, 圆角 边框

} finally {

g.setColor( oldColor );

}

}

 

}

 

 

 

 

3.3   Pro gressA nima t i o nFie ld

前面我 扩展 有的 L ab elFi eld 实现了能 够互动的 H y p erlin kBut to n Fi eld ,然后 现了 个完 全自定 的根 字段 F o c u s 与否来 示不 Bit m ap Bu tt o n Fi eld

 

我们能 实现 加动 UI Fi eld 比如 P ro g r essAn im atio n Fi eld 可以使 后台 J av a T h re ad

刷新自 的显 内容。

 

 

 

 

 

注:在 BlackBerry OS 6 .0 中已包含 animation field 。但使用 BlackBer ry OS 5.0 的开发 仍然会 这段 码感 趣。

 

P ro g r essAn im atio n Fi eld 实现其 很简 下面 的长条 图片 成六段, 每过 2 0 0 毫秒 示下 一段, 环往 即可。当 屏幕显 这个 Fi eld 的时 候,启 线程 环显示; 当屏幕 有在 示这个 Fi eld 的时候 停止显示 显示线

 

 

 

实现计

 

P ro g r essAn im atio n Fi eld

extends   Field 并实现相 应的方

Fi eld 在手机 幕上显示 为一个 方形

实现   layout () :调用   set Ex te nt () 设置   Field


 

域,有 度,

的宽度 高度 图片 宽度     片的

Fi eld 长方 的区域中 显示图片

实现     paint() 使   Gr a ph ic s   对象的   drawBitma p

方法显 图片 部分

后台线 程序 时刷新 Fi eld 显示的

0.2 i n v ok e 新的线 进行刷 屏幕

App li cat i on.g etAp p li ca ti on() . i nv ok eLa ter ( t h is,

200 , tru e );

 

 

 

P r o g ressAn i m ati o n Fi eld 构造方 中计 这个 Fi eld 的高度 宽度( fra m eWid th fram eHeigh t ),

然后在 la yo u t () 中设 自己 度为 片一个 Fr am e 的宽 ,高 为图 的高度。

 

 

public ProgressAnimationField( Bitmap bitmap, int numFrames, long style )

{

super ( style | Field. NON_FOCUSABLE );

_bitmap = bitmap;

_numFrames = numFrames;

_frameWidth = _bitmap .getWidth() / _numFrames ;  // 只取图 中一个 Frame 的宽度

_frameHeight = _bitmap .getHeight();

 

_application = Application.getApplication ();

}

 

protected void layout( int width, int height )

{

setExtent( _frameWidth , _frameHeight );// 设定本 Field 宽度 图片 Fr am e 的宽度 高度 图片 高度。

}

 

 

  paint() 方法 ,调用   Graphics.drawBitmap   显示图 的当前   frame   图片。

 

 

protec ted void paint( Graphics g )

{

g.drawBitmap( 0, 0, _frameWidth , _frameHeight , _bitmap , _frameWidth * _currentFrame , 0 );

_currentFrame ++;

if ( _currentFrame >= _numFrames ) {

_currentFrame = 0;

}

}

 

 

o n D isp lay( ) App li catio n .inv o k eL at er 方法每 0 .2 刷新 幕。

_app li catio n .inv o k eL a te r( t h is, 2 0 0 , true ) 中的 20 0 是说 0 .2 2 0 0 ,毫秒即 m il li s eco n d 分之一 )后 thi s 线 程,参数 true 说每过 0 .2 秒都 再次 thi s 线 程。

 

in vo k eL a te r() 可以 个后台线 程程 不会阻塞 应用程 ,造 应用程序 僵死。

 

_app li catio n = App li cati o n .g et App li catio n ( ) Fi eld 造的时 做了 局缓

 

o n Und isp lay( ) 取消 inv o k e 再刷新 幕图 显示。


public void run()  {

if ( _visible ) {

invalidate();  // invalidate 方法将 force 手机调用 Field paint() 法重 绘界面。

}

}

 

protected void onDisplay () //OS 5.0 里面 Field 的未 API

{

super .onDisplay();

_visible = true ;

if ( _timerID == -1 ) {

_timerID = _application .invokeLater( this, 200, true ); // 0.2 秒就后台 invoke 一次

}

}

 

protected void onUndisplay()//OS 5.0 里面 Field 未公开 API

{

super .onUndisplay();

_visible = false ;

if ( _timerID != -1 ) {

_application .cancelInvokeLater( _timerID );// 取消每 0.2 秒就后台 invok e 一次的操作

_timerID = -1;

}

}

 

 

 

 

小结

 

在例子 H y p erlin kButt o n Fi e ld 中,我们 L ab elFi el d 获得更多 显示 滚轮和 盘操 理;在 Bit m ap Bu t to n Fi eld M edi aC o n tr o lS t y leFi eld 中,我 看到 何使用图 Bit m ap 切换 实现一 简单 图片按钮 ,然后使 用基于 H o riz o n t alM an ag er M edi aC o n tr o lS ty l eField UI 件;在 P r o g res sAn im atio n Fi eld 们使用后 台线程 时刷 界面显示

 

 

 

 

从上面 个例 中,我们 看到 H y p erlin k Bu tt o n Fi eld / Bit m ap Bu tt o n Fi eld/ P r o g re ssAn im ati o n Fi eld 是最 小用户 面元 ,换句话 说,这些 UI 组件 能包含 chi ld 元素。

 

如果我 要实 M edi a Co n tr o lS ty l eField 体播 放器界 ,或者 Tabl e 签页, 以滚 的表 格,那 就需 去实现更 复杂 口管 - M an a g e r

 

 

 

参考

 

本节中使 用的 有例 代码 在下面 找到 Ho w t o - I m p le m e nt a dv ance d bu t to ns , fi e l ds , a nd m an ag er s

 

http://www . blackberry.co m/ k n o w ledgecenterpubl i c/liv e lin k .exe/f e tch/2 0 00/3485 8 3/8 0 0332 / 8005 0 5/8 0 0608 /H ow_to_-

_I m ple m ent_advanced_buttons, _ fie ld s , _and_ ma n ag ers.ht m l?nodeid=24 0 6256 & vern u m =0

 

代码 Ho w t o - I m ple m e nt a dv an ce d butto ns , fiel ds , a nd m an ag er s

 

htt p://www. bl ack berry .co m /k no wle dgece nter su ppo r t /k m su pport /deve l o p erk no wle dge ba se /zi p/Ho w_ T o_ Im ple m e nt_ Adv ance d_ UI.zi p

 

UI an d N avi g atio n - 开发 - Bl ackBerr y J av a App l ic at i o n


说明: R IM UI 发入 htt p://doc s.bl ack be rry .co m /en/deve l o per s/deli v er able s/16521/UI_co m po ne nt s_ 508102_11.jsp 创建自 义字段

htt p://doc s.bl ack be rry .co m /en/deve l o per s/deli v er able s/16521/Cre ate_ a_c usto m _fiel d _ 508117_11.jsp Cre at e a c usto m fi e l d htt p://doc s.bl ack be rry .co m /en/deve l o per s/deli v er able s/11958/Cre ate_ a_c usto m _fiel d _ 508117_11.jsp

 

 

 
 
BlackBerry SDK下载

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值