SlideShare a Scribd company logo
1 of 28
Download to read offline
Creating an Uber Clone - Part IX
The “Where to?” UI is a pretty big piece of the puzzle and it also includes the navigation UI which is the bottom portion
Destination UI
© Codename One 2017 all rights reserved
Up until now we focused on this part of the toolbar area
Destination UI
© Codename One 2017 all rights reserved
Now we need to do this portion. The destination UI toggle is a huge part of the navigation UI. It's the bottom section of the form that contains the list of destinations. We
can build it on top of the code we wrote for the navigation UI and place it in the center of the layer so it will play nicely with the rest of the UI.
Destination UI
© Codename One 2017 all rights reserved
For now I’ll ignore this potion as it’s mostly a specialization of other things and can be done relatively easily if you understand the rest of the things I did
private void showToNavigationBar(Container parentLayer) {
MultiButton addHome = new MultiButton("Add Home");
addHome.setUIID("Container");
addHome.setUIIDLine1("WhereToButtonLine1");
addHome.setIconUIID("WhereToButtonIcon");
FontImage.setMaterialIcon(addHome, FontImage.MATERIAL_HOME);
MultiButton addWork = new MultiButton("Add Work");
addWork.setUIID("Container");
addWork.setUIIDLine1("WhereToButtonLine1");
addWork.setIconUIID("WhereToButtonIcon");
FontImage.setMaterialIcon(addWork, FontImage.MATERIAL_WORK);
MultiButton savedPlaces = new MultiButton("Saved Places");
savedPlaces.setUIID("Container");
savedPlaces.setUIIDLine1("WhereToButtonLineNoBorder");
savedPlaces.setEmblemUIID("WhereToButtonLineNoBorder");
savedPlaces.setIconUIID("WhereToButtonIcon");
savedPlaces.setEmblem(FontImage.createMaterial(
FontImage.MATERIAL_NAVIGATE_NEXT,
savedPlaces.getIconComponent().getUnselectedStyle()));
FontImage.setMaterialIcon(savedPlaces,
FontImage.MATERIAL_STAR_BORDER);
Destination UI
Let’s jump right in to the “showNavigationBar” method.

The top elements are relatively simple multi-buttons, we use Container as their UIID so they will be transparent with 0 padding/margin.
savedPlaces.setEmblem(FontImage.createMaterial(
FontImage.MATERIAL_NAVIGATE_NEXT,
savedPlaces.getIconComponent().getUnselectedStyle()));
FontImage.setMaterialIcon(savedPlaces,
FontImage.MATERIAL_STAR_BORDER);
Label whereSeparator = new Label("", "WhereSeparator");
whereSeparator.setShowEvenIfBlank(true);
MultiButton history1 = new MultiButton("Mikve Yisrael Str...");
history1.setUIID("Container");
history1.setUIIDLine1("WhereToButtonLine1");
history1.setIconUIID("WhereToButtonIcon");
FontImage.setMaterialIcon(history1, FontImage.MATERIAL_HISTORY);
Container result = BoxLayout.encloseY(addHome, addWork,
savedPlaces, whereSeparator, history1);
result.setUIID("Form");
result.setScrollableY(true);
result.setScrollVisible(false);
result.setY(getDisplayHeight());
Destination UI
The separator is just a label with a specific style. Notice that blank labels/buttons etc. are hidden by default in Codename One and you should invoke
setShowEvenIfBlank if you want such a label to still render
savedPlaces.setEmblem(FontImage.createMaterial(
FontImage.MATERIAL_NAVIGATE_NEXT,
savedPlaces.getIconComponent().getUnselectedStyle()));
FontImage.setMaterialIcon(savedPlaces,
FontImage.MATERIAL_STAR_BORDER);
Label whereSeparator = new Label("", "WhereSeparator");
whereSeparator.setShowEvenIfBlank(true);
MultiButton history1 = new MultiButton("Mikve Yisrael Str...");
history1.setUIID("Container");
history1.setUIIDLine1("WhereToButtonLine1");
history1.setIconUIID("WhereToButtonIcon");
FontImage.setMaterialIcon(history1, FontImage.MATERIAL_HISTORY);
Container result = BoxLayout.encloseY(addHome, addWork,
savedPlaces, whereSeparator, history1);
result.setUIID("Form");
result.setScrollableY(true);
result.setScrollVisible(false);
result.setY(getDisplayHeight());
Destination UI
We can reuse the Form UIID here because that's effectively what we want. We want this UI to appear as if it's a Form
savedPlaces.setEmblem(FontImage.createMaterial(
FontImage.MATERIAL_NAVIGATE_NEXT,
savedPlaces.getIconComponent().getUnselectedStyle()));
FontImage.setMaterialIcon(savedPlaces,
FontImage.MATERIAL_STAR_BORDER);
Label whereSeparator = new Label("", "WhereSeparator");
whereSeparator.setShowEvenIfBlank(true);
MultiButton history1 = new MultiButton("Mikve Yisrael Str...");
history1.setUIID("Container");
history1.setUIIDLine1("WhereToButtonLine1");
history1.setIconUIID("WhereToButtonIcon");
FontImage.setMaterialIcon(history1, FontImage.MATERIAL_HISTORY);
Container result = BoxLayout.encloseY(addHome, addWork,
savedPlaces, whereSeparator, history1);
result.setUIID("Form");
result.setScrollableY(true);
result.setScrollVisible(false);
result.setY(getDisplayHeight());
Destination UI
We need this to be scrollable but we don't want the scrollbar on the side as it might cause aesthetic issues
Label whereSeparator = new Label("", "WhereSeparator");
whereSeparator.setShowEvenIfBlank(true);
MultiButton history1 = new MultiButton("Mikve Yisrael Str...");
history1.setUIID("Container");
history1.setUIIDLine1("WhereToButtonLine1");
history1.setIconUIID("WhereToButtonIcon");
FontImage.setMaterialIcon(history1, FontImage.MATERIAL_HISTORY);
Container result = BoxLayout.encloseY(addHome, addWork,
savedPlaces, whereSeparator, history1);
result.setUIID("Form");
result.setScrollableY(true);
result.setScrollVisible(false);
result.setY(getDisplayHeight());
result.setWidth(getDisplayWidth());
result.setHeight(result.getPreferredH());
parentLayer.add(CENTER, result);
parentLayer.animateLayout(200);
}
Destination UI
The showing of this element is animated from the bottom of the Form
WhereToButtonLine1
© Codename One 2017 all rights reserved
While this UI is very simple it did define a few UIID's. Let's start with WhereToButtonLine1 which represents the entries in the list of elements and also adds the underline.
The color is just black over transparent which in this case leads to white
WhereToButtonLine1
© Codename One 2017 all rights reserved
The padding on the left side is relatively low since the icon will take the extra padding. On the other sides we have typical 4 millimeter padding
WhereToButtonLine1
© Codename One 2017 all rights reserved
Margin is 0 as usual
WhereToButtonLine1
© Codename One 2017 all rights reserved
We put the underline here because the design placed the underline only under the text and didn't place it under the icon which has a different UIID. The underline is a
gray 2 pixel high line
WhereToButtonLine1
© Codename One 2017 all rights reserved
The font is the standard 3 millimeter light font
WhereToButtonIcon
© Codename One 2017 all rights reserved
The WhereToButtonIcon style applies to the icon which has less horizontal padding so it won’t drift too far from the text but identical vertical padding so it will align
properly with the text
WhereToButtonIcon
© Codename One 2017 all rights reserved
It derives from WhereToButtonLine1 so they will fit together well
WhereToButtonNoBorder
© Codename One 2017 all rights reserved
We need the no border version of the style so it will remove the underline border on the last entry. Otherwise we can see an out of place underline in that one last entry in
the list
WhereToButtonNoBorder
© Codename One 2017 all rights reserved
We derive from the same style so everything else is identical
WhereSeparator
© Codename One 2017 all rights reserved
The WhereSeparator is just a gray padded line, so it has the right gray color and is completely opaque with no background transparency.
WhereSeparator
© Codename One 2017 all rights reserved
It’s exactly 2 millimeters tall so it will stand out but won’t take out an entire line.
WhereSeparator
© Codename One 2017 all rights reserved
Margin is 0 so it can reach the edge of the parent container
from.addFocusListener(new FocusListener() {
public void focusGained(Component cmp) {
fromSelected.setIcon(square);
if(layer.getComponentCount() > 1) {
Component c = layer.getComponentAt(1);
c.setY(getDisplayHeight());
layer.animateUnlayout(200, 150, () -> {
c.remove();
revalidate();
});
}
}
public void focusLost(Component cmp) {
fromSelected.setIcon(circle);
}
});
to.addFocusListener(new FocusListener() {
public void focusGained(Component cmp) {
fromSelected.setIcon(circle);
toSelected.setIcon(square);
showToNavigationBar(layer);
}
public void focusLost(Component cmp) {
toSelected.setIcon(circle);
}
});
Focus Listener
Now that we added this we need to show this UI and hide it when the user toggles the focus in the text fields. We can do this by binding focus listeners to the to and
from text fields.

When focus is lost/gained we toggle between the square and circle modes by setting the icon to the appropriate labels
from.addFocusListener(new FocusListener() {
public void focusGained(Component cmp) {
fromSelected.setIcon(square);
if(layer.getComponentCount() > 1) {
Component c = layer.getComponentAt(1);
c.setY(getDisplayHeight());
layer.animateUnlayout(200, 150, () -> {
c.remove();
revalidate();
});
}
}
public void focusLost(Component cmp) {
fromSelected.setIcon(circle);
}
});
to.addFocusListener(new FocusListener() {
public void focusGained(Component cmp) {
fromSelected.setIcon(circle);
toSelected.setIcon(square);
showToNavigationBar(layer);
}
public void focusLost(Component cmp) {
toSelected.setIcon(circle);
}
});
Focus Listener
We always have one container in the layer except for the case where the second component is the where to container. It's always the second component because it's
always added last.
from.addFocusListener(new FocusListener() {
public void focusGained(Component cmp) {
fromSelected.setIcon(square);
if(layer.getComponentCount() > 1) {
Component c = layer.getComponentAt(1);
c.setY(getDisplayHeight());
layer.animateUnlayout(200, 150, () -> {
c.remove();
revalidate();
});
}
}
public void focusLost(Component cmp) {
fromSelected.setIcon(circle);
}
});
to.addFocusListener(new FocusListener() {
public void focusGained(Component cmp) {
fromSelected.setIcon(circle);
toSelected.setIcon(square);
showToNavigationBar(layer);
}
public void focusLost(Component cmp) {
toSelected.setIcon(circle);
}
});
Focus Listener
We set the position of this container below the forms
from.addFocusListener(new FocusListener() {
public void focusGained(Component cmp) {
fromSelected.setIcon(square);
if(layer.getComponentCount() > 1) {
Component c = layer.getComponentAt(1);
c.setY(getDisplayHeight());
layer.animateUnlayout(200, 150, () -> {
c.remove();
revalidate();
});
}
}
public void focusLost(Component cmp) {
fromSelected.setIcon(circle);
}
});
to.addFocusListener(new FocusListener() {
public void focusGained(Component cmp) {
fromSelected.setIcon(circle);
toSelected.setIcon(square);
showToNavigationBar(layer);
}
public void focusLost(Component cmp) {
toSelected.setIcon(circle);
}
});
Focus Listener
Animate "unlayout" moves the component outside of the screen to the position we asked for using a smooth animation
from.addFocusListener(new FocusListener() {
public void focusGained(Component cmp) {
fromSelected.setIcon(square);
if(layer.getComponentCount() > 1) {
Component c = layer.getComponentAt(1);
c.setY(getDisplayHeight());
layer.animateUnlayout(200, 150, () -> {
c.remove();
revalidate();
});
}
}
public void focusLost(Component cmp) {
fromSelected.setIcon(circle);
}
});
to.addFocusListener(new FocusListener() {
public void focusGained(Component cmp) {
fromSelected.setIcon(circle);
toSelected.setIcon(square);
showToNavigationBar(layer);
}
public void focusLost(Component cmp) {
toSelected.setIcon(circle);
}
});
Focus Listener
This callback is invoked when the unlayout completes. At this point we have an invalid UI that needs a layout but before we do that we remove the component that we
animated out of the form
back.addActionListener(e -> {
navigationToolbar.setY(-navigationToolbar.getHeight());
if(layer.getComponentCount() > 1) {
layer.getComponentAt(1).setY(getDisplayHeight());
}
navigationToolbar.getParent().animateUnlayout(200, 120, () -> {
layer.removeAll();
revalidate();
});
});
Back
Now that the UI appears we also need to remove it when going back so I'll update the back action listener from above to handle the "Where to?" UI as well.

This is the exact same unlayout operation we did before
navigationToolbar.getUnselectedStyle().setBgPainter((g1, rect) -> {
g1.setAlpha(255);
g1.setColor(0xffffff);
if(dropShadow != null) {
if(layer.getComponentCount() > 1) {
g1.fillRect(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
}
g1.drawImage(dropShadow, rect.getX(), rect.getY() +
rect.getHeight() - dropShadow.getHeight(), rect.getWidth(),
dropShadow.getHeight());
g1.fillRect(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight() -
dropShadow.getHeight() / 2);
} else {
g1.fillRect(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
}
g1.setColor(0xa4a4ac);
g1.setAntiAliased(true);
int x = fromSelected.getAbsoluteX() + fromSelected.getWidth() / 2 - 1;
int y = fromSelected.getAbsoluteY() + fromSelected.getHeight() / 2 +
circle.getHeight() / 2;
g1.fillRect(x, y, 2, toSelected.getAbsoluteY() - y +
toSelected.getHeight() / 2 - circle.getHeight() / 2);
});
Background Painter
And finally we need to make a subtle but important change to the background painter code from before. 

Because of the drop shadow a gap is formed between the top and bottom pieces so a special case here paints a white rectangle under the shadow to hide the gap.
Without that the shadow would appear on top of the map and not on top of a white background.

Once this is done opening the "Where To?" UI and toggling the fields should work as expected.

More Related Content

Similar to Creating an Uber Clone - Part IX - Transcript.pdf

Animations - Part 1 - Transcript.pdf
Animations - Part 1 - Transcript.pdfAnimations - Part 1 - Transcript.pdf
Animations - Part 1 - Transcript.pdfShaiAlmog1
 
Style vs. Content and Clean Theming in iOS
Style vs. Content and Clean Theming in iOSStyle vs. Content and Clean Theming in iOS
Style vs. Content and Clean Theming in iOSKeith Norman
 
Mobile Application Development with JUCE and Native API’s
Mobile Application Development with JUCE and Native API’sMobile Application Development with JUCE and Native API’s
Mobile Application Development with JUCE and Native API’sAdam Wilson
 
Swingpre 150616004959-lva1-app6892
Swingpre 150616004959-lva1-app6892Swingpre 150616004959-lva1-app6892
Swingpre 150616004959-lva1-app6892renuka gavli
 
Swing and AWT in java
Swing and AWT in javaSwing and AWT in java
Swing and AWT in javaAdil Mehmoood
 
Creating an Uber Clone - Part IX.pdf
Creating an Uber Clone - Part IX.pdfCreating an Uber Clone - Part IX.pdf
Creating an Uber Clone - Part IX.pdfShaiAlmog1
 
Keynote + Next Gen UIs.pptx
Keynote + Next Gen UIs.pptxKeynote + Next Gen UIs.pptx
Keynote + Next Gen UIs.pptxEqraKhattak
 
Creating an Uber Clone - Part IV - Transcript.pdf
Creating an Uber Clone - Part IV - Transcript.pdfCreating an Uber Clone - Part IV - Transcript.pdf
Creating an Uber Clone - Part IV - Transcript.pdfShaiAlmog1
 
Abstract Window Toolkit
Abstract Window ToolkitAbstract Window Toolkit
Abstract Window ToolkitRutvaThakkar1
 
Top Tips for Android UIs - Getting the Magic on Tablets
Top Tips for Android UIs - Getting the Magic on TabletsTop Tips for Android UIs - Getting the Magic on Tablets
Top Tips for Android UIs - Getting the Magic on TabletsMotorola Mobility - MOTODEV
 
Adapting to Tablets and Desktops - Part 1 - Transcript.pdf
Adapting to Tablets and Desktops - Part 1 - Transcript.pdfAdapting to Tablets and Desktops - Part 1 - Transcript.pdf
Adapting to Tablets and Desktops - Part 1 - Transcript.pdfShaiAlmog1
 
Tips & tricks for sharing C# code on iOS, Android and Windows Phone by Jaime ...
Tips & tricks for sharing C# code on iOS, Android and Windows Phone by Jaime ...Tips & tricks for sharing C# code on iOS, Android and Windows Phone by Jaime ...
Tips & tricks for sharing C# code on iOS, Android and Windows Phone by Jaime ....NET Conf UY
 
Programming iOS in C#
Programming iOS in C#Programming iOS in C#
Programming iOS in C#Frank Krueger
 
CS6611 Mobile Application Development Lab Manual-2018-19
CS6611 Mobile Application Development Lab Manual-2018-19CS6611 Mobile Application Development Lab Manual-2018-19
CS6611 Mobile Application Development Lab Manual-2018-19Gobinath Subramaniam
 
Guice tutorial
Guice tutorialGuice tutorial
Guice tutorialAnh Quân
 

Similar to Creating an Uber Clone - Part IX - Transcript.pdf (20)

Animations - Part 1 - Transcript.pdf
Animations - Part 1 - Transcript.pdfAnimations - Part 1 - Transcript.pdf
Animations - Part 1 - Transcript.pdf
 
Style vs. Content and Clean Theming in iOS
Style vs. Content and Clean Theming in iOSStyle vs. Content and Clean Theming in iOS
Style vs. Content and Clean Theming in iOS
 
Mobile Application Development with JUCE and Native API’s
Mobile Application Development with JUCE and Native API’sMobile Application Development with JUCE and Native API’s
Mobile Application Development with JUCE and Native API’s
 
Swingpre 150616004959-lva1-app6892
Swingpre 150616004959-lva1-app6892Swingpre 150616004959-lva1-app6892
Swingpre 150616004959-lva1-app6892
 
Swing and AWT in java
Swing and AWT in javaSwing and AWT in java
Swing and AWT in java
 
Creating an Uber Clone - Part IX.pdf
Creating an Uber Clone - Part IX.pdfCreating an Uber Clone - Part IX.pdf
Creating an Uber Clone - Part IX.pdf
 
Keynote + Next Gen UIs.pptx
Keynote + Next Gen UIs.pptxKeynote + Next Gen UIs.pptx
Keynote + Next Gen UIs.pptx
 
Creating an Uber Clone - Part IV - Transcript.pdf
Creating an Uber Clone - Part IV - Transcript.pdfCreating an Uber Clone - Part IV - Transcript.pdf
Creating an Uber Clone - Part IV - Transcript.pdf
 
Abstract Window Toolkit
Abstract Window ToolkitAbstract Window Toolkit
Abstract Window Toolkit
 
Top Tips for Android UIs - Getting the Magic on Tablets
Top Tips for Android UIs - Getting the Magic on TabletsTop Tips for Android UIs - Getting the Magic on Tablets
Top Tips for Android UIs - Getting the Magic on Tablets
 
Swift
SwiftSwift
Swift
 
Chapter - 6.pptx
Chapter - 6.pptxChapter - 6.pptx
Chapter - 6.pptx
 
Adapting to Tablets and Desktops - Part 1 - Transcript.pdf
Adapting to Tablets and Desktops - Part 1 - Transcript.pdfAdapting to Tablets and Desktops - Part 1 - Transcript.pdf
Adapting to Tablets and Desktops - Part 1 - Transcript.pdf
 
iOS UI best practices
iOS UI best practicesiOS UI best practices
iOS UI best practices
 
Tips & tricks for sharing C# code on iOS, Android and Windows Phone by Jaime ...
Tips & tricks for sharing C# code on iOS, Android and Windows Phone by Jaime ...Tips & tricks for sharing C# code on iOS, Android and Windows Phone by Jaime ...
Tips & tricks for sharing C# code on iOS, Android and Windows Phone by Jaime ...
 
Programming iOS in C#
Programming iOS in C#Programming iOS in C#
Programming iOS in C#
 
CS6611 Mobile Application Development Lab Manual-2018-19
CS6611 Mobile Application Development Lab Manual-2018-19CS6611 Mobile Application Development Lab Manual-2018-19
CS6611 Mobile Application Development Lab Manual-2018-19
 
Google GIN
Google GINGoogle GIN
Google GIN
 
Guice tutorial
Guice tutorialGuice tutorial
Guice tutorial
 
Advanced iOS
Advanced iOSAdvanced iOS
Advanced iOS
 

More from ShaiAlmog1

The Duck Teaches Learn to debug from the masters. Local to production- kill ...
The Duck Teaches  Learn to debug from the masters. Local to production- kill ...The Duck Teaches  Learn to debug from the masters. Local to production- kill ...
The Duck Teaches Learn to debug from the masters. Local to production- kill ...ShaiAlmog1
 
create-netflix-clone-06-client-ui.pdf
create-netflix-clone-06-client-ui.pdfcreate-netflix-clone-06-client-ui.pdf
create-netflix-clone-06-client-ui.pdfShaiAlmog1
 
create-netflix-clone-01-introduction_transcript.pdf
create-netflix-clone-01-introduction_transcript.pdfcreate-netflix-clone-01-introduction_transcript.pdf
create-netflix-clone-01-introduction_transcript.pdfShaiAlmog1
 
create-netflix-clone-02-server_transcript.pdf
create-netflix-clone-02-server_transcript.pdfcreate-netflix-clone-02-server_transcript.pdf
create-netflix-clone-02-server_transcript.pdfShaiAlmog1
 
create-netflix-clone-04-server-continued_transcript.pdf
create-netflix-clone-04-server-continued_transcript.pdfcreate-netflix-clone-04-server-continued_transcript.pdf
create-netflix-clone-04-server-continued_transcript.pdfShaiAlmog1
 
create-netflix-clone-01-introduction.pdf
create-netflix-clone-01-introduction.pdfcreate-netflix-clone-01-introduction.pdf
create-netflix-clone-01-introduction.pdfShaiAlmog1
 
create-netflix-clone-03-server.pdf
create-netflix-clone-03-server.pdfcreate-netflix-clone-03-server.pdf
create-netflix-clone-03-server.pdfShaiAlmog1
 
create-netflix-clone-04-server-continued.pdf
create-netflix-clone-04-server-continued.pdfcreate-netflix-clone-04-server-continued.pdf
create-netflix-clone-04-server-continued.pdfShaiAlmog1
 
create-netflix-clone-05-client-model_transcript.pdf
create-netflix-clone-05-client-model_transcript.pdfcreate-netflix-clone-05-client-model_transcript.pdf
create-netflix-clone-05-client-model_transcript.pdfShaiAlmog1
 
create-netflix-clone-03-server_transcript.pdf
create-netflix-clone-03-server_transcript.pdfcreate-netflix-clone-03-server_transcript.pdf
create-netflix-clone-03-server_transcript.pdfShaiAlmog1
 
create-netflix-clone-02-server.pdf
create-netflix-clone-02-server.pdfcreate-netflix-clone-02-server.pdf
create-netflix-clone-02-server.pdfShaiAlmog1
 
create-netflix-clone-05-client-model.pdf
create-netflix-clone-05-client-model.pdfcreate-netflix-clone-05-client-model.pdf
create-netflix-clone-05-client-model.pdfShaiAlmog1
 
Creating a Whatsapp Clone - Part II.pdf
Creating a Whatsapp Clone - Part II.pdfCreating a Whatsapp Clone - Part II.pdf
Creating a Whatsapp Clone - Part II.pdfShaiAlmog1
 
Creating a Whatsapp Clone - Part IX - Transcript.pdf
Creating a Whatsapp Clone - Part IX - Transcript.pdfCreating a Whatsapp Clone - Part IX - Transcript.pdf
Creating a Whatsapp Clone - Part IX - Transcript.pdfShaiAlmog1
 
Creating a Whatsapp Clone - Part II - Transcript.pdf
Creating a Whatsapp Clone - Part II - Transcript.pdfCreating a Whatsapp Clone - Part II - Transcript.pdf
Creating a Whatsapp Clone - Part II - Transcript.pdfShaiAlmog1
 
Creating a Whatsapp Clone - Part V - Transcript.pdf
Creating a Whatsapp Clone - Part V - Transcript.pdfCreating a Whatsapp Clone - Part V - Transcript.pdf
Creating a Whatsapp Clone - Part V - Transcript.pdfShaiAlmog1
 
Creating a Whatsapp Clone - Part IV - Transcript.pdf
Creating a Whatsapp Clone - Part IV - Transcript.pdfCreating a Whatsapp Clone - Part IV - Transcript.pdf
Creating a Whatsapp Clone - Part IV - Transcript.pdfShaiAlmog1
 
Creating a Whatsapp Clone - Part IV.pdf
Creating a Whatsapp Clone - Part IV.pdfCreating a Whatsapp Clone - Part IV.pdf
Creating a Whatsapp Clone - Part IV.pdfShaiAlmog1
 
Creating a Whatsapp Clone - Part I - Transcript.pdf
Creating a Whatsapp Clone - Part I - Transcript.pdfCreating a Whatsapp Clone - Part I - Transcript.pdf
Creating a Whatsapp Clone - Part I - Transcript.pdfShaiAlmog1
 
Creating a Whatsapp Clone - Part IX.pdf
Creating a Whatsapp Clone - Part IX.pdfCreating a Whatsapp Clone - Part IX.pdf
Creating a Whatsapp Clone - Part IX.pdfShaiAlmog1
 

More from ShaiAlmog1 (20)

The Duck Teaches Learn to debug from the masters. Local to production- kill ...
The Duck Teaches  Learn to debug from the masters. Local to production- kill ...The Duck Teaches  Learn to debug from the masters. Local to production- kill ...
The Duck Teaches Learn to debug from the masters. Local to production- kill ...
 
create-netflix-clone-06-client-ui.pdf
create-netflix-clone-06-client-ui.pdfcreate-netflix-clone-06-client-ui.pdf
create-netflix-clone-06-client-ui.pdf
 
create-netflix-clone-01-introduction_transcript.pdf
create-netflix-clone-01-introduction_transcript.pdfcreate-netflix-clone-01-introduction_transcript.pdf
create-netflix-clone-01-introduction_transcript.pdf
 
create-netflix-clone-02-server_transcript.pdf
create-netflix-clone-02-server_transcript.pdfcreate-netflix-clone-02-server_transcript.pdf
create-netflix-clone-02-server_transcript.pdf
 
create-netflix-clone-04-server-continued_transcript.pdf
create-netflix-clone-04-server-continued_transcript.pdfcreate-netflix-clone-04-server-continued_transcript.pdf
create-netflix-clone-04-server-continued_transcript.pdf
 
create-netflix-clone-01-introduction.pdf
create-netflix-clone-01-introduction.pdfcreate-netflix-clone-01-introduction.pdf
create-netflix-clone-01-introduction.pdf
 
create-netflix-clone-03-server.pdf
create-netflix-clone-03-server.pdfcreate-netflix-clone-03-server.pdf
create-netflix-clone-03-server.pdf
 
create-netflix-clone-04-server-continued.pdf
create-netflix-clone-04-server-continued.pdfcreate-netflix-clone-04-server-continued.pdf
create-netflix-clone-04-server-continued.pdf
 
create-netflix-clone-05-client-model_transcript.pdf
create-netflix-clone-05-client-model_transcript.pdfcreate-netflix-clone-05-client-model_transcript.pdf
create-netflix-clone-05-client-model_transcript.pdf
 
create-netflix-clone-03-server_transcript.pdf
create-netflix-clone-03-server_transcript.pdfcreate-netflix-clone-03-server_transcript.pdf
create-netflix-clone-03-server_transcript.pdf
 
create-netflix-clone-02-server.pdf
create-netflix-clone-02-server.pdfcreate-netflix-clone-02-server.pdf
create-netflix-clone-02-server.pdf
 
create-netflix-clone-05-client-model.pdf
create-netflix-clone-05-client-model.pdfcreate-netflix-clone-05-client-model.pdf
create-netflix-clone-05-client-model.pdf
 
Creating a Whatsapp Clone - Part II.pdf
Creating a Whatsapp Clone - Part II.pdfCreating a Whatsapp Clone - Part II.pdf
Creating a Whatsapp Clone - Part II.pdf
 
Creating a Whatsapp Clone - Part IX - Transcript.pdf
Creating a Whatsapp Clone - Part IX - Transcript.pdfCreating a Whatsapp Clone - Part IX - Transcript.pdf
Creating a Whatsapp Clone - Part IX - Transcript.pdf
 
Creating a Whatsapp Clone - Part II - Transcript.pdf
Creating a Whatsapp Clone - Part II - Transcript.pdfCreating a Whatsapp Clone - Part II - Transcript.pdf
Creating a Whatsapp Clone - Part II - Transcript.pdf
 
Creating a Whatsapp Clone - Part V - Transcript.pdf
Creating a Whatsapp Clone - Part V - Transcript.pdfCreating a Whatsapp Clone - Part V - Transcript.pdf
Creating a Whatsapp Clone - Part V - Transcript.pdf
 
Creating a Whatsapp Clone - Part IV - Transcript.pdf
Creating a Whatsapp Clone - Part IV - Transcript.pdfCreating a Whatsapp Clone - Part IV - Transcript.pdf
Creating a Whatsapp Clone - Part IV - Transcript.pdf
 
Creating a Whatsapp Clone - Part IV.pdf
Creating a Whatsapp Clone - Part IV.pdfCreating a Whatsapp Clone - Part IV.pdf
Creating a Whatsapp Clone - Part IV.pdf
 
Creating a Whatsapp Clone - Part I - Transcript.pdf
Creating a Whatsapp Clone - Part I - Transcript.pdfCreating a Whatsapp Clone - Part I - Transcript.pdf
Creating a Whatsapp Clone - Part I - Transcript.pdf
 
Creating a Whatsapp Clone - Part IX.pdf
Creating a Whatsapp Clone - Part IX.pdfCreating a Whatsapp Clone - Part IX.pdf
Creating a Whatsapp Clone - Part IX.pdf
 

Recently uploaded

Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherRemote DBA Services
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProduct Anonymous
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoffsammart93
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...DianaGray10
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyKhushali Kathiriya
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityPrincipled Technologies
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel Araújo
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...apidays
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businesspanagenda
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAndrey Devyatkin
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CVKhem
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...apidays
 
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsTop 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsRoshan Dwivedi
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc
 
HTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation StrategiesHTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation StrategiesBoston Institute of Analytics
 
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...Principled Technologies
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodJuan lago vázquez
 

Recently uploaded (20)

Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : Uncertainty
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsTop 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
HTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation StrategiesHTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation Strategies
 
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 

Creating an Uber Clone - Part IX - Transcript.pdf

  • 1. Creating an Uber Clone - Part IX The “Where to?” UI is a pretty big piece of the puzzle and it also includes the navigation UI which is the bottom portion
  • 2. Destination UI © Codename One 2017 all rights reserved Up until now we focused on this part of the toolbar area
  • 3. Destination UI © Codename One 2017 all rights reserved Now we need to do this portion. The destination UI toggle is a huge part of the navigation UI. It's the bottom section of the form that contains the list of destinations. We can build it on top of the code we wrote for the navigation UI and place it in the center of the layer so it will play nicely with the rest of the UI.
  • 4. Destination UI © Codename One 2017 all rights reserved For now I’ll ignore this potion as it’s mostly a specialization of other things and can be done relatively easily if you understand the rest of the things I did
  • 5. private void showToNavigationBar(Container parentLayer) { MultiButton addHome = new MultiButton("Add Home"); addHome.setUIID("Container"); addHome.setUIIDLine1("WhereToButtonLine1"); addHome.setIconUIID("WhereToButtonIcon"); FontImage.setMaterialIcon(addHome, FontImage.MATERIAL_HOME); MultiButton addWork = new MultiButton("Add Work"); addWork.setUIID("Container"); addWork.setUIIDLine1("WhereToButtonLine1"); addWork.setIconUIID("WhereToButtonIcon"); FontImage.setMaterialIcon(addWork, FontImage.MATERIAL_WORK); MultiButton savedPlaces = new MultiButton("Saved Places"); savedPlaces.setUIID("Container"); savedPlaces.setUIIDLine1("WhereToButtonLineNoBorder"); savedPlaces.setEmblemUIID("WhereToButtonLineNoBorder"); savedPlaces.setIconUIID("WhereToButtonIcon"); savedPlaces.setEmblem(FontImage.createMaterial( FontImage.MATERIAL_NAVIGATE_NEXT, savedPlaces.getIconComponent().getUnselectedStyle())); FontImage.setMaterialIcon(savedPlaces, FontImage.MATERIAL_STAR_BORDER); Destination UI Let’s jump right in to the “showNavigationBar” method. The top elements are relatively simple multi-buttons, we use Container as their UIID so they will be transparent with 0 padding/margin.
  • 6. savedPlaces.setEmblem(FontImage.createMaterial( FontImage.MATERIAL_NAVIGATE_NEXT, savedPlaces.getIconComponent().getUnselectedStyle())); FontImage.setMaterialIcon(savedPlaces, FontImage.MATERIAL_STAR_BORDER); Label whereSeparator = new Label("", "WhereSeparator"); whereSeparator.setShowEvenIfBlank(true); MultiButton history1 = new MultiButton("Mikve Yisrael Str..."); history1.setUIID("Container"); history1.setUIIDLine1("WhereToButtonLine1"); history1.setIconUIID("WhereToButtonIcon"); FontImage.setMaterialIcon(history1, FontImage.MATERIAL_HISTORY); Container result = BoxLayout.encloseY(addHome, addWork, savedPlaces, whereSeparator, history1); result.setUIID("Form"); result.setScrollableY(true); result.setScrollVisible(false); result.setY(getDisplayHeight()); Destination UI The separator is just a label with a specific style. Notice that blank labels/buttons etc. are hidden by default in Codename One and you should invoke setShowEvenIfBlank if you want such a label to still render
  • 7. savedPlaces.setEmblem(FontImage.createMaterial( FontImage.MATERIAL_NAVIGATE_NEXT, savedPlaces.getIconComponent().getUnselectedStyle())); FontImage.setMaterialIcon(savedPlaces, FontImage.MATERIAL_STAR_BORDER); Label whereSeparator = new Label("", "WhereSeparator"); whereSeparator.setShowEvenIfBlank(true); MultiButton history1 = new MultiButton("Mikve Yisrael Str..."); history1.setUIID("Container"); history1.setUIIDLine1("WhereToButtonLine1"); history1.setIconUIID("WhereToButtonIcon"); FontImage.setMaterialIcon(history1, FontImage.MATERIAL_HISTORY); Container result = BoxLayout.encloseY(addHome, addWork, savedPlaces, whereSeparator, history1); result.setUIID("Form"); result.setScrollableY(true); result.setScrollVisible(false); result.setY(getDisplayHeight()); Destination UI We can reuse the Form UIID here because that's effectively what we want. We want this UI to appear as if it's a Form
  • 8. savedPlaces.setEmblem(FontImage.createMaterial( FontImage.MATERIAL_NAVIGATE_NEXT, savedPlaces.getIconComponent().getUnselectedStyle())); FontImage.setMaterialIcon(savedPlaces, FontImage.MATERIAL_STAR_BORDER); Label whereSeparator = new Label("", "WhereSeparator"); whereSeparator.setShowEvenIfBlank(true); MultiButton history1 = new MultiButton("Mikve Yisrael Str..."); history1.setUIID("Container"); history1.setUIIDLine1("WhereToButtonLine1"); history1.setIconUIID("WhereToButtonIcon"); FontImage.setMaterialIcon(history1, FontImage.MATERIAL_HISTORY); Container result = BoxLayout.encloseY(addHome, addWork, savedPlaces, whereSeparator, history1); result.setUIID("Form"); result.setScrollableY(true); result.setScrollVisible(false); result.setY(getDisplayHeight()); Destination UI We need this to be scrollable but we don't want the scrollbar on the side as it might cause aesthetic issues
  • 9. Label whereSeparator = new Label("", "WhereSeparator"); whereSeparator.setShowEvenIfBlank(true); MultiButton history1 = new MultiButton("Mikve Yisrael Str..."); history1.setUIID("Container"); history1.setUIIDLine1("WhereToButtonLine1"); history1.setIconUIID("WhereToButtonIcon"); FontImage.setMaterialIcon(history1, FontImage.MATERIAL_HISTORY); Container result = BoxLayout.encloseY(addHome, addWork, savedPlaces, whereSeparator, history1); result.setUIID("Form"); result.setScrollableY(true); result.setScrollVisible(false); result.setY(getDisplayHeight()); result.setWidth(getDisplayWidth()); result.setHeight(result.getPreferredH()); parentLayer.add(CENTER, result); parentLayer.animateLayout(200); } Destination UI The showing of this element is animated from the bottom of the Form
  • 10. WhereToButtonLine1 © Codename One 2017 all rights reserved While this UI is very simple it did define a few UIID's. Let's start with WhereToButtonLine1 which represents the entries in the list of elements and also adds the underline. The color is just black over transparent which in this case leads to white
  • 11. WhereToButtonLine1 © Codename One 2017 all rights reserved The padding on the left side is relatively low since the icon will take the extra padding. On the other sides we have typical 4 millimeter padding
  • 12. WhereToButtonLine1 © Codename One 2017 all rights reserved Margin is 0 as usual
  • 13. WhereToButtonLine1 © Codename One 2017 all rights reserved We put the underline here because the design placed the underline only under the text and didn't place it under the icon which has a different UIID. The underline is a gray 2 pixel high line
  • 14. WhereToButtonLine1 © Codename One 2017 all rights reserved The font is the standard 3 millimeter light font
  • 15. WhereToButtonIcon © Codename One 2017 all rights reserved The WhereToButtonIcon style applies to the icon which has less horizontal padding so it won’t drift too far from the text but identical vertical padding so it will align properly with the text
  • 16. WhereToButtonIcon © Codename One 2017 all rights reserved It derives from WhereToButtonLine1 so they will fit together well
  • 17. WhereToButtonNoBorder © Codename One 2017 all rights reserved We need the no border version of the style so it will remove the underline border on the last entry. Otherwise we can see an out of place underline in that one last entry in the list
  • 18. WhereToButtonNoBorder © Codename One 2017 all rights reserved We derive from the same style so everything else is identical
  • 19. WhereSeparator © Codename One 2017 all rights reserved The WhereSeparator is just a gray padded line, so it has the right gray color and is completely opaque with no background transparency.
  • 20. WhereSeparator © Codename One 2017 all rights reserved It’s exactly 2 millimeters tall so it will stand out but won’t take out an entire line.
  • 21. WhereSeparator © Codename One 2017 all rights reserved Margin is 0 so it can reach the edge of the parent container
  • 22. from.addFocusListener(new FocusListener() { public void focusGained(Component cmp) { fromSelected.setIcon(square); if(layer.getComponentCount() > 1) { Component c = layer.getComponentAt(1); c.setY(getDisplayHeight()); layer.animateUnlayout(200, 150, () -> { c.remove(); revalidate(); }); } } public void focusLost(Component cmp) { fromSelected.setIcon(circle); } }); to.addFocusListener(new FocusListener() { public void focusGained(Component cmp) { fromSelected.setIcon(circle); toSelected.setIcon(square); showToNavigationBar(layer); } public void focusLost(Component cmp) { toSelected.setIcon(circle); } }); Focus Listener Now that we added this we need to show this UI and hide it when the user toggles the focus in the text fields. We can do this by binding focus listeners to the to and from text fields. When focus is lost/gained we toggle between the square and circle modes by setting the icon to the appropriate labels
  • 23. from.addFocusListener(new FocusListener() { public void focusGained(Component cmp) { fromSelected.setIcon(square); if(layer.getComponentCount() > 1) { Component c = layer.getComponentAt(1); c.setY(getDisplayHeight()); layer.animateUnlayout(200, 150, () -> { c.remove(); revalidate(); }); } } public void focusLost(Component cmp) { fromSelected.setIcon(circle); } }); to.addFocusListener(new FocusListener() { public void focusGained(Component cmp) { fromSelected.setIcon(circle); toSelected.setIcon(square); showToNavigationBar(layer); } public void focusLost(Component cmp) { toSelected.setIcon(circle); } }); Focus Listener We always have one container in the layer except for the case where the second component is the where to container. It's always the second component because it's always added last.
  • 24. from.addFocusListener(new FocusListener() { public void focusGained(Component cmp) { fromSelected.setIcon(square); if(layer.getComponentCount() > 1) { Component c = layer.getComponentAt(1); c.setY(getDisplayHeight()); layer.animateUnlayout(200, 150, () -> { c.remove(); revalidate(); }); } } public void focusLost(Component cmp) { fromSelected.setIcon(circle); } }); to.addFocusListener(new FocusListener() { public void focusGained(Component cmp) { fromSelected.setIcon(circle); toSelected.setIcon(square); showToNavigationBar(layer); } public void focusLost(Component cmp) { toSelected.setIcon(circle); } }); Focus Listener We set the position of this container below the forms
  • 25. from.addFocusListener(new FocusListener() { public void focusGained(Component cmp) { fromSelected.setIcon(square); if(layer.getComponentCount() > 1) { Component c = layer.getComponentAt(1); c.setY(getDisplayHeight()); layer.animateUnlayout(200, 150, () -> { c.remove(); revalidate(); }); } } public void focusLost(Component cmp) { fromSelected.setIcon(circle); } }); to.addFocusListener(new FocusListener() { public void focusGained(Component cmp) { fromSelected.setIcon(circle); toSelected.setIcon(square); showToNavigationBar(layer); } public void focusLost(Component cmp) { toSelected.setIcon(circle); } }); Focus Listener Animate "unlayout" moves the component outside of the screen to the position we asked for using a smooth animation
  • 26. from.addFocusListener(new FocusListener() { public void focusGained(Component cmp) { fromSelected.setIcon(square); if(layer.getComponentCount() > 1) { Component c = layer.getComponentAt(1); c.setY(getDisplayHeight()); layer.animateUnlayout(200, 150, () -> { c.remove(); revalidate(); }); } } public void focusLost(Component cmp) { fromSelected.setIcon(circle); } }); to.addFocusListener(new FocusListener() { public void focusGained(Component cmp) { fromSelected.setIcon(circle); toSelected.setIcon(square); showToNavigationBar(layer); } public void focusLost(Component cmp) { toSelected.setIcon(circle); } }); Focus Listener This callback is invoked when the unlayout completes. At this point we have an invalid UI that needs a layout but before we do that we remove the component that we animated out of the form
  • 27. back.addActionListener(e -> { navigationToolbar.setY(-navigationToolbar.getHeight()); if(layer.getComponentCount() > 1) { layer.getComponentAt(1).setY(getDisplayHeight()); } navigationToolbar.getParent().animateUnlayout(200, 120, () -> { layer.removeAll(); revalidate(); }); }); Back Now that the UI appears we also need to remove it when going back so I'll update the back action listener from above to handle the "Where to?" UI as well. This is the exact same unlayout operation we did before
  • 28. navigationToolbar.getUnselectedStyle().setBgPainter((g1, rect) -> { g1.setAlpha(255); g1.setColor(0xffffff); if(dropShadow != null) { if(layer.getComponentCount() > 1) { g1.fillRect(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight()); } g1.drawImage(dropShadow, rect.getX(), rect.getY() + rect.getHeight() - dropShadow.getHeight(), rect.getWidth(), dropShadow.getHeight()); g1.fillRect(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight() - dropShadow.getHeight() / 2); } else { g1.fillRect(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight()); } g1.setColor(0xa4a4ac); g1.setAntiAliased(true); int x = fromSelected.getAbsoluteX() + fromSelected.getWidth() / 2 - 1; int y = fromSelected.getAbsoluteY() + fromSelected.getHeight() / 2 + circle.getHeight() / 2; g1.fillRect(x, y, 2, toSelected.getAbsoluteY() - y + toSelected.getHeight() / 2 - circle.getHeight() / 2); }); Background Painter And finally we need to make a subtle but important change to the background painter code from before. Because of the drop shadow a gap is formed between the top and bottom pieces so a special case here paints a white rectangle under the shadow to hide the gap. Without that the shadow would appear on top of the map and not on top of a white background. Once this is done opening the "Where To?" UI and toggling the fields should work as expected.