三 一个触摸屏幕应用界面的例子
本章以一个定制的黑莓UI展示程序为例,说明黑莓编程中需要注意的各个方面,通过一个可以定制的个性化的toolbar的实现以及黑莓应用的背景的切换,来说明触摸屏幕编程和普通全键盘手机编制程序的区别。
黑莓标准的UI组件里面是没有toolbar的,这里要设计一个toolbar,可以考虑标准UI组件的扩展,这里我们让toolbar继承自HorizontalFieldManager.
基本的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)
{
leftJustifiedButtons.addElement(button);
}
else
{
rightJustifiedButtons.addElement(button);
}
}
为了实现更加可供定制化的效果,可以扩充Horizontalmanager的subpaint方法,添加部分背景处理的能力:
protected void subpaint(Graphics graphics)
{
if (bg != null)
{
for (int x = 0; x < Display.getWidth();)
{
graphics.drawBitmap(x, 0, getPreferredWidth(), bg.getHeight(), bg, 0, 0);
x += bg.getWidth();
}
}
else
{
graphics.setColor(Color.BLACK);
graphics.drawRect(0, 0, getPreferredWidth(), getPreferredHeight());
}
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)
{
field.setActive(false);
this.setFocus();
}
else
{
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;
}
}
我们这里以一个定制的toolbar组件为例,说明如何在BlackBerry的触摸屏幕上响应和处理屏幕的转换和翻转,做到application对屏幕的自适应能力。Blackberry标准的屏幕切换事件处理中,是推荐用户在sublayout中对页面组件的布局进行相应的调整,上面的方法中,也实现了部分这样的功能,但是并没有用到触屏编程中需要考虑的方位问题的检测,所以并不完整。
所以下面我们来考虑这个例子中的一个比较好的切入点,对于屏幕背景的切换,标准的blackberry的api中,提供了screen以及mainmanager的backbround的背景设置的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方法中去通过对layoutmanager的设置。
在完成基本的屏幕和toolbar组件的设计之后,剩下的就是测试和验证这个设计了,
我们设计一个toolbar的添加button的类别,然后把这些button类别添加到我们设计的toolbar中,代码如下:
public class ToolBarButtonField extends ImageButtonField
//class ToolBarButtonField extends ImageButtonField
{
//private static final int WIDTH = 55;
//private static final int HEIGHT = 55;
private static final int WIDTH = 128;
private static final int HEIGHT = 128;
int prefWidth = WIDTH;
int prefHeight = HEIGHT;
public ToolBarButtonField(Bitmap focusImage, Bitmap unFocusImage)
{
super(focusImage, unFocusImage, Field.FOCUSABLE);
if (focusImage.getWidth() < WIDTH)
prefWidth = focusImage.getWidth();
if (focusImage.getHeight() < HEIGHT)
prefHeight = focusImage.getHeight();
}
}
在我们应用的主类中,加入如下测试代码:
DecorTestScreen screen = new DecorTestScreen();
ToolBarField toolBar = new ToolBarField();
bgbutton = Bitmap.getBitmapResource("app2.png");
ToolBarButtonField boolbarbutton = new ToolBarButtonField(bgbutton, bgbutton);
bgbutton1 = Bitmap.getBitmapResource("app1.png");
ToolBarButtonField boolbarbutton1 = new ToolBarButtonField(bgbutton1, bgbutton1);
bgbutton2 = Bitmap.getBitmapResource("app3.png");
ToolBarButtonField boolbarbutton2 = new ToolBarButtonField(bgbutton2, bgbutton2);
bgbutton3 = Bitmap.getBitmapResource("app4.png");
ToolBarButtonField boolbarbutton3 = new ToolBarButtonField(bgbutton3, bgbutton3);
toolBar.addButton(boolbarbutton, false);
toolBar.addButton(boolbarbutton1, false);
toolBar.addButton(boolbarbutton2, false);
toolBar.addButton(boolbarbutton3, false);
screen.setTitle(toolBar);
screen.add(horizontalFieldManager);
//screen.setStatus(toolBar);
pushScreen(screen);
通过screen的settitle()方法,就可以把我们新加入的toolbar加入到屏幕上面去,或者通过setStatus,就可以把我们的toolbar加入到屏幕下面来。