2011-02-09 31 views
1

我有一个关于BlackBerry VerticalScrollField和滚动的问题,它似乎锁定或使UI不稳定。以下代码是黑莓屏幕,左边是内容世界(位于滚动字段中),右边是跳转栏,允许点击内容。具有跳转点的垂直滚动条 - setVerticalScroll锁定UI

当单击一个跳转字母时,会调用setVerticalScroll方法,它会执行滚动,但会产生令用户界面不稳定或不可用的副作用。滚动调用是在UI线程上完成的,因此它不清楚错误的来源。该应用正在6.0模拟器中测试。

我已经包含了可以复制到BB Eclipse中用于黑客/测试的类。

滚动的那踢部分可以向下面的代码底部找到:

UiApplication.getUiApplication().invokeLater(new Runnable(){ 
    public void run() { 
     scroller.setVerticalScroll(y, true); 
}}); 

下面是完整的类:

 
package test;

import java.util.Vector;

import net.rim.device.api.system.ApplicationManager; import net.rim.device.api.ui.Field; import net.rim.device.api.ui.Font; import net.rim.device.api.ui.Graphics; import net.rim.device.api.ui.TouchEvent; import net.rim.device.api.ui.UiApplication; import net.rim.device.api.ui.component.LabelField; import net.rim.device.api.ui.component.Status; import net.rim.device.api.ui.container.HorizontalFieldManager; import net.rim.device.api.ui.container.MainScreen; import net.rim.device.api.ui.container.VerticalFieldManager;

public class Startup extends UiApplication { private int[] jump; static final String[] words = new String[]{ "auto", "apple", "bear", "car", "farm", "ferret", "gold", "green", "garden", "hedge", "happy", "igloo", "infrared", "jelly", "kangaroo", "lemon", "lion", "marble", "moon", "nine", "opera", "orange", "people", "puppy", "pear", "quince", "race", "run", "sunset", "token", "willow", "zebra" }; private final static String[] alphabet = new String[]{"A","B","C","D","E", "F","G","H","I","J","K","L","M","N","O","P","Q","R", "S","T","U","V","W","X","Y","Z","#"}; private VerticalFieldManager scroller;

public Startup() { UiApplication.getUiApplication().invokeLater(new Runnable() { public void run() { UiApplication.getUiApplication().pushScreen(new ScrollScreen()); } }); } public static void main(String[] args) { ApplicationManager app = ApplicationManager.getApplicationManager(); while (app.inStartup()) { try { Thread.sleep(200); } catch (Throwable e) {} } Startup startup = new Startup(); startup.enterEventDispatcher(); } /** * Screen with content in a scrollbar left and a letters on the right that * can be used to jump into the content. */ class ScrollScreen extends MainScreen { public ScrollScreen() { super(NO_HORIZONTAL_SCROLL | NO_VERTICAL_SCROLL); HorizontalFieldManager hfm = new HorizontalFieldManager(USE_ALL_HEIGHT | NO_VERTICAL_SCROLL | NO_HORIZONTAL_SCROLL){ protected void sublayout(int maxWidth, int maxHeight) { Field scroll = getField(0); Field alpha = getField(1); layoutChild(alpha, maxWidth, maxHeight); layoutChild(scroll, maxWidth-alpha.getWidth(), maxHeight); setPositionChild(scroll, 0, 0); setPositionChild(alpha, maxWidth-alpha.getWidth(), 0); setExtent(maxWidth, maxHeight); } }; hfm.add(createScrollContent()); hfm.add(createAlphabetJumpBar()); add(hfm); } private Field createScrollContent() { Vector vocabulary = new Vector(); for (int ii=0; ii<alphabet.length; ii++) vocabulary.addElement(alphabet[ii]); scroller = new VerticalFieldManager(VERTICAL_SCROLL | USE_ALL_WIDTH) { protected void sublayout(int maxWidth, int maxHeight) { // Record the jump offsets int y = 0; for (int ii=0; ii<getFieldCount(); ii++) { Field field = getField(ii); layoutChild(field, maxWidth, maxHeight); setPositionChild(field, 0, y); if (field instanceof WordField) { WordField object = (WordField)field;; char character = object.getWord().toLowerCase().charAt(0); int offset = ((int)character)-(int)alphabet[0].toLowerCase().charAt(0); if (offset < 0 || offset > jump.length) offset = jump.length-1; while (offset >= 0 && offset < jump.length && jump[offset] == 0) { jump[offset] = y; offset--; } } y += field.getHeight(); } int offset = jump.length-1; do { jump[offset] = y; offset--; } while (offset >= 0 && jump[offset] == 0); setExtent(maxWidth, maxHeight); setVirtualExtent(maxWidth, y+10); } }; jump = new int[alphabet.length]; Font largeFont = Font.getDefault().derive(Font.PLAIN, 46); for (int ii=0; ii<words.length; ii++) { WordField wordField = new WordField(words[ii]); wordField.setFont(largeFont); scroller.add(wordField); } return scroller; } private Field createAlphabetJumpBar() { VerticalFieldManager vfm = new VerticalFieldManager() { protected void sublayout(int maxWidth, int maxHeight) { int y = 0; int width = 0; double allowedAlphaHeight = (double)maxHeight/(double)getFieldCount(); for (int ii=0; ii<getFieldCount(); ii++) { WordField field = (WordField)getField(ii); layoutChild(field, maxWidth, (int)allowedAlphaHeight); setPositionChild(field, 0, y); y += field.getHeight(); double paddedY = Math.floor(allowedAlphaHeight*(ii+1)); if (y < paddedY) y = (int)paddedY; width = Math.max(width, field.getWidth()); } setExtent(width, maxHeight); } }; for (int ii=0; ii<alphabet.length; ii++) { vfm.add(new AlphaField(alphabet[ii]){ protected boolean touchEvent(TouchEvent message) { if (message.getEvent() == TouchEvent.UP) { int startOffset = (int)alphabet[0].charAt(0); int offset = ((int)getWord().charAt(0)) - startOffset; final int y = offset == 0 ? 0 : jump[offset - 1]; UiApplication.getUiApplication().invokeLater(new Runnable(){ public void run() { scroller.setVerticalScroll(y, true); }}); } return true; } }); } return vfm; } class WordField extends LabelField { private final String word; public WordField(String word) { super(word); this.word = word; } public String getWord() { return word; } } Font alphaFont = null; class AlphaField extends WordField { public AlphaField(String word) { super(word); } protected void layout(int width, int height) { if (alphaFont == null) alphaFont = Font.getDefault().derive(Font.PLAIN, height); setExtent(alphaFont.getAdvance(getWord()), alphaFont.getHeight()); } protected void paint(Graphics graphics) { graphics.setFont(alphaFont); graphics.drawText(getWord(), 0, 0); } } /** * For debugging. * @see net.rim.device.api.ui.Screen#keyChar(char, int, int) */ protected boolean keyChar(char c, int status, int time) { if ('o' == c) { // shows the jump offsets into the scroll field UiApplication.getUiApplication().invokeLater(new Runnable(){ public void run() { StringBuffer buf = new StringBuffer(); for (int ii=0; ii<jump.length; ii++) { buf.append(alphabet[ii]+"="+jump[ii]); if (ii<jump.length-1) buf.append(","); } Status.show("offsets="+buf.toString()); }}); } return super.keyChar(c, status, time); } }

}

回答

0

终于追查到了这个问题 - 如果字母标签字段的touchEvent返回true,那么它锁定主滚动字段,但是如果返回super.touchEvent(消息)被调用,滚动发生并且滚动字段仍然可以通过点击屏幕上下滚动。

这可能是BlackBerry OS中的错误,或者只是模拟器。 6.0的Field.touchEvent()文档建议如果该方法消耗该事件,则返回true;但是这样做(至少在上面的代码中)会导致另一个UI字段失去检测触摸事件的能力,这会导致它滚动。

1

你在一些你已经在UI事件线程中使用UiApplication.invokeLater的地方使用UiApplication.invokeLater,所以这些都是多余的 - 在keyChar和setVertica中的调试代码从touchEvent处理程序中调用Scroll调用。当您从UI线程执行invokeLater时,Runnable会同步执行,且不会指定任何延迟。

您确定要显式设置滚动吗?一种选择是通过调用setFocus()将焦点放在您感兴趣的WordField上,然后操作系统将执行滚动事件以在屏幕上为您移动该字段。

如果您确实需要明确设置垂直滚动,您的问题可能是触摸事件已经导致滚动,因此再次设置会导致问题。你可以通过为你的invokeLater(...)指定一个毫秒的延迟来解决这个问题。这意味着您的Runnable将被添加到事件队列中,而不是同步执行。这样,滚动不会在另一个事件调用堆栈的中间更改。

+0

更新代码以使用睡眠的线程,获取事件锁定并滚动结束,结果相同。如果找不到问题的根源,我会尝试使用焦点触发滚动。谢谢你的提示! – Martin 2011-02-09 20:12:14