Creating an Uber Clone - Part VII - Transcript.pdf
1. Creating an Uber Clone - Part VII
In this section we finally get to “the map” UI, I hope you followed the instructions before for configuring the map. If not please follow through with that if things don’t work
and if you don’t see the map or it acts funny check out with us in the online support forums. You can also check out the map section in the deep dive into mobile
development course which comes bundled.
Before we begin we need a class we discussed before in the maps module. The MapLayout, I didn’t change much as left it “as is”. Since it’s already available elsewhere I
won’t go into the full discussion here and go right into the form itself.
4. public class MapForm extends Form {
private static final String MAP_JS_KEY = "AIza-------";
private Image square;
private Image dropShadow;
public MapForm() {
super(new LayeredLayout());
setScrollableY(false);
Display.getInstance().callSeriallyOnIdle(() -> {
dropShadow = LoginForm.squareShadow(getDisplayWidth(), 30,
convertToPixels(3), 0.40f);
});
setTransitionOutAnimator(CommonTransitions.createEmpty());
MapContainer mc = new MapContainer(MAP_JS_KEY);
mc.setShowMyLocation(true);
add(mc);
Container mapLayer = new Container();
mapLayer.setLayout(new MapLayout(mc, mapLayer));
add(mapLayer);
Coord telAviv = new Coord(32.072449, 34.778613);
mc.zoom(telAviv, mc.getMaxZoom() + 1);
Label car = new Label(Resources.getGlobalResources().
getImage("map-vehicle-icon-uberX.png"));
car.getAllStyles().setOpacity(140);
MapForm
Lets jump right into the code.
You need the JS key from Google Maps as explained in the map extension page. This must have a filled up value
5. public class MapForm extends Form {
private static final String MAP_JS_KEY = "AIza-------";
private Image square;
private Image dropShadow;
public MapForm() {
super(new LayeredLayout());
setScrollableY(false);
Display.getInstance().callSeriallyOnIdle(() -> {
dropShadow = LoginForm.squareShadow(getDisplayWidth(), 30,
convertToPixels(3), 0.40f);
});
setTransitionOutAnimator(CommonTransitions.createEmpty());
MapContainer mc = new MapContainer(MAP_JS_KEY);
mc.setShowMyLocation(true);
add(mc);
Container mapLayer = new Container();
mapLayer.setLayout(new MapLayout(mc, mapLayer));
add(mapLayer);
Coord telAviv = new Coord(32.072449, 34.778613);
mc.zoom(telAviv, mc.getMaxZoom() + 1);
Label car = new Label(Resources.getGlobalResources().
getImage("map-vehicle-icon-uberX.png"));
car.getAllStyles().setOpacity(140);
MapForm
We usually use BorderLayout which implicitly disables scrollability. LayeredLayout doesn't do that and the forms content pane is scrollable on the Y-axis by default
6. public class MapForm extends Form {
private static final String MAP_JS_KEY = "AIza-------";
private Image square;
private Image dropShadow;
public MapForm() {
super(new LayeredLayout());
setScrollableY(false);
Display.getInstance().callSeriallyOnIdle(() -> {
dropShadow = LoginForm.squareShadow(getDisplayWidth(), 30,
convertToPixels(3), 0.40f);
});
setTransitionOutAnimator(CommonTransitions.createEmpty());
MapContainer mc = new MapContainer(MAP_JS_KEY);
mc.setShowMyLocation(true);
add(mc);
Container mapLayer = new Container();
mapLayer.setLayout(new MapLayout(mc, mapLayer));
add(mapLayer);
Coord telAviv = new Coord(32.072449, 34.778613);
mc.zoom(telAviv, mc.getMaxZoom() + 1);
Label car = new Label(Resources.getGlobalResources().
getImage("map-vehicle-icon-uberX.png"));
car.getAllStyles().setOpacity(140);
MapForm
Notice we didn't use a thread here and instead used the callSeriallyOnIdle method. On the login Form I didn't use that because the animation might have prevented idle
from occurring. This shadow is used later on in the showNavigationToolbar method
7. public class MapForm extends Form {
private static final String MAP_JS_KEY = "AIza-------";
private Image square;
private Image dropShadow;
public MapForm() {
super(new LayeredLayout());
setScrollableY(false);
Display.getInstance().callSeriallyOnIdle(() -> {
dropShadow = LoginForm.squareShadow(getDisplayWidth(), 30,
convertToPixels(3), 0.40f);
});
setTransitionOutAnimator(CommonTransitions.createEmpty());
MapContainer mc = new MapContainer(MAP_JS_KEY);
mc.setShowMyLocation(true);
add(mc);
Container mapLayer = new Container();
mapLayer.setLayout(new MapLayout(mc, mapLayer));
add(mapLayer);
Coord telAviv = new Coord(32.072449, 34.778613);
mc.zoom(telAviv, mc.getMaxZoom() + 1);
Label car = new Label(Resources.getGlobalResources().
getImage("map-vehicle-icon-uberX.png"));
car.getAllStyles().setOpacity(140);
MapForm
The transitions in the main application are based on cover and the transition out will only be a problem
8. public class MapForm extends Form {
private static final String MAP_JS_KEY = "AIza-------";
private Image square;
private Image dropShadow;
public MapForm() {
super(new LayeredLayout());
setScrollableY(false);
Display.getInstance().callSeriallyOnIdle(() -> {
dropShadow = LoginForm.squareShadow(getDisplayWidth(), 30,
convertToPixels(3), 0.40f);
});
setTransitionOutAnimator(CommonTransitions.createEmpty());
MapContainer mc = new MapContainer(MAP_JS_KEY);
mc.setShowMyLocation(true);
add(mc);
Container mapLayer = new Container();
mapLayer.setLayout(new MapLayout(mc, mapLayer));
add(mapLayer);
Coord telAviv = new Coord(32.072449, 34.778613);
mc.zoom(telAviv, mc.getMaxZoom() + 1);
Label car = new Label(Resources.getGlobalResources().
getImage("map-vehicle-icon-uberX.png"));
car.getAllStyles().setOpacity(140);
MapForm
The map is on the lowest layer and everything is placed on top of it
9. public class MapForm extends Form {
private static final String MAP_JS_KEY = "AIza-------";
private Image square;
private Image dropShadow;
public MapForm() {
super(new LayeredLayout());
setScrollableY(false);
Display.getInstance().callSeriallyOnIdle(() -> {
dropShadow = LoginForm.squareShadow(getDisplayWidth(), 30,
convertToPixels(3), 0.40f);
});
setTransitionOutAnimator(CommonTransitions.createEmpty());
MapContainer mc = new MapContainer(MAP_JS_KEY);
mc.setShowMyLocation(true);
add(mc);
Container mapLayer = new Container();
mapLayer.setLayout(new MapLayout(mc, mapLayer));
add(mapLayer);
Coord telAviv = new Coord(32.072449, 34.778613);
mc.zoom(telAviv, mc.getMaxZoom() + 1);
Label car = new Label(Resources.getGlobalResources().
getImage("map-vehicle-icon-uberX.png"));
car.getAllStyles().setOpacity(140);
MapForm
This layer is on top of the map and uses the MapLayout. Here we will place the car and other landmarks we need
10. mapLayer.setLayout(new MapLayout(mc, mapLayer));
add(mapLayer);
Coord telAviv = new Coord(32.072449, 34.778613);
mc.zoom(telAviv, mc.getMaxZoom() + 1);
Label car = new Label(Resources.getGlobalResources().
getImage("map-vehicle-icon-uberX.png"));
car.getAllStyles().setOpacity(140);
mapLayer.add(telAviv, car);
square = Image.createImage(convertToPixels(0.7f),
convertToPixels(0.7f), 0xff000000);
Button whereTo = new Button("Where To?", square, "WhereTo");
whereTo.setGap(convertToPixels(3));
add(BoxLayout.encloseY(whereTo));
FloatingActionButton history1 = FloatingActionButton.createFAB(
FontImage.MATERIAL_HISTORY, "History");
FloatingActionButton history2 = FloatingActionButton.createFAB(
FontImage.MATERIAL_HISTORY, "History");
TextArea history1Label = new TextArea("Mikve Yisrael Str...", 3, 4);
TextArea history2Label = new TextArea("Burgeranch", 3, 4);
history1Label.setUIID("HistoryLabel");
history2Label.setUIID("HistoryLabel");
history1Label.setEditable(false);
MapForm
I place a car on top of the map in Tel Aviv. Notice that the car is just a label... I've set the opacity to 140 to match the translucent cars in the native app. Notice that the
`MapLayout` takes a `Coord` as a constraint so it can properly position the car…
11. mapLayer.setLayout(new MapLayout(mc, mapLayer));
add(mapLayer);
Coord telAviv = new Coord(32.072449, 34.778613);
mc.zoom(telAviv, mc.getMaxZoom() + 1);
Label car = new Label(Resources.getGlobalResources().
getImage("map-vehicle-icon-uberX.png"));
car.getAllStyles().setOpacity(140);
mapLayer.add(telAviv, car);
square = Image.createImage(convertToPixels(0.7f),
convertToPixels(0.7f), 0xff000000);
Button whereTo = new Button("Where To?", square, "WhereTo");
whereTo.setGap(convertToPixels(3));
add(BoxLayout.encloseY(whereTo));
FloatingActionButton history1 = FloatingActionButton.createFAB(
FontImage.MATERIAL_HISTORY, "History");
FloatingActionButton history2 = FloatingActionButton.createFAB(
FontImage.MATERIAL_HISTORY, "History");
TextArea history1Label = new TextArea("Mikve Yisrael Str...", 3, 4);
TextArea history2Label = new TextArea("Burgeranch", 3, 4);
history1Label.setUIID("HistoryLabel");
history2Label.setUIID("HistoryLabel");
history1Label.setEditable(false);
MapForm
This is the small square we place next to the "Where to?" button. I could have used a unicode value too but it wasn't available in all the fonts. Notice the "Where to?"
element is just a button as it moves us to a separate UI and isn't really a TextField
12. whereTo.setGap(convertToPixels(3));
add(BoxLayout.encloseY(whereTo));
FloatingActionButton history1 = FloatingActionButton.createFAB(
FontImage.MATERIAL_HISTORY, "History");
FloatingActionButton history2 = FloatingActionButton.createFAB(
FontImage.MATERIAL_HISTORY, "History");
TextArea history1Label = new TextArea("Mikve Yisrael Str...", 3, 4);
TextArea history2Label = new TextArea("Burgeranch", 3, 4);
history1Label.setUIID("HistoryLabel");
history2Label.setUIID("HistoryLabel");
history1Label.setEditable(false);
history1Label.setGrowByContent(false);
history2Label.setEditable(false);
history2Label.setGrowByContent(false);
Container h1 = BoxLayout.encloseY(history1, history1Label);
Container h2 = BoxLayout.encloseY(history2, history2Label);
h1.setLeadComponent(history1);
h2.setLeadComponent(history2);
ScaleImageLabel gradient = new ScaleImageLabel(Resources.
getGlobalResources().getImage("gradient-overlay.png"));
gradient.setBackgroundType(Style.BACKGROUND_IMAGE_SCALED_FILL);
add(BorderLayout.south(gradient));
MapForm
The history buttons are FloatingActionButton instances that are customized in terms of styling. I used TextArea instead of SpanLabel because I wanted the history
element to act as a single component with lead component. Lead components can take over a hierarchy of several components and handle the events for everyone so in
this case a click on the text area below the history will trigger an event in the FloatingActionButton
13. whereTo.setGap(convertToPixels(3));
add(BoxLayout.encloseY(whereTo));
FloatingActionButton history1 = FloatingActionButton.createFAB(
FontImage.MATERIAL_HISTORY, "History");
FloatingActionButton history2 = FloatingActionButton.createFAB(
FontImage.MATERIAL_HISTORY, "History");
TextArea history1Label = new TextArea("Mikve Yisrael Str...", 3, 4);
TextArea history2Label = new TextArea("Burgeranch", 3, 4);
history1Label.setUIID("HistoryLabel");
history2Label.setUIID("HistoryLabel");
history1Label.setEditable(false);
history1Label.setGrowByContent(false);
history2Label.setEditable(false);
history2Label.setGrowByContent(false);
Container h1 = BoxLayout.encloseY(history1, history1Label);
Container h2 = BoxLayout.encloseY(history2, history2Label);
h1.setLeadComponent(history1);
h2.setLeadComponent(history2);
ScaleImageLabel gradient = new ScaleImageLabel(Resources.
getGlobalResources().getImage("gradient-overlay.png"));
gradient.setBackgroundType(Style.BACKGROUND_IMAGE_SCALED_FILL);
add(BorderLayout.south(gradient));
MapForm
The bottom of the map has a gradient overlay that darkens the bottom. This is probably in place to make the history labels readable. I just generated a gradient image in
photoshop and placed it there
14. history1Label.setUIID("HistoryLabel");
history2Label.setUIID("HistoryLabel");
history1Label.setEditable(false);
history1Label.setGrowByContent(false);
history2Label.setEditable(false);
history2Label.setGrowByContent(false);
Container h1 = BoxLayout.encloseY(history1, history1Label);
Container h2 = BoxLayout.encloseY(history2, history2Label);
h1.setLeadComponent(history1);
h2.setLeadComponent(history2);
ScaleImageLabel gradient = new ScaleImageLabel(Resources.
getGlobalResources().getImage("gradient-overlay.png"));
gradient.setBackgroundType(Style.BACKGROUND_IMAGE_SCALED_FILL);
add(BorderLayout.south(gradient));
add(BorderLayout.south(FlowLayout.encloseCenter(h1, h2)));
}
@Override
protected void initGlobalToolbar() {
setToolbar(new Toolbar(true));
CommonCode.constructSideMenu(getToolbar());
}
}
MapForm
We do two important things here... We use the overlay toolbar which "floats" on top of the UI. We initialize the side menu which we will discuss soon…
That was a lot to cover but there is a lot more... We did mention 3 new styles above which isn't that much all things considered.