【问题标题】:Vertical scrollbar with jump points - setVerticalScroll locking UI带有跳转点的垂直滚动条 - setVerticalScroll 锁定 UI
【发布时间】:2011-02-10 05:12:54
【问题描述】:

我有一个关于 BlackBerry VerticalScrollField 和滚动的问题,它似乎锁定或使 UI 不稳定。下面的代码是一个 BlackBerry 屏幕,左边是世界作为内容(在滚动字段中),右边有一个跳转栏,允许点击内容。

当点击一个跳转字母时,setVerticalScroll 方法被调用,它执行滚动,但有一个不幸的副作用是呈现 UI 不稳定或不可用。滚动调用是在 UI 线程上完成的,因此不清楚错误的来源是什么。该应用正在 6.0 模拟器中进行测试。

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

滚动的部分可以在底部找到,代码如下:

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

这是完整的课程:

包装测试;

导入 java.util.Vector;

导入 net.rim.device.api.system.ApplicationManager; 导入 net.rim.device.api.ui.Field; 导入 net.rim.device.api.ui.Font; 导入 net.rim.device.api.ui.Graphics; 导入 net.rim.device.api.ui.TouchEvent; 导入 net.rim.device.api.ui.UiApplication; 导入 net.rim.device.api.ui.component.LabelField; 导入 net.rim.device.api.ui.component.Status; 导入 net.rim.device.api.ui.container.Horizo​​ntalFieldManager; 导入 net.rim.device.api.ui.container.MainScreen; 导入 net.rim.device.api.ui.container.VerticalFieldManager;

公共类启动扩展 UiApplication { 私有 int[] 跳转; 静态最终字符串 [] 单词 = 新字符串 []{ “汽车”、“苹果”、“熊”、“汽车”、“农场”、“雪貂”、“黄金”、 “绿色”、“花园”、“树篱”、“快乐”、“冰屋”、“红外线”、 “果冻”、“袋鼠”、“柠檬”、“狮子”、“大理石”、“月亮”、 “九”、“歌剧”、“橙”、“人”、“小狗”、“梨”、 “木瓜”、“种族”、“奔跑”、“日落”、“令牌”、“柳树”、“斑马” }; 私有最终静态字符串 [] 字母表 = 新字符串 []{"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","#"}; 私有 VerticalFieldManager 滚动条;

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); } }

}

【问题讨论】:

    标签: blackberry scroll


    【解决方案1】:

    您在一些已经在 UI 事件线程上的地方使用 UiApplication.invokeLater,因此这些都是多余的 - keyChar 中的调试代码和来自 touchEvent 处理程序的 setVerticalScroll 调用。当您从 UI 线程执行 invokeLater 时,Runnable 会同步执行,没有指定延迟。

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

    如果你真的需要显式设置垂直滚动,你的问题可能是触摸事件已经引起了滚动,所以再次设置会出现问题。您可以通过为您的 invokeLater(...) 指定一毫秒的延迟来解决此问题。这意味着您的 Runnable 将被添加到事件队列中,而不是同步执行。这样滚动不会在另一个事件调用堆栈的中间发生变化。

    【讨论】:

    • 更新代码以使用睡眠、获取事件锁和滚动的线程最终得到相同的结果。如果找不到问题的根源,我会尝试使用焦点来触发滚动。感谢您的提示!
    • 经过更多试验后,我可以看到即使没有调用滚动方法,单击右侧条时 UI 也会锁定,因此该垂直字段或其子字段可能存在问题; keyChar 方法中的相同滚动逻辑也可以正常工作。
    【解决方案2】:

    终于找到了问题——如果字母标签字段的 touchEvent 返回 true 则它会锁定主滚动字段,但是如果调用 return super.touchEvent(message) 滚动发生并且滚动字段仍然可以通过点击屏幕上下滚动。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多