best practice to re-order Tabs

50 views
Skip to first unread message

shop.servic...@gmail.com

unread,
May 4, 2019, 8:56:52 PM5/4/19
to CodenameOne Discussions
If you are experiencing an issue please mention the full platform your issue applies to:
IDE: NetBeans/Eclipse/IDEA NetBeans 8.2
Desktop OS Windows 10 Pro
Simulator Latest
Device PC, IOS, Android

I have a requirement to re-order tabs (Move to end, Move before selected Tab etc.) Via list dialog.

I have looked at the various methods, insert, remove, replace

However, after some trial, I don't see a clean simple way to swap tabs.

Thoughts?

Regards

Shai Almog

unread,
May 5, 2019, 12:29:11 AM5/5/19
to CodenameOne Discussions
Didn't have time to try/run this but something like this might work. You'd need to remove and re-add the tab in the right location within the drop listener so the swipe/animation will work.
It relied a bit on the internal structure of the tabs component hierarchy but not too much:

Form hi = new Form("Tabs", new BorderLayout());

Tabs t = new Tabs();

t
.addTab("T1", new Label("Tab 1"));
t
.addTab("T2", new Label("Tab 2"));
t
.addTab("T3", new Label("Tab 3"));
t
.addTab("T4", new Label("Tab 4"));

Container tabsC = t.getTabsContainer();
tabsC
.setDropTarget(true);
for(Component c : tabsC) {
    c
.setDraggable(true);
}

tabsC
.addDropListener(e -> {
   
/// you need to fill this up
});

hi
.add(CENTER, t);

hi
.show();



shop.servic...@gmail.com

unread,
May 6, 2019, 10:07:51 AM5/6/19
to CodenameOne Discussions
Thanks, have been workint this and have the following:

tabsC.addDropListener(e -> {
   
/// you need to fill this up
    I get The Source (e.getDraggedComponent()) and can learn the tabsC index.
    however I can not learn the target index needed to get the underlying component (tabs.getComponentIndex(e.getDropTarget()) returns -1)
   
    Q. Dropping tab 3 to tab 1, I see visually the tab title text has changed position. The underlying RadioButton instance has been swapped.
         however the object inserted in each of the tabs have not been reordered.
         I see your thought on removing and adding the tab in the right location, however I would need to know the dropped index to acomplish this.
         There seems to be an option to use replace (current, next), however I need to learn what the dropped index is.

         Appreciate any help your team can provide.   
        Thanks in advance! 
});

Shai Almog

unread,
May 6, 2019, 11:08:42 PM5/6/19
to CodenameOne Discussions
I thought this would make an interesting blog post so I wrote a full working sample. My initial mock had a mistake in listener registration:

Form hi = new Form("Tabs", new BorderLayout());

Tabs t = new Tabs();

t
.addTab("T1", new Label("Tab 1"));
t
.addTab("T2", new Label("Tab 2"));
t
.addTab("T3", new Label("Tab 3"));
t
.addTab("T4", new Label("Tab 4"));

Container tabsC = t.getTabsContainer();
tabsC
.setDropTarget(true);
for(Component c : tabsC) {
    c
.setDraggable(true);

    c
.addDropListener(e -> {
        e
.consume();
       
Component dragged = c;
       
int x = e.getX();
       
int y = e.getY();
       
int i = tabsC.getComponentIndex(dragged);
       
if(i > -1) {
           
Component dest = tabsC.getComponentAt(x, y);
           
if(dest != dragged) {
               
Component source = t.getTabComponentAt(i);
               
int destIndex = tabsC.getComponentIndex(dest);
               
if(destIndex > -1 && destIndex != i) {
                   
String title = t.getTabTitle(i);
                    t
.removeTabAt(i);
                   
if(destIndex > i) {
                        t
.insertTab(title, null, source, destIndex - 1);
                   
} else {
                        t
.insertTab(title, null, source, destIndex);
                   
}
               
}
           
}
            tabsC
.animateLayout(400);
       
}
   
});
}

hi
.add(CENTER, t);
hi
.show();


shop.servic...@gmail.com

unread,
May 7, 2019, 8:59:05 AM5/7/19
to CodenameOne Discussions
Thanks so much.
That worked perfectly

Regards

shop.servic...@gmail.com

unread,
May 9, 2019, 12:31:36 PM5/9/19
to CodenameOne Discussions
One suggestion as I suspect this was unintended.
When dragging form low index to higher index the dropped index was (dest -1) and for me should be dest idx.

                    if(destIndex > i) {
                        t
.insertTab(title, null, source, destIndex - 1);
                   
} else {
                        t
.insertTab(title, null, source, destIndex);
                   
}

                   should become:
                  t.insertTab(title, null, source, destIndex);

Q. How can we change the drag sensitivity or delay so that when I want to scroll my tab list the dragged listener does not interpret this as a drag request.

Thanks in advance.

Regards

Shai Almog

unread,
May 9, 2019, 11:30:19 PM5/9/19
to CodenameOne Discussions
Drag is from the left most or right most position so this shouldn't impact the normal usage of tab dragging. Do you see an impact of that?

shop.servic...@gmail.com

unread,
May 10, 2019, 8:55:33 AM5/10/19
to CodenameOne Discussions
I try to scroll on extreme edges and 10% of the time it does scroll, however the other 90% the tab DropListener event is triggered.
(then of course I have a unintended reordering that was random as scrolling is generally a vertical swipe (With LEFT Orientation)

For Simple Reference, Attached is a picture of my tabbed component. (Tabs on LEFT Orientation)

What affect does tabsC.animateLayout(400); have?

Thoughts?

Regards.
TabsDragNdrop.PNG

Shai Almog

unread,
May 11, 2019, 12:44:36 AM5/11/19
to CodenameOne Discussions
Why do you have swipe activated for vertical tabs?
Doesn't it make more sense to disable swiping?

shop.servic...@gmail.com

unread,
May 11, 2019, 8:42:21 AM5/11/19
to CodenameOne Discussions
Sorry, I was referring to scrolling and I called my finger action from top to bottom as a swipe. Not sure how else to refer to this action.
I set here:             SubSystemTabs.setSwipeActivated(false);

Is there something else I can do to reduce the sensitivity of DND when I want to scroll the tabs?

Are there demos that I can look at where components in a scrollable pane are also DND enabled.

Thoughts?

Regards

Shai Almog

unread,
May 11, 2019, 11:07:12 PM5/11/19
to CodenameOne Discussions
We just call that scrolling ;-)
There are several solutions for this, one of them is to define a drag region within the component which means only a specific region is swipeable. The other is to have an edit mode, e.g. you can set the draggable to true only when that edit mode is enabled.

shop.servic...@gmail.com

unread,
May 12, 2019, 11:43:09 AM5/12/19
to CodenameOne Discussions
Thanks.
I prefer setting the drag region If I understand this.

Would we set a region like the (LEFT Tabs Orientation, Swiping and scrolling would be top to bottom))  left 1/2 of the Tab component would scroll and the right half would be DND?

How would I accomplish setting drag region? I don't see any method to do this directly.
Also can you give me a visual of the user delineating scroll / dragging region?

Thanks in advance.

Regards.

Shai Almog

unread,
May 12, 2019, 10:50:52 PM5/12/19
to CodenameOne Discussions
No.
Drag region is the area within a component that can be "draggable" that means that if you grab a tab in outside that region it will not drag only if you drag from that area. You usually mark that area with a fuzzy texture marking to indicate that it's something people can touch/drag.

shop.servic...@gmail.com

unread,
May 13, 2019, 8:17:14 AM5/13/19
to CodenameOne Discussions
Thanks.

How does one programmatically set the drag region for a component?

Regards.

Shai Almog

unread,
May 13, 2019, 10:14:35 PM5/13/19
to CodenameOne Discussions
You need to create a custom tab component that has a visual indicator of the region. Then override isDragAndDropOperation(x, y) to return true if a click is within that region.
Reply all
Reply to author
Forward
0 new messages