Blackberry: почему drawListRow() вызывается с разными y для ListField и KeywordFilterField
Я пытаюсь переместить приложение с использованием KeywordFilterField на ListField, и я пытаюсь в течение нескольких часов выяснить, почему вызывается метод drawListRow() с разными значениями y - в зависимости от того, какой из этих двух списков я использую:
Если getRowHeight() возвращает 40, тогда значения y будут -
Для KeywordFilterField есть: 0; 40; 80; 120; ... (то есть, как и ожидалось)
Но для Листфилда я вижу: 9; 49; 89; 129; ... (то есть смещение на 9 по некоторым причинам)
Откуда 9? Есть ли в ListField или ListFieldCallback метод, который я мог бы вызвать, чтобы получить это значение? Я просто пытаюсь нарисовать светло-серую линию между элементами списка.
Ниже мой тестовый код и border.png (используется как граница BasicEditField):
package mypackage;
import java.util.*;
import net.rim.device.api.collection.*;
import net.rim.device.api.collection.util.*;
import net.rim.device.api.system.*;
import net.rim.device.api.ui.*;
import net.rim.device.api.ui.component.*;
import net.rim.device.api.ui.container.*;
import net.rim.device.api.ui.decor.*;
import net.rim.device.api.util.*;
public class MyList extends UiApplication {
public static void main(String args[]) {
MyList app = new MyList();
app.enterEventDispatcher();
}
public MyList() {
pushScreen(new MyScreen());
}
}
class MyScreen extends MainScreen {
static final int EXTRA_ROWS = 2;
MyItemList myItems = new MyItemList();
ListField myList = new ListField(EXTRA_ROWS);
Border myBorder = BorderFactory.createBitmapBorder(
new XYEdges(12, 12, 12, 12),
Bitmap.getBitmapResource("border.png"));
Background myBg = BackgroundFactory.createSolidBackground(0x111111);
StringProvider myProvider = new StringProvider("Search");
BasicEditField myFind = new BasicEditField(USE_ALL_WIDTH) {
protected void paint(Graphics g) {
if (getTextLength() == 0) {
g.setColor(Color.LIGHTGRAY);
g.drawText(myProvider.toString(), 0, 0);
}
g.setColor(Color.BLACK);
super.paint(g);
}
};
public MyScreen() {
getMainManager().setBackground(myBg);
myFind.setBorder(myBorder);
setTitle(myFind);
myItems.doAdd(new MyItem(1, "Eins"));
myItems.doAdd(new MyItem(2, "Zwei"));
myItems.doAdd(new MyItem(3, "Drei"));
myItems.doAdd(new MyItem(4, "Vier"));
myList.setCallback(new MyListFieldCallback());
add(myList);
}
private class MyListFieldCallback implements ListFieldCallback {
public void drawListRow(ListField list, Graphics g, int index, int y, int width) {
System.err.println("XXX index=" + index+ ", y=" + y + ", width=" + width);
g.setColor(Color.WHITE);
if (index < EXTRA_ROWS) {
Font i = getFont().derive(Font.ITALIC);
g.setFont(i);
g.drawText("Add Item", 0, y);
return;
}
if (index >= EXTRA_ROWS) {
MyItem item = (MyItem) myItems.getAt(index - EXTRA_ROWS);
g.drawText(item.toString(), 0, y);
g.setColor(0x333333);
// XXX why do I need to subtract 9 here?
g.drawLine(0, y-9, width, y-9);
return;
}
g.drawText(list.getEmptyString(), 0, y);
}
public Object get(ListField list, int index) {
return myItems.getAt(index);
}
public int getPreferredWidth(ListField list) {
return Display.getWidth();
}
public int indexOfList(ListField list, String prefix, int start) {
return 0;
}
}
class MyItemList extends SortedReadableList {
public MyItemList() {
super(new MyItem.MyComparator());
}
protected void doAdd(Object obj) {
super.doAdd(obj);
myList.setSize(size() + EXTRA_ROWS);
}
protected boolean doRemove(Object obj) {
myList.setSize(size() - 1 + EXTRA_ROWS);
return super.doRemove(obj);
}
}
}
class MyItem {
int _num;
String _name;
public MyItem(int num, String name) {
_num = num;
_name = name;
}
public String toString() {
return _num + ": " + _name;
}
static class MyComparator implements Comparator {
public int compare(Object obj1, Object obj2) {
MyItem item1 = (MyItem) obj1;
MyItem item2 = (MyItem) obj2;
return item1.toString().compareTo(item2.toString());
}
}
static class MyProvider implements KeywordProvider {
public String[] getKeywords(Object obj) {
MyItem item = (MyItem) obj;
return new String[]{ Integer.toString(item._num), item._name };
}
}
}
Полученная продукция:
[ 64,890] XXX index=0, y=9, width=360
[ 64,890] XXX index=1, y=49, width=360
[ 64,898] XXX index=2, y=89, width=360
[ 64,898] XXX index=3, y=129, width=360
[ 64,906] XXX index=4, y=169, width=360
[ 64,906] XXX index=5, y=209, width=360
ОБНОВЛЕНИЕ в ответ на jprofitt
Когда я попробую ваше предложение (я использую красный цвет для вашего текста и линий):
if (index >= EXTRA_ROWS) {
MyItem item = (MyItem) myItems.getAt(index - EXTRA_ROWS);
g.drawText(item.toString(), 0, y);
g.setColor(Color.RED);
g.drawText("XXX", 0, y + (list.getRowHeight() - list.getFont().getHeight())/2);
g.setColor(0x333333);
// XXX why do I need to subtract 9 here?
g.drawLine(0, y-9, width, y-9);
g.setColor(Color.RED);
g.drawLine(0, y, width, y);
return;
}
Тогда это на самом деле не работает - потому что синяя линия фокуса не совпадает с вашими предлагаемыми (красными) линиями. Он совпадает с моими (серыми) линиями, что означает, что вам действительно нужно вычесть -9 по некоторым причинам:
Спасибо! Alex
2 ответа
Да, это странное поведение. Я предполагаю, что это что-то особенное для OS 6. Похоже на OS 6 ListField
стал настолько умным, что передает координату Y, уже подготовленную для непосредственного использования при рисовании текста, поэтому вам не нужно выполнять ручной расчет (обычно я рассчитываю Y для рисования текста так же, как предлагает jprofitt). Таким образом, предполагая, что мое предположение верно, я изменил код следующим образом:
if (index >= EXTRA_ROWS) {
MyItem item = (MyItem) myItems.getAt(index - EXTRA_ROWS);
g.drawText(item.toString(), 0, y);
g.setColor(0x333333);
// XXX why do I need to subtract 9 here?
// use the offset instead
int offset = (myList.getRowHeight() - getFont().getHeight()) >> 1;
g.drawLine(0, y - offset, width, y - offset);
return;
}
и работает нормально (проверено на всех размерах шрифта, доступных в настройках устройства).
Хорошо, я верю, что понял это. Что происходит, так это то, что высота строки больше высоты шрифта. Поэтому, когда вы рисуете текст прямо в точке y, вы рисуете его сверху, выровненным по фактической строке. В моем случае высота строки составляла 40, а высота шрифта была 20. Половина этой разницы - это то, куда входил ваш y - 9. Если вы измените вызовы drawText() на это, он должен работать без необходимости что-либо вычитать при рисовании линия:
g.drawText(theString, 0, y + (list.getRowHeight() - list.getFont().getHeight())/2);
Вы можете кэшировать высоту шрифта и высоту строки, чтобы вам не приходилось выполнять вычисления в paint() для эффективности.