作者: 杨江
一 概述
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 。
片 |
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