作者: 王志刚
一 触摸屏 幕设 计需要 注意的 地方
开发用于 带触摸 屏的 Blac k Ber r y ® 设备的应用程 序时 ,您应考 虑这些 设备的 以下 U I 功能:
• 触摸屏
• 屏幕方位的重 要性
• 触摸屏键盘
• 加速度计(一 些带触 摸屏 的 Bla c kB e rr y 设备上)
关于这些 项目的 具体内 容和 细节,可 以参考 blackbe r r y 的编程白 皮书: BlackBe r r y Ja v a A pp l ic a ti o n
Tra n si t io n in g t o T o uc h S cre e n D ev e lo p me n t .
二 触摸屏 幕的 具体编 程和设 计的要 求
随着触摸 屏幕手 机的引 入, Bla c kB e rr y 也加入了相应 API 的支持:
net . ri m .d e vi c e. a pi . ui . T o uch s cr e e n 这个类的 作用就 是系统 用来 判别当前 手机是 否是触 屏的 uti l it y 类别,所以一个比 较通用的 jav a 程序的做 法 就是在程 序入口 中加入 这样 的逻辑判 断:
if (Touchscreen.isSupported ())
{
}
else
{
/* Touch screen logic */
UiApplication.getUiApplication ().invokeLater( new Runnable()
{
public void run()
{
}
});
}
Dialog.alert ( "This application requires a touch screen device." );
System.exit (0);
在 JDE5.0 的示例 程序中, 有一个例 子 touchdemo , 有关于这 个工具 类的具 体使 用方法, 可以参 考相应 的 代理例子 在做一 个通用 的 bl ac kb er ry 客户端程 序。
触屏手机 的引入 ,可以 加入 对屏幕的 方向的 变化, 这个 在原有的 全键盘 手机中 是没 有的,所 以在触 摸屏幕 手机开发 应用过 程中, 需要 加入 相应 的响应 的逻辑 . 有两种方 式可以 用来对 屏幕 的方位进 行控制 和调整 ,第 一种方式 是在 screen 的 su bl ay ou t 方法中。
public void sublayout(int width, int height)
{
//update scrren layout based on orientation
if(Display.getOrientation()== Display.ORIENTATION_LANDSCAPE)
{
invalidate();
}
else if(Display.getOrientation()== Display.ORIENTATION_PORTRAIT)
{
invalidate();
}
supe r.sublayout(width, height);
}
还有一种 方式是 在应用 中显 式调用屏 幕的方 位信息 ,然 后做出调 整:
switch(Display.getOrientation())
{
case Display.ORIENTATION_LANDSCAPE:
Dialog.alert("Screen orientation is landscape"); break;
case Display.ORIENTATION_PORTRAIT:
Dialog.alert("Screen orientation is portrait"); break;
case Dis play.ORIENTATION_SQUARE:
Dialog.alert("Screen orientation is square"); break;
default:
Dialog.alert("Screen orientation is not known"); break;
}
除了对屏 幕方位 也就是 重力 切换的处 理,在 触摸屏 幕编 程中,需 要考虑 UI 事件的处 理和全键 盘手机 的不 同,关于 这部分 的具体 处理 ,可以参 考下面 部分的 示例 以及后续 的内容 介绍 。
三 一个触摸 屏幕应用界面 的例子
本章以一 个定制 的黑莓 UI 展 示程序为 例,说 明黑莓 编程 中需要注 意的各 个方面 ,通 过一个可 以定制 的个性 化的 toolbar 的实 现以及黑 莓应用的 背景的 切换, 来说 明触摸屏 幕编程 和普通 全键 盘手机编 制程序 的区
别。
黑莓标准 的 UI 组件 里面是没 有 toolbar 的,这 里要设计 一个 toolbar ,可 以考虑标 准 UI 组件的 扩展, 这 里我们让 toolbar 继承自 H or iz on ta lF ie ld Ma na ge r . 基本的 toolbar 的 特性包括 排列的方 向和 toolbar 的高 宽等等以 及组件 的排列 性质 。这些都 是可以 配置 的,如果 要做到 一个比 较灵 活的设计 ,这里 我们写 死。
//public class ToolBarField extends HorizontalFieldManager public class ToolBarField extends HorizontalFieldManager
{
//private static final int DefaultButtonHeight = 55;
//private static final int DefaultButtonWidth = 55; private static final int DefaultButtonHeight = 129; private static final int DefaultButtonWidth = 129;
private Vector leftJustifiedButtons = new Vector(); private Vector rightJustifiedButtons = new Vector(); private int preferredHeight = DefaultButtonHeight; private int sideMargin = 3;
private int buttonSpacing = 2;
private int preferredWidth = Display.getWidth();
private Bitmap bg = null;
……
}
在 toolbarfield 类的 设计 中,核心 的部分 在于
private Vector leftJustifiedButtons = new Vector();
private Vector rightJustifiedButtons = new Vector(); 这两个是 为了放 置用户 加入 扩种的具体 field 组件 ,这 里使用的 是标准 的 vector 元素,可 以添加 也可以 删 除组件, 这里我 们简单 起见 ,只实现 添加的 接口, 如下 面的 addbutton 方法 所示 :
public void addButton(ToolBarButtonField button, boolean leftJustified)
{
super.add(button);
if (button.getPreferredHeight() > preferredHeight)
preferredHeight = button.getPreferredHeight();
if (leftJustified)
{
}
else
{
}
}
leftJustifiedButtons.addElement(button);
rightJustifiedButtons.addElement(button);
为了实现 更加可 供定制 化的 效果,可 以扩充 Horizont almanager 的 subpaint 方 法,添加 部分背 景处理
的能力:
protected void subpaint(Graphics graphics)
{
if (bg != null)
{
for (int x = 0; x < Display.getWidth();)
{
}
}
else
{
graphics.drawBitmap(x, 0, getPreferredWidth(), bg.getHeight(), bg, 0, 0);
x += bg.getWidth();
graphics.setColor(Color.BLACK);
graphics.drawRect(0, 0, getPreferredWidth(), getPrefe rredHeight());
}
super.subpaint(graphics);
}
如果所有 的功能 扩充到 这里 ,我们所 设计的 toolbar 也 只是一个 可供全 键盘手 机使 用的版本 ,这里 我们加
入一个新 的 touchevent 方 法, 用来 加入对 触摸屏 幕的 响应 有了 这个方 法,这 个就 是一个专 门针对
touchscreen 的控件版 本 版本:
public boolean touchEvent(TouchEvent event)
{
int eventID = event.getEvent();
if (eventID == TouchEvent.DOWN || eventID == TouchEvent.UP)
{
boolean hit = false; int x = event.getX(1); int y = event.getY(1);
for (int f = 0; f < getFieldCount(); f++)
{
ToolBarButtonField field = (ToolBarButtonField)getField(f);
XYRect ext = field.getExtent();
if (ext.contains(x, y))
{
hit = true;
if (eventID == TouchEvent.UP)
{
}
else
{
}
field.setActive(false);
this.setFocus();
field.setFocus();
field.setActive(true);
invalidate();
break;
}
}
if (!hit && eventID == TouchEvent.UP)
{
this.setFocus();
invalidate();
}
}
return true;
}
基本上 UI 的 展现, 如果把如 上的部分 做完了 ,有了 基本的 UI 的事件 的处理 之后也就 可以了, 系统会 自动对
UI 的布局做 一些调 整,但是 作为一个 标准的 应用组 件, 需要考虑 的是如 何让 UI 的展 现在任何 情况下 都能达 到比较理 想的效 果,那 么就 需要对触 屏手机 的屏幕 视图 方位切换 事件进 行相应 的处 理和考虑 了。
protected void sublayout(int maxWidth, int maxHeight)
{
this.setExtent(maxWidth, getPreferredHeight());
Enumeration iter = leftJustifiedButtons.elements();
if (maxHeight > Display.getHeight())
maxHeight = Display.getHeight();
int y = 0;
int curX = sideMargin;
//
// Layout the left justified buttons
//
while (iter.hasMoreElements())
{
ToolBarButtonField button = (ToolBarButtonField)iter.nextElement();
this.layoutChild(button, button.getPreferredWidth(), button.getPreferredWidth());
this.setPositionChild(button, curX, y);
curX = curX + button.getWidth();
}
int minX = curX + buttonSpacing;
int totalButtonsWidth = 0;
//
// Layout the right justified buttons
//
iter = rightJustifiedButtons.elements();
while (iter.hasMoreElements())
{
ToolBarButtonField button = (ToolBarButtonField)iter.nextElement(); this.layoutChild(button, button.getPreferredWidth(), button.getPreferredWidth()); totalButtonsWidth += button.getWidth() + buttonSpacing;
}
totalButtonsWidth -= buttonSpacing;
if ((totalButtonsWidth+minX) > maxWidth)
{
preferredWidth = totalButtonsWidth+minX;
}
curX = maxWidth;
iter = rightJustifiedButtons.elements();
while (iter.hasMoreElements())
{
ToolBarButtonField button = (ToolBarButtonField)iter.nextElement();
this.layoutChild(button, button.getPreferredWidth(), button.getPreferredWidth());
curX = curX - button.getWidth(); this.setPositionChild(button, curX, y); curX -= buttonSpacing;
}
}
我们这里 以一个 定制的 to o lb ar 组件为例 ,说明 如何 在 BlackBerry 的触摸 屏幕 上响应和 处理屏 幕的转 换
和翻转, 做到 applicatio n 对屏幕的 自适应 能力。 Bl ac kb er ry 标准的屏 幕切换 事件处理 中,是 推荐用 户 在 sublayout 中对页 面组 件的布局 进行相 应的调 整, 上面的方 法中, 也实现 了部 分这样的 功能, 但是并 没 有用到触 屏编程 中需要 考虑 的方位问 题的检 测,所 以并 不完整。
所以下面 我们来 考虑这 个例 子中的一 个比较 好的切 入点 ,对于屏 幕背景 的切换 ,标 准的 blackberry 的 api 中,提供 了 screen 以 及 mainmanager 的 ba ck br ou nd 的背景设 置的 api ,但 是由于种 种原因 是有些 问题,这 里我们 考虑一 种方 法,可以 绕过这 个问题 :
DecorTestScreen screen = new DecorTestScreen(); VerticalFieldManager horizontalFieldManager = new
VerticalFieldManager(VerticalFieldManager.USE_ALL_WIDTH | VerticalFieldManager.USE_ALL_HEIGHT){
//Override the paint method to draw the background image. public void paint(Graphics graphics)
{
graphics.clear();
switch(Display.getOrientation())
{
case Display.ORIENTATION_LANDSCAPE:
graphics.drawBitmap(0, 0, Display.getWidth(), Display.getHeight(), backgroundBitmap, 0, 0);
break;
case Display.ORIENTATION_PORTRAIT:
graphics.drawBitmap(0, 0, Display.getWidth(), Display.getHeight(), backgroundBitmap2, 0, 0);
break;
default:
break;
}
super.paint(graphics);
}
};
screen.setTitle(toolBar);
screen.add(horizontalFieldManager);
这里面使 用的办 法实际 上就 是天面提 到的在 应用中 检测 程序的方 位,然 后重新 绘制 屏幕,只 不过我 们这里 重新绘制 的是屏 幕背景 不是 具体的 ui 组 件,如 果是 ui 组件,更 好的办 法是它 们放 置到 sublayout 方法 中 去通过对 layoutmanag er 的设置。
在完成基 本的屏 幕和 to ol b ar 组件的设 计之后 ,剩下的 就是测试 和验证 这个设 计了 , 我们设计 一个 toolbar 的添 加 button 的类别 ,然后把 这些 button 类别 添加到我 们设计的 toolbar 中,代 码如下:
public class ToolBarButtonField extends ImageButtonField
//class T