2011-02-09 5 views
1

BlackBerry VerticalScrollFieldとUIを不安定にしたりロックしたりするようなスクロールに関する質問があります。次のコードは、ワールドがコンテンツの左側(スクロールフィールド内)にあり、ジャンプバーが右側に移動してコンテンツをクリックできるBlackBerry画面です。ジャンプポイント付き垂直スクロールバー - setVerticalScrollロックUI

ジャンプ文字をクリックすると、setVerticalScrollメソッドが呼び出されますが、スクロールは実行されますが、UIが不安定または使用不能になるという不幸な副作用があります。スクロール呼び出しは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(message)がスクロールされ、スクロールフィールドが画面をクリックして上下にスクロールしてください。

これは、BlackBerry OSまたはシミュレータのバグである可能性があります。 6.0のドキュメントField.touchEvent()は、メソッドがイベントを消費する場合はtrueを返すよう推奨しています。そうすることで(少なくとも上記のコードで)、別のUIフィールドがタッチイベントを検出してスクロールする機能を失う原因となります。

1

あなたがしていますUiApplication.invokeLaterをUIイベントスレッド上のいくつかの場所で使っているので、それらは冗長です - keyCharのデバッグコードとsetVertica touchEventハンドラからの呼び出しをスクロールします。 Runnableは、UIスレッドからinvokeLaterを実行したときに遅延が指定されていないときに同期して実行されます。

スクロールを明示的に設定してもよろしいですか? 1つのオプションは、setFocus()を呼び出すことによって、興味のあるWordFieldにフォーカスを設定することです。その後、OSはスクロールするイベントを実行して、画面上のそのフィールドを移動します。

実際に垂直スクロールを明示的に設定する必要がある場合は、タッチイベントが既にスクロールを引き起こしている可能性があるため、再度設定すると問題が発生する可能性があります。 invokeLater(...)に1ミリ秒の遅延を指定することで、この問題を回避できます。これは、あなたのRunnableが同期して実行されるのではなく、イベントキューに追加されることを意味します。そうすれば、別のイベントコールスタックの途中でスクロールが変更されることはありません。

+0

スリープ状態のスレッドを使用するようにコードを更新すると、イベントロックとスクロールが同じ結果で終了します。問題の原因が見つからない場合は、フォーカスを使用してスクロールをトリガーします。ヒントをありがとう! – Martin

+0

もう少し試してみたら、スクロールメソッドを呼び出さなくても右手のストリップをクリックしたときにUIがロックされ、その垂直なフィールドやその子に問題があることがわかりました。 keyCharメソッドの同じスクロールロジックもうまくいきます。 – Martin

関連する問題