Search code examples
blackberryscrollredraw

Blackberry scrolling doesn't redraw fields


I have a very strange problem at the moment.

Basically when I scroll in a screen, the fields don't get redrawn completely or consistently.

I have a Screen (NO_VERTICAL_SCROLL), with a manager as a titlebar. Below that I have a vertical field manager (VERTICAL_SCROLL) with labelfields. When I scroll the vfm one or two lines of the labelfields, which were already visible, get redrawn. The section I'm scrolling down to has absolutely nothing drawn.

I tried invalidate(), and calling doPaint in a scrollchangelistener, but its actually much worse. It results in the titlebar only being partially redrawn.

In the code below I used a custom FontManager, DimenManager, and ImageResourceManager to return values dependent on screen size. I used a custom BitmapButtonField and ClickableLabel in order to change the state of a field when a click is being held in.

public class BaseScreen extends MainScreen implements StringsResource
{
    protected ResourceBundle resources;

    public BaseScreen(long style)
    {
        super(style);

        StandardTitleBar titlebar = new StandardTitleBar();
        titlebar.addSignalIndicator();
        titlebar.addClock();
        titlebar.addNotifications();

        setTitle(titlebar);

        resources = ResourceBundle.getBundle(BUNDLE_ID, BUNDLE_NAME);
    }
}

public class TandCScreen extends BaseScreen
{
    final String copy_text1 = "long text here";
    final String copy_text2 = "even longer text here";

    ColoredLabelField label_title;
    ColoredLabelField label_subtitle;
    ColoredLabelField label1;
    ColoredLabelField label2;
    ClickableLabel label3;

    public TandCScreen()
    {
        super(NO_VERTICAL_SCROLL | NO_VERTICAL_SCROLLBAR);
        label_title = new ColoredLabelField(resources.getString(STRING_APP_NAME), Color.WHITE, DrawStyle.HCENTER | USE_ALL_WIDTH);
        label_title.setBackground(BackgroundFactory.createSolidBackground(0x60223b));
        label_subtitle = new ColoredLabelField(resources.getString(STRING_TANDC_TITLE), 0x58585b, DrawStyle.HCENTER | USE_ALL_WIDTH);

        label1 = new ColoredLabelField(copy_text1, 0x58585b, USE_ALL_WIDTH);
        label2 = new ColoredLabelField("", 0xa7a9ab, USE_ALL_WIDTH);

        label3 = new ClickableLabel("Read more...")
        {
            protected void unclick()
            {
                super.unclick();
                UiApplication.getUiApplication().invokeLater(new Runnable()
                {
                    public void run()
                    {
                        ColoredLabelField label = new ColoredLabelField(copy_text2, 0xa7a9ab, 0);
                        label.setFont(FontManager.body());
                        label.setMargin(0, 0, DimenManager.interField(), 0);
                        label2.getManager().replace(label2, label);
                        label3.getManager().delete(label3);
                    }
                });
            }
        };

        label_title.setFont(FontManager.subtitle());
        label_subtitle.setFont(FontManager.subtitle());
        label1.setFont(FontManager.body());
        label2.setFont(FontManager.body());
        label3.setFont(FontManager.body());

        BitmapButtonField button_accept = new BitmapButtonField(ImageResourceManager.buttonAccept(), ImageResourceManager.buttonAcceptHover(), FIELD_HCENTER)
        {
            protected void click()
            {
                super.click();
                setImage(ImageResourceManager.buttonAcceptSelected());
                setFocusImage(ImageResourceManager.buttonAcceptSelected());
            }

            protected void unclick()
            {
                super.unclick();
                PersistentStoreManager.setTandCAccepted(true);
                UiApplication.getUiApplication().pushScreen(new LoginScreen());
                close();
            }
        };

        BitmapButtonField button_decline = new BitmapButtonField(ImageResourceManager.buttonDecline(), ImageResourceManager.buttonDeclineHover(), FIELD_HCENTER)
        {
            protected void click()
            {
                super.click();
                setImage(ImageResourceManager.buttonDeclineSelected());
                setFocusImage(ImageResourceManager.buttonDeclineSelected());
            }

            protected void unclick()
            {
                super.unclick();
                close();
            }
        };

        int margin = (VariableManager.DISPLAY_WIDTH - button_accept.getPreferredWidth()) / 2;
        // calculate where to put ellipsis
        Font font = label2.getFont();
        int max_length = (VariableManager.DISPLAY_WIDTH - margin * 2) * 2;
        int i = copy_text2.length() - 1;
        while (font.getAdvance(copy_text2.substring(0, i)) + font.getAdvance("...") >= max_length)
            i--;

        label2.setText(copy_text2.substring(0, i).trim() + "...");

        VerticalFieldManager vfm = new VerticalFieldManager(VERTICAL_SCROLL | VERTICAL_SCROLLBAR);
        vfm.add(new NullField());
        vfm.add(label_subtitle);
        vfm.add(new Seperator());
        vfm.add(label1);
        vfm.add(label2);
        vfm.add(label3);
        vfm.add(button_accept);
        vfm.add(button_decline);

        vfm.setMargin(0, margin, 0, margin);

        // paddings
        int padding = (DimenManager.header() - label_title.getPreferredHeight()) / 2;
        label_title.setPadding(padding, 0, padding, 0);
        label_subtitle.setPadding(DimenManager.interField(), 0, DimenManager.interField(), 0);
        label1.setMargin(DimenManager.interField(), 0, DimenManager.interField(), 0);
        label3.setMargin(DimenManager.interField(), 0, DimenManager.interField(), button_accept.getPreferredWidth() - label3.getPreferredWidth());
        button_decline.setMargin(DimenManager.interField(), 0, DimenManager.interButton(), 0);

        add(label_title);
        add(vfm);
    }

    protected boolean onSavePrompt()
    {
        return false;
    }

    protected void makeMenu(Menu menu, int instance)
    {
        if (instance == Menu.INSTANCE_CONTEXT)
        {
            ContextMenu contextMenu = ContextMenu.getInstance();
            contextMenu.setTarget(this);
            contextMenu.clear();
            this.makeContextMenu(contextMenu);
            menu.deleteAll();
            menu.add(contextMenu);
        }
        else
        {
            super.makeMenu(menu, instance);
        }
    }
    protected void makeContextMenu(ContextMenu contextMenu)
    {
    }

    /**
     * Clickable labelfield which changes color on down press, and fires action
     * on release. Action is canceled if touch moves outside field bounds.
     * 
     * @author kevin
     * 
     */
    private class ClickableLabel extends LabelField
    {
        private boolean canceled = true;
        private boolean consumed = false;
        protected boolean pressed = false;

        public ClickableLabel(String label)
        {
            super(label, LabelField.FOCUSABLE | USE_ALL_WIDTH);
            setFont(FontManager.body());
        }

        protected void paint(Graphics g)
        {
            // background
            if (pressed)
            {
                g.setColor(0x2C1721);
            }
            else if (isFocus())
            {
                g.setColor(0x993C6B);
            }
            else
            {
                g.setColor(0x60223B);
            }

            int padding_y = (getPreferredHeight() - getFont().getHeight()) / 2;
            int padding_x = getPaddingLeft();
            g.drawText(getText(), padding_x, padding_y);
        }

        public int getPreferredHeight()
        {
            return ImageResourceManager.highlight().getHeight();
        }

        protected void layout(int width, int height)
        {
            height = getPreferredHeight();
            super.layout(width, height);
            setExtent(width, height);
        }

        // --------- Highlight selected row ---------
        protected void onFocus(int direction)
        {
            super.onFocus(direction);
            invalidate();
        }

        protected void onUnfocus()
        {
            super.onUnfocus();
            invalidate();
        }
        // --------------------------------------------

        protected void drawFocus(Graphics graphics, boolean on)
        {
        }

        /**
         * Called when trackpad pressed, or touchscreen touched
         */
        protected void click()
        {
            pressed = true;
            invalidate();
        }

        /**
         * Called when trackpad released, or touchscreen released
         */
        protected void unclick()
        {
            cancel();
        }

        protected void cancel()
        {
            pressed = false;
            invalidate();
        }

        protected boolean navigationClick(int status, int time)
        {
            if (status != 0)
            {
                if (consumed)
                {
                    consumed = false;
                }
                else
                {
                    click();
                }
            }
            return true;
        }

        protected boolean navigationUnclick(int status, int time)
        {
            if (status != 0)
            {
                if (consumed)
                    consumed = false;
                else
                    unclick();
            }
            return true;
        }

        protected boolean touchEvent(TouchEvent message)
        {
            int x = message.getX(1);
            int y = message.getY(1);
            if (x < 0 || y < 0 || x > getExtent().width || y > getExtent().height)
            {
                // Outside the field
                if (!canceled)
                {
                    cancel();
                }
                canceled = true;
                return false;
            }

            if (message.getEvent() == TouchEvent.UP)
            {

                if (canceled)
                    cancel();
                else
                    unclick();
                consumed = true;

                return true;
            }
            if (message.getEvent() == TouchEvent.DOWN)
            {
                click();
                consumed = true;
                canceled = false;

                return true;
            }

            return super.touchEvent(message);
        }
    }

    private class Seperator extends SeparatorField
    {
        protected void paint(Graphics graphics)
        {
            graphics.setColor(0xa7a9ab);
            super.paint(graphics);
        }
    }
}

Thanks in advance for any suggestions


Solution

  • Found the issue. On the labelfields, there was a setExtent(getPreferredWidth(), getPreferredHeight()); that was reducing the size of the area to redraw. Very stupid mistake.

    Thanks to everyone who tried to help.