三 一個觸摸屏幕應用界面的例子
本章以一個定製的黑莓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加入到屏幕下面來。