3. blackButton.addActionListener(e -> {
exitNavigationMode(layer, fromComponent, toComponent, pathObject);
Label searching = new Label("Finding your ride",
Resources.getGlobalResources().getImage("searching-cab-icon.png"),
"SearchingDialog");
pinLayer.add(SOUTH, searching);
pinLayer.getUnselectedStyle().setBgColor(0);
pinLayer.getUnselectedStyle().setBgTransparency(120);
pinLayer.add(CENTER, new BlinkDot());
LocationService.hailRide(from, to, car -> {
pinLayer.getUnselectedStyle().setBgTransparency(0);
pinLayer.removeAll();
});
});
enterNavigationMode
We can start by adding an event handler to the blackButton from the enterNavigationMode method
We are effectively coloring the pin layer to create the tint effect
4. blackButton.addActionListener(e -> {
exitNavigationMode(layer, fromComponent, toComponent, pathObject);
Label searching = new Label("Finding your ride",
Resources.getGlobalResources().getImage("searching-cab-icon.png"),
"SearchingDialog");
pinLayer.add(SOUTH, searching);
pinLayer.getUnselectedStyle().setBgColor(0);
pinLayer.getUnselectedStyle().setBgTransparency(120);
pinLayer.add(CENTER, new BlinkDot());
LocationService.hailRide(from, to, car -> {
pinLayer.getUnselectedStyle().setBgTransparency(0);
pinLayer.removeAll();
});
});
enterNavigationMode
We added a new BlinkDot class to implement the pulsing blue dot effect
5. blackButton.addActionListener(e -> {
exitNavigationMode(layer, fromComponent, toComponent, pathObject);
Label searching = new Label("Finding your ride",
Resources.getGlobalResources().getImage("searching-cab-icon.png"),
"SearchingDialog");
pinLayer.add(SOUTH, searching);
pinLayer.getUnselectedStyle().setBgColor(0);
pinLayer.getUnselectedStyle().setBgTransparency(120);
pinLayer.add(CENTER, new BlinkDot());
LocationService.hailRide(from, to, car -> {
pinLayer.getUnselectedStyle().setBgTransparency(0);
pinLayer.removeAll();
});
});
enterNavigationMode
Another new API the hailRide method in LocationService allows us to hail a ride...
6. blackButton.addActionListener(e -> {
exitNavigationMode(layer, fromComponent, toComponent, pathObject);
Label searching = new Label("Finding your ride",
Resources.getGlobalResources().getImage("searching-cab-icon.png"),
"SearchingDialog");
pinLayer.add(SOUTH, searching);
pinLayer.getUnselectedStyle().setBgColor(0);
pinLayer.getUnselectedStyle().setBgTransparency(120);
pinLayer.add(CENTER, new BlinkDot());
LocationService.hailRide(from, to, car -> {
pinLayer.getUnselectedStyle().setBgTransparency(0);
pinLayer.removeAll();
});
});
enterNavigationMode
Notice I don't show anything when the ride is hailed, I'll add that workflow with the driver app later
12. public class BlinkDot extends Component {
private int value;
private Motion growth;
public BlinkDot() {
setUIID("Label");
}
@Override
protected void initComponent() {
super.initComponent();
getComponentForm().registerAnimated(this);
}
@Override
protected void deinitialize() {
getComponentForm().deregisterAnimated(this);
super.deinitialize();
}
@Override
public boolean animate() {
if(growth == null || growth.isFinished()) {
growth = Motion.createEaseInOutMotion(3, getWidth() / 2, 1000);
growth.start();
}
int newValue = growth.getValue();
if(newValue != value) {
value = newValue;
return true;
}
BlinkDot
The BlinkDot class is pretty trivial. I could have used an animated gif but instead I just did this.
This is mostly for transparency we don't really use the UIID here
13. public class BlinkDot extends Component {
private int value;
private Motion growth;
public BlinkDot() {
setUIID("Label");
}
@Override
protected void initComponent() {
super.initComponent();
getComponentForm().registerAnimated(this);
}
@Override
protected void deinitialize() {
getComponentForm().deregisterAnimated(this);
super.deinitialize();
}
@Override
public boolean animate() {
if(growth == null || growth.isFinished()) {
growth = Motion.createEaseInOutMotion(3, getWidth() / 2, 1000);
growth.start();
}
int newValue = growth.getValue();
if(newValue != value) {
value = newValue;
return true;
}
BlinkDot
I use low level animations here so the best practice is to register/remove with initComponent/deinitialize
14. public class BlinkDot extends Component {
private int value;
private Motion growth;
public BlinkDot() {
setUIID("Label");
}
@Override
protected void initComponent() {
super.initComponent();
getComponentForm().registerAnimated(this);
}
@Override
protected void deinitialize() {
getComponentForm().deregisterAnimated(this);
super.deinitialize();
}
@Override
public boolean animate() {
if(growth == null || growth.isFinished()) {
growth = Motion.createEaseInOutMotion(3, getWidth() / 2, 1000);
growth.start();
}
int newValue = growth.getValue();
if(newValue != value) {
value = newValue;
return true;
}
BlinkDot
The motion class represents a timed motion between values which allows us to animate a value from point X to point Y. In this case I'm just growing the circle using the
value. Notice only the animate method mutates values as the paint method can be invoked more than once per cycle in theory
15. growth.start();
}
int newValue = growth.getValue();
if(newValue != value) {
value = newValue;
return true;
}
return false;
}
@Override
public void paint(Graphics g) {
g.setAlpha(255);
g.setColor(0x297aa7);
int s = convertToPixels(2);
g.setAntiAliased(true);
g.fillArc(getX() + getWidth() / 2 - s / 2, getY() + getHeight() / 2 -
s / 2, s, s, 0, 360);
g.drawArc(getX() + getWidth() / 2 - value,
getY() + getHeight() / 2 - value, value * 2, value * 2, 0, 360);
g.drawArc(getX() + getWidth() / 2 - value - 1, getY() + getHeight() / 2 -
value - 1, value * 2 + 1, value * 2 + 1, 0, 360);
}
@Override
protected Dimension calcPreferredSize() {
int s = convertToPixels(15);
return new Dimension(s, s);
}
BlinkDot
The drawing logic is mostly hardcoded, I would have used the shape API to get a more refined effect but it would have made things more complicated