Scrollable container scrolling from bottom instead of top

51 views
Skip to first unread message

Bryan Buchanan

unread,
Oct 2, 2016, 12:35:22 AM10/2/16
to CodenameOne Discussions
Suppose I have

Container c = new Container();
c
.setLayout(new BoxLayout(BoxLayout.Y_AXIS));
c
.setScrollableY(true);

and the container is a certain height and takes up some %age of the screen.

Normally if I add stuff

c.add(new Label("B");
c
.add(new Label("C");

the "A" is at the top row of the container and "B" under "A" etc as you add more, eventually there will be a scrollbar and you can scroll down with items always added at the bottom. What I'd like to do is when I add "A", have it displayed at the bottom visible row of the container, then when I add "B", "A" moves up, and "B" is now at the bottom, so as you keep adding things, they are always added/displayed on the bottom row of the container, and things eventually scroll off the top.

Is that doable ?

Diamond

unread,
Oct 2, 2016, 1:22:23 AM10/2/16
to CodenameOne Discussions
Hi,

To achieve that, set your form layout to BorderLayout and place container c at the South Position of the form.

Bryan Buchanan

unread,
Oct 2, 2016, 2:04:47 AM10/2/16
to CodenameOne Discussions
That's not quite what I want.

Within the container (where ever it may be placed on the form), as I add labels to the form, I want the last label added to be at the bottom of the component, with free white space at the top of the container. Normally, as you add components to a container with a BoxLayoutY, they are added to the top with whitespace at the bottom. (Same if you are adding items to a List).

Bryan Buchanan

unread,
Oct 2, 2016, 2:11:51 AM10/2/16
to CodenameOne Discussions
See the attached.

Initially 65 was entered, and displayed on the bottom, then 21 which also displayed on the bottom, which pushed 65 up, etc.

test.png

Diamond

unread,
Oct 2, 2016, 2:23:17 AM10/2/16
to CodenameOne Discussions
Hi,

That's not possible without wrapping BoxLayout-Y with a BorderLayout Container and having c at the South position.

White space will still be at the top since BorderLayout fills whole screen height and the BoxLayout-Y will become scrollable when the screen height is filled up by it's content.

Container c = new Container(BoxLayout.y());
c.setScrollableY(true);

Container wrapper = BorderLayout.south(c);

Then wherever you initially placed container c, replace it with wrapper and continue adding your labels to c

Bryan Buchanan

unread,
Oct 2, 2016, 4:02:52 AM10/2/16
to CodenameOne Discussions
That won't do it. All that will do is position the container. What I really want is to reverse the scrolling behaviour - instead of components being added to the top of the container and moving down (and getting a scroll bar when the container is "full"), I want components to be added from the bottom and move up.

Diamond

unread,
Oct 2, 2016, 6:42:41 AM10/2/16
to CodenameOne Discussions
Hi,

Is that an assumption or you've tried it and it doesn't work for you?

From the explanation of what you are trying to achieve, the first component appears at the bottom...a new one pushes it up a little... and a newer one pushes the new one up...continuously until the first element "65" reaches the top and c container becomes scrollable.

Diamond

unread,
Oct 2, 2016, 7:08:20 AM10/2/16
to CodenameOne Discussions
If you want the whole content to occupy a certain percentage of the screen height and never go beyond and become scrollable. Place the wrapper in another wrapper that has a TableLayout. 

For example, we want it to occupy 40% max:

Container c = new Container(BoxLayout.y());
c.setScrollableY(true);

TableLayout tl = new TableLayout(2, 1);
Constraint constraint = tl.createConstraint();
constraint.setHeightPercentage(60);
                
Container wrapper = new Container(tl);
wrapper.add(constraint, new Label(" ")).add(BorderLayout.south(c)); // Label is a placeholder to occupy the top 60% and leave the remaining 40% for your c container and its shell

Bryan Buchanan

unread,
Oct 2, 2016, 8:16:37 AM10/2/16
to CodenameOne Discussions


On Sunday, October 2, 2016 at 8:42:41 PM UTC+10, Diamond wrote:
Hi,

Is that an assumption or you've tried it and it doesn't work for you?

Tried and didn't work.
 

From the explanation of what you are trying to achieve, the first component appears at the bottom...a new one pushes it up a little... and a newer one pushes the new one up...continuously until the first element "65" reaches the top and c container becomes scrollable

Correct - it's exactly the opposite to the behaviour of adding stuff to a list or whatever - instead of adding down, you add by pushing up.
 
.

Bryan Buchanan

unread,
Oct 2, 2016, 8:18:04 AM10/2/16
to CodenameOne Discussions
I set it to a fixed size:

class MyContainerTop extends Container {

       
MyContainerTop(Layout s) {
           
super(s);
       
}

       
@Override
       
public Dimension calcPreferredSize() {

           
int h = Display.getInstance().convertToPixels(SIZE, false);

           
Dimension d = super.calcPreferredSize();
            d
.setHeight(h);

           
return d;
       
}
   
}

Shai Almog

unread,
Oct 2, 2016, 11:24:55 PM10/2/16
to CodenameOne Discussions
I think you will need to create your own layout manager to do this. Normally this wouldn't be a problem but the scrolling behavior when the total grows would be a problem.

You can keep focus on the bottom by scrollComponentToVisible() or requestFocus().

I would suggest just copying the code of BoxLayout and starting from that point as the only change you need to make is laying out from the bottom upwards, you can also discard all the logic related to X layout etc.

Bryan Buchanan

unread,
Oct 3, 2016, 1:53:07 AM10/3/16
to CodenameOne Discussions
OK, I'll try that. But before I do, I need to solve a problem with scrolling.

On the form, I have two containers, and they each set their size like this:

    static final int SIZE = 25; // DIPS ~ 1mm/dip

   
/**
     * sets size of container at top of screen
     */


   
/**
     * sets size of container at bottom of screen
     */

   
class MyContainerBottom extends Container {

       
MyContainerBottom(Layout s) {

           
super(s);
       
}

       
@Override
       
public Dimension calcPreferredSize() {


           
int h = MyForm.this.getHeight() - Display.getInstance().convertToPixels(SIZE, false);
            h
-= MyForm.this.getToolbar().getPreferredH();


           
Dimension d = super.calcPreferredSize();
            d
.setHeight(h);

           
return d;
       
}
   
}

This lays out the top component, which is initially just an empty Container with a border to which Labels will be added.

The bottom component contains a bunch of buttons and stuff. This all works fine and renders correctly on different devices. However, as I add Labels, the top container doesn't scroll - they disappear off the bottom of the container. A scrollbar momentarily appears but vanishes.

        result = new MyContainerTop(new BoxLayout(BoxLayout.Y_AXIS));
        result
.setScrollableY(true);
        result
.setUIID("BorderContainer");

        form.add(result);
        form
.add(bottom_container);

What am I doing wrong ?

Bryan Buchanan

unread,
Oct 3, 2016, 10:15:16 PM10/3/16
to CodenameOne Discussions
Solved this.

Changed the form layout to TableLayout, removed the extended container classes, and added the components to the form with:

        int h = 100 * Display.getInstance().convertToPixels(SIZE, false) / MyForm.this.getHeight();
        add
(layout.createConstraint().heightPercentage(h), result);
        add
(layout.createConstraint().heightPercentage(100-h), f);

Scrolling now works, and the relative sizes are just what I wanted.

Now see if I can get the upside-down scrolling to work :)

Reply all
Reply to author
Forward
0 new messages