SlideShare a Scribd company logo
Creating an Uber Clone - Part XXII
With that out of the way search should work but how does it display the result?

For that we need to add additional features to the MapForm that address these capabilities. Before we go into that lets check out what that means
Routes
© Codename One 2017 all rights reserved
The ride booking UI plots the path of the ride on the map and includes two tags one pointing at your current location and one on the destination. The first tag is divided to
a "time indication" and name. The latter only contains the name. Notice that the elements have a rounded rectangle shape with a pointy end on one side to point at the
position within the path.
private Component createNavigationTag(String location, int durationMinutes) {
Label locationLabel = new Label(location, "NavigationLabel");
if(durationMinutes > 0) {
Label duration = new Label("" + durationMinutes,
"NavigationMinuteLabel");
Label min = new Label("MIN", "NavigationMinuteDescLabel");
Container west = BoxLayout.encloseY(duration, min);
Container result = BorderLayout.centerEastWest(locationLabel,
null, west);
result.getUnselectedStyle().setBorder(BlackAndWhiteBorder.create().
blackLinePosition(west.getPreferredW()));
return result;
}
locationLabel.getUnselectedStyle().setBorder(
BlackAndWhiteBorder.create());
return locationLabel;
}
addMapListener
Lets start with creating these tags. The tag code itself is trivial it's just a Label or a Container with some details. Nothing special.

Except for one important detail, the BlackAndWhiteBorder. In order to implement the unique shape of the tag I created a new Border class. Notice I used the preferred
width of the west component to determine the black section. This is done in the blackLinePosition method.

Before we go any further I’d just like to make one point clear: I Would have Used a 9-piece Border. If this were a real application I would have just cut a 9-piece border
and moved on. However, since the point is teaching I chose to do this the "hard way"
NavigationLabel
© Codename One 2017 all rights reserved
Before we get into the BlackAndWhiteBorder there are a few UIID's we need to define.

The NavigationLabel UIID is a the black on white label that appears in the tag.
NavigationLabel
© Codename One 2017 all rights reserved
The only unique thing about it is the relatively small amount of padding so the tag doesn’t take up too much space
NavigationLabel
© Codename One 2017 all rights reserved
The margin is predictably zero
NavigationLabel
© Codename One 2017 all rights reserved
And the font is slightly smaller than usual
NavigationMinuteLabel
© Codename One 2017 all rights reserved
The NavigationMinuteLabel UIID is the white on black minute value.
NavigationMinuteLabel
© Codename One 2017 all rights reserved
It’s center aligned
NavigationMinuteLabel
© Codename One 2017 all rights reserved
It has 0 padding below to keep the text and number close together but has similar paddings on the other sides to match the NavigationLabel
NavigationMinuteLabel
© Codename One 2017 all rights reserved
It has zero margin
NavigationMinuteLabel
© Codename One 2017 all rights reserved
and it has a smaller font size than usual although not a tiny font
NavigationMinuteDescLabel
© Codename One 2017 all rights reserved
The NavigationMinuteDescLabel UIID is used for the text below that. The text with the word “MIN”. It derives from NavigationMinuteLabel
NavigationMinuteDescLabel
© Codename One 2017 all rights reserved
And has an even smaller font than that…
public class BlackAndWhiteBorder extends Border {
private static final String CACHE_KEY = "cn1$$-bwcache";
private final float shadowBlur = 10;
private final float shadowSpread;
private final int shadowOpacity = 110;
private final float cornerRadius = 1f;
private int blackLinePosition = -1;
BlackAndWhiteBorder() {
shadowSpread = Display.getInstance().convertToPixels(0.2f);
}
public static BlackAndWhiteBorder create() {
return new BlackAndWhiteBorder();
}
public BlackAndWhiteBorder blackLinePosition(int blackLinePosition) {
this.blackLinePosition = blackLinePosition;
return this;
}
private Image createTargetImage(Component c, int w, int h, boolean fast) {
Image target = Image.createImage(w, h, 0);
int shapeX = 0;
int shapeY = 0;
int shapeW = w;
int shapeH = h;
BlackAndWhiteBorder
Now that these are out of the way let's take a look at the border. Notice we can just subclass the Border class just like we can implement painters etc. This provides a
similar path for customization but is sometimes more flexible. Most of this code is based on the builtin RoundRectBorder class.

Drawing this type of border is pretty expensive so we draw onto an image and place that image in cache within the component using putClientProperty we use this value
as the key
public class BlackAndWhiteBorder extends Border {
private static final String CACHE_KEY = "cn1$$-bwcache";
private final float shadowBlur = 10;
private final float shadowSpread;
private final int shadowOpacity = 110;
private final float cornerRadius = 1f;
private int blackLinePosition = -1;
BlackAndWhiteBorder() {
shadowSpread = Display.getInstance().convertToPixels(0.2f);
}
public static BlackAndWhiteBorder create() {
return new BlackAndWhiteBorder();
}
public BlackAndWhiteBorder blackLinePosition(int blackLinePosition) {
this.blackLinePosition = blackLinePosition;
return this;
}
private Image createTargetImage(Component c, int w, int h, boolean fast) {
Image target = Image.createImage(w, h, 0);
int shapeX = 0;
int shapeY = 0;
int shapeW = w;
int shapeH = h;
BlackAndWhiteBorder
The blackLinePosition is used in the version of this border that's partially black
private Image createTargetImage(Component c, int w, int h, boolean fast) {
Image target = Image.createImage(w, h, 0);
int shapeX = 0;
int shapeY = 0;
int shapeW = w;
int shapeH = h;
Graphics tg = target.getGraphics();
tg.setAntiAliased(true);
int shadowSpreadL = Display.getInstance().convertToPixels(shadowSpread);
shapeW -= shadowSpreadL;
shapeH -= shadowSpreadL;
shapeX += Math.round(((float)shadowSpreadL) * 0.9);
shapeY += Math.round(((float)shadowSpreadL) * 0.9);
for(int iter = shadowSpreadL - 1 ; iter >= 0 ; iter--) {
tg.translate(iter, iter);
fillShape(tg, 0, shadowOpacity / shadowSpreadL, w-(iter*2),h - (iter * 2));
tg.translate(-iter, -iter);
}
if(Display.getInstance().isGaussianBlurSupported() && !fast) {
Image blured = Display.getInstance().gaussianBlurImage(target,shadowBlur/2);
target = Image.createImage(w, h, 0);
tg = target.getGraphics();
tg.drawImage(blured, 0, 0);
BlackAndWhiteBorder
Here we create the border image that we will cache for the given component. Since a shadow is set on the border and that can take some processing power. To speed
this up we have two versions of the method fast and slow. We call the fast one and invoke the slow one asynchronously to update the border
private Image createTargetImage(Component c, int w, int h, boolean fast) {
Image target = Image.createImage(w, h, 0);
int shapeX = 0;
int shapeY = 0;
int shapeW = w;
int shapeH = h;
Graphics tg = target.getGraphics();
tg.setAntiAliased(true);
int shadowSpreadL = Display.getInstance().convertToPixels(shadowSpread);
shapeW -= shadowSpreadL;
shapeH -= shadowSpreadL;
shapeX += Math.round(((float)shadowSpreadL) * 0.9);
shapeY += Math.round(((float)shadowSpreadL) * 0.9);
for(int iter = shadowSpreadL - 1 ; iter >= 0 ; iter--) {
tg.translate(iter, iter);
fillShape(tg, 0, shadowOpacity / shadowSpreadL, w-(iter*2),h - (iter * 2));
tg.translate(-iter, -iter);
}
if(Display.getInstance().isGaussianBlurSupported() && !fast) {
Image blured = Display.getInstance().gaussianBlurImage(target,shadowBlur/2);
target = Image.createImage(w, h, 0);
tg = target.getGraphics();
tg.drawImage(blured, 0, 0);
BlackAndWhiteBorder
We do a shadow effect by drawing a gradient with varying alpha degrees then blurring that out
tg.drawImage(blured, 0, 0);
tg.setAntiAliased(true);
}
tg.translate(shapeX, shapeY);
c.getStyle().setBorder(Border.createEmpty());
GeneralPath gp = createShape(shapeW, shapeH);
tg.setClip(gp);
c.getStyle().getBgPainter().paint(tg, new Rectangle(0, 0, w, h));
c.getStyle().setBorder(this);
return target;
}
public void paintBorderBackground(Graphics g, final Component c) {
final int w = c.getWidth();
final int h = c.getHeight();
int x = c.getX();
int y = c.getY();
if(w > 0 && h > 0) {
Image background = (Image)c.getClientProperty(CACHE_KEY);
if(background!=null && background.getWidth()==w && background.getHeight()==h){
g.drawImage(background, x, y);
return;
}
BlackAndWhiteBorder
If we have a cached version of the border image we will just use that as the background of the component assuming the size of the component didn't change
int y = c.getY();
if(w > 0 && h > 0) {
Image background = (Image)c.getClientProperty(CACHE_KEY);
if(background!=null && background.getWidth()==w && background.getHeight()==h){
g.drawImage(background, x, y);
return;
}
} else {
return;
}
Image target = createTargetImage(c, w, h, true);
g.drawImage(target, x, y);
c.putClientProperty(CACHE_KEY, target);
Display.getInstance().callSeriallyOnIdle(new Runnable() {
public void run() {
if(w == c.getWidth() && h == c.getHeight()) {
Image target = createTargetImage(c, w, h, false);
c.putClientProperty(CACHE_KEY, target);
c.repaint();
}
}
BlackAndWhiteBorder
Otherwise we create that image and update it later with the slower version that includes the gradient shadow effect
c.putClientProperty(CACHE_KEY, target);
c.repaint();
}
}
});
}
private GeneralPath createShape(int shapeW, int shapeH) {
GeneralPath gp = new GeneralPath();
float radius = Display.getInstance().convertToPixels(cornerRadius);
float x = 0;
float y = 0;
float widthF = shapeW;
float heightF = shapeH;
gp.moveTo(x + radius, y);
if(blackLinePosition > -1) {
gp.lineTo(x + widthF, y);
} else {
gp.lineTo(x + widthF - radius, y);
gp.quadTo(x + widthF, y, x + widthF, y + radius);
}
gp.lineTo(x + widthF, y + heightF - radius);
gp.quadTo(x + widthF, y + heightF, x + widthF - radius, y + heightF);
if(blackLinePosition > -1) {
BlackAndWhiteBorder
We create the shape of the component. If it's the one with the black line we place the corner in the top right otherwise we place it in the bottom left
gp.quadTo(x + widthF, y + heightF, x + widthF - radius, y + heightF);
if(blackLinePosition > -1) {
gp.lineTo(x + radius, y + heightF);
gp.quadTo(x, y + heightF, x, y + heightF - radius);
} else {
gp.lineTo(x, y + heightF);
}
gp.lineTo(x, y + radius);
gp.quadTo(x, y, x + radius, y);
gp.closePath();
return gp;
}
public int getMinimumHeight() {
return convertToPixels(shadowSpread) + convertToPixels(cornerRadius) * 2;
}
public int getMinimumWidth() {
return convertToPixels(shadowSpread) + convertToPixels(cornerRadius) * 2;
}
private void fillShape(Graphics g, int color, int opacity, int width, int height) {
g.setColor(0xffffff);
g.setAlpha(255);
GeneralPath gp = createShape(width, height);
if(blackLinePosition > -1) {
BlackAndWhiteBorder
We can now fill out the shape as part of the image creation code if we have a black line we do the fill operation twice with different clip sizes to create that effect

More Related Content

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

Introduction to graphics programming in c
Introduction to graphics programming in cIntroduction to graphics programming in c
Introduction to graphics programming in c
baabtra.com - No. 1 supplier of quality freshers
 
Leaving Flatland: getting started with WebGL
Leaving Flatland: getting started with WebGLLeaving Flatland: getting started with WebGL
Leaving Flatland: getting started with WebGL
gerbille
 
Maps - Part 3 - Transcript.pdf
Maps - Part 3 - Transcript.pdfMaps - Part 3 - Transcript.pdf
Maps - Part 3 - Transcript.pdf
ShaiAlmog1
 
Graphics in C++
Graphics in C++Graphics in C++
Graphics in C++
Ahsan Mughal
 
Trident International Graphics Workshop 2014 5/5
Trident International Graphics Workshop 2014 5/5Trident International Graphics Workshop 2014 5/5
Trident International Graphics Workshop 2014 5/5
Takao Wada
 
C Graphics Functions
C Graphics FunctionsC Graphics Functions
C Graphics Functions
SHAKOOR AB
 
Creating an Uber Clone - Part III - Transcript.pdf
Creating an Uber Clone - Part III - Transcript.pdfCreating an Uber Clone - Part III - Transcript.pdf
Creating an Uber Clone - Part III - Transcript.pdf
ShaiAlmog1
 
Trident International Graphics Workshop 2014 1/5
Trident International Graphics Workshop 2014 1/5Trident International Graphics Workshop 2014 1/5
Trident International Graphics Workshop 2014 1/5
Takao Wada
 
openFrameworks 007 - graphics
openFrameworks 007 - graphicsopenFrameworks 007 - graphics
openFrameworks 007 - graphicsroxlu
 
Creating an Uber Clone - Part VII - Transcript.pdf
Creating an Uber Clone - Part VII - Transcript.pdfCreating an Uber Clone - Part VII - Transcript.pdf
Creating an Uber Clone - Part VII - Transcript.pdf
ShaiAlmog1
 
7. chapter vi
7. chapter vi7. chapter vi
7. chapter vi
Chhom Karath
 
Animations - Part 3.pdf
Animations - Part 3.pdfAnimations - Part 3.pdf
Animations - Part 3.pdf
ShaiAlmog1
 
Yahoo Open Source - The Tour & Mystery of AppDevKit (MOPCON 2016)
Yahoo Open Source - The Tour & Mystery of AppDevKit (MOPCON 2016)Yahoo Open Source - The Tour & Mystery of AppDevKit (MOPCON 2016)
Yahoo Open Source - The Tour & Mystery of AppDevKit (MOPCON 2016)
anistar sung
 
203 Is It Real or Is It Virtual? Augmented Reality on the iPhone
203 Is It Real or Is It Virtual? Augmented Reality on the iPhone203 Is It Real or Is It Virtual? Augmented Reality on the iPhone
203 Is It Real or Is It Virtual? Augmented Reality on the iPhone
jonmarimba
 
Webgl para JavaScripters
Webgl para JavaScriptersWebgl para JavaScripters
Webgl para JavaScriptersgerbille
 
OpenGL L06-Performance
OpenGL L06-PerformanceOpenGL L06-Performance
OpenGL L06-Performance
Mohammad Shaker
 
Kotlin Mullets
Kotlin MulletsKotlin Mullets
Kotlin Mullets
James Ward
 
Computer graphics
Computer graphicsComputer graphics
Computer graphicsamitsarda3
 

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

Introduction to graphics programming in c
Introduction to graphics programming in cIntroduction to graphics programming in c
Introduction to graphics programming in c
 
Leaving Flatland: getting started with WebGL
Leaving Flatland: getting started with WebGLLeaving Flatland: getting started with WebGL
Leaving Flatland: getting started with WebGL
 
Maps - Part 3 - Transcript.pdf
Maps - Part 3 - Transcript.pdfMaps - Part 3 - Transcript.pdf
Maps - Part 3 - Transcript.pdf
 
Graphics in C++
Graphics in C++Graphics in C++
Graphics in C++
 
Applications
ApplicationsApplications
Applications
 
Trident International Graphics Workshop 2014 5/5
Trident International Graphics Workshop 2014 5/5Trident International Graphics Workshop 2014 5/5
Trident International Graphics Workshop 2014 5/5
 
C Graphics Functions
C Graphics FunctionsC Graphics Functions
C Graphics Functions
 
Creating an Uber Clone - Part III - Transcript.pdf
Creating an Uber Clone - Part III - Transcript.pdfCreating an Uber Clone - Part III - Transcript.pdf
Creating an Uber Clone - Part III - Transcript.pdf
 
Trident International Graphics Workshop 2014 1/5
Trident International Graphics Workshop 2014 1/5Trident International Graphics Workshop 2014 1/5
Trident International Graphics Workshop 2014 1/5
 
Games 3 dl4-example
Games 3 dl4-exampleGames 3 dl4-example
Games 3 dl4-example
 
openFrameworks 007 - graphics
openFrameworks 007 - graphicsopenFrameworks 007 - graphics
openFrameworks 007 - graphics
 
Creating an Uber Clone - Part VII - Transcript.pdf
Creating an Uber Clone - Part VII - Transcript.pdfCreating an Uber Clone - Part VII - Transcript.pdf
Creating an Uber Clone - Part VII - Transcript.pdf
 
7. chapter vi
7. chapter vi7. chapter vi
7. chapter vi
 
Animations - Part 3.pdf
Animations - Part 3.pdfAnimations - Part 3.pdf
Animations - Part 3.pdf
 
Yahoo Open Source - The Tour & Mystery of AppDevKit (MOPCON 2016)
Yahoo Open Source - The Tour & Mystery of AppDevKit (MOPCON 2016)Yahoo Open Source - The Tour & Mystery of AppDevKit (MOPCON 2016)
Yahoo Open Source - The Tour & Mystery of AppDevKit (MOPCON 2016)
 
203 Is It Real or Is It Virtual? Augmented Reality on the iPhone
203 Is It Real or Is It Virtual? Augmented Reality on the iPhone203 Is It Real or Is It Virtual? Augmented Reality on the iPhone
203 Is It Real or Is It Virtual? Augmented Reality on the iPhone
 
Webgl para JavaScripters
Webgl para JavaScriptersWebgl para JavaScripters
Webgl para JavaScripters
 
OpenGL L06-Performance
OpenGL L06-PerformanceOpenGL L06-Performance
OpenGL L06-Performance
 
Kotlin Mullets
Kotlin MulletsKotlin Mullets
Kotlin Mullets
 
Computer graphics
Computer graphicsComputer graphics
Computer graphics
 

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.pdf
ShaiAlmog1
 
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
ShaiAlmog1
 
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
ShaiAlmog1
 
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
ShaiAlmog1
 
create-netflix-clone-01-introduction.pdf
create-netflix-clone-01-introduction.pdfcreate-netflix-clone-01-introduction.pdf
create-netflix-clone-01-introduction.pdf
ShaiAlmog1
 
create-netflix-clone-06-client-ui_transcript.pdf
create-netflix-clone-06-client-ui_transcript.pdfcreate-netflix-clone-06-client-ui_transcript.pdf
create-netflix-clone-06-client-ui_transcript.pdf
ShaiAlmog1
 
create-netflix-clone-03-server.pdf
create-netflix-clone-03-server.pdfcreate-netflix-clone-03-server.pdf
create-netflix-clone-03-server.pdf
ShaiAlmog1
 
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
ShaiAlmog1
 
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
ShaiAlmog1
 
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
ShaiAlmog1
 
create-netflix-clone-02-server.pdf
create-netflix-clone-02-server.pdfcreate-netflix-clone-02-server.pdf
create-netflix-clone-02-server.pdf
ShaiAlmog1
 
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
ShaiAlmog1
 
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
ShaiAlmog1
 
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
ShaiAlmog1
 
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
ShaiAlmog1
 
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
ShaiAlmog1
 
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
ShaiAlmog1
 
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
ShaiAlmog1
 
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
ShaiAlmog1
 

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-06-client-ui_transcript.pdf
create-netflix-clone-06-client-ui_transcript.pdfcreate-netflix-clone-06-client-ui_transcript.pdf
create-netflix-clone-06-client-ui_transcript.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
 

Recently uploaded

Key Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdfKey Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdf
Cheryl Hung
 
ODC, Data Fabric and Architecture User Group
ODC, Data Fabric and Architecture User GroupODC, Data Fabric and Architecture User Group
ODC, Data Fabric and Architecture User Group
CatarinaPereira64715
 
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 previewState of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
Prayukth K V
 
From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
Product School
 
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
Product School
 
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Ramesh Iyer
 
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptxIOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
Abida Shariff
 
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
Sri Ambati
 
Essentials of Automations: Optimizing FME Workflows with Parameters
Essentials of Automations: Optimizing FME Workflows with ParametersEssentials of Automations: Optimizing FME Workflows with Parameters
Essentials of Automations: Optimizing FME Workflows with Parameters
Safe Software
 
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdfFIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance
 
UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4
DianaGray10
 
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
UiPathCommunity
 
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
Product School
 
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
DanBrown980551
 
Accelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish CachingAccelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish Caching
Thijs Feryn
 
Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........
Alison B. Lowndes
 
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdfFIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance
 
When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...
Elena Simperl
 
UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3
DianaGray10
 
PHP Frameworks: I want to break free (IPC Berlin 2024)
PHP Frameworks: I want to break free (IPC Berlin 2024)PHP Frameworks: I want to break free (IPC Berlin 2024)
PHP Frameworks: I want to break free (IPC Berlin 2024)
Ralf Eggert
 

Recently uploaded (20)

Key Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdfKey Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdf
 
ODC, Data Fabric and Architecture User Group
ODC, Data Fabric and Architecture User GroupODC, Data Fabric and Architecture User Group
ODC, Data Fabric and Architecture User Group
 
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 previewState of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
 
From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
 
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
 
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
 
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptxIOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
 
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
 
Essentials of Automations: Optimizing FME Workflows with Parameters
Essentials of Automations: Optimizing FME Workflows with ParametersEssentials of Automations: Optimizing FME Workflows with Parameters
Essentials of Automations: Optimizing FME Workflows with Parameters
 
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdfFIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
 
UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4
 
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
 
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
 
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
 
Accelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish CachingAccelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish Caching
 
Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........
 
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdfFIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
 
When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...
 
UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3
 
PHP Frameworks: I want to break free (IPC Berlin 2024)
PHP Frameworks: I want to break free (IPC Berlin 2024)PHP Frameworks: I want to break free (IPC Berlin 2024)
PHP Frameworks: I want to break free (IPC Berlin 2024)
 

Creating an Uber Clone - Part XXII - Transcript.pdf

  • 1. Creating an Uber Clone - Part XXII With that out of the way search should work but how does it display the result? For that we need to add additional features to the MapForm that address these capabilities. Before we go into that lets check out what that means
  • 2. Routes © Codename One 2017 all rights reserved The ride booking UI plots the path of the ride on the map and includes two tags one pointing at your current location and one on the destination. The first tag is divided to a "time indication" and name. The latter only contains the name. Notice that the elements have a rounded rectangle shape with a pointy end on one side to point at the position within the path.
  • 3. private Component createNavigationTag(String location, int durationMinutes) { Label locationLabel = new Label(location, "NavigationLabel"); if(durationMinutes > 0) { Label duration = new Label("" + durationMinutes, "NavigationMinuteLabel"); Label min = new Label("MIN", "NavigationMinuteDescLabel"); Container west = BoxLayout.encloseY(duration, min); Container result = BorderLayout.centerEastWest(locationLabel, null, west); result.getUnselectedStyle().setBorder(BlackAndWhiteBorder.create(). blackLinePosition(west.getPreferredW())); return result; } locationLabel.getUnselectedStyle().setBorder( BlackAndWhiteBorder.create()); return locationLabel; } addMapListener Lets start with creating these tags. The tag code itself is trivial it's just a Label or a Container with some details. Nothing special. Except for one important detail, the BlackAndWhiteBorder. In order to implement the unique shape of the tag I created a new Border class. Notice I used the preferred width of the west component to determine the black section. This is done in the blackLinePosition method. Before we go any further I’d just like to make one point clear: I Would have Used a 9-piece Border. If this were a real application I would have just cut a 9-piece border and moved on. However, since the point is teaching I chose to do this the "hard way"
  • 4. NavigationLabel © Codename One 2017 all rights reserved Before we get into the BlackAndWhiteBorder there are a few UIID's we need to define. The NavigationLabel UIID is a the black on white label that appears in the tag.
  • 5. NavigationLabel © Codename One 2017 all rights reserved The only unique thing about it is the relatively small amount of padding so the tag doesn’t take up too much space
  • 6. NavigationLabel © Codename One 2017 all rights reserved The margin is predictably zero
  • 7. NavigationLabel © Codename One 2017 all rights reserved And the font is slightly smaller than usual
  • 8. NavigationMinuteLabel © Codename One 2017 all rights reserved The NavigationMinuteLabel UIID is the white on black minute value.
  • 9. NavigationMinuteLabel © Codename One 2017 all rights reserved It’s center aligned
  • 10. NavigationMinuteLabel © Codename One 2017 all rights reserved It has 0 padding below to keep the text and number close together but has similar paddings on the other sides to match the NavigationLabel
  • 11. NavigationMinuteLabel © Codename One 2017 all rights reserved It has zero margin
  • 12. NavigationMinuteLabel © Codename One 2017 all rights reserved and it has a smaller font size than usual although not a tiny font
  • 13. NavigationMinuteDescLabel © Codename One 2017 all rights reserved The NavigationMinuteDescLabel UIID is used for the text below that. The text with the word “MIN”. It derives from NavigationMinuteLabel
  • 14. NavigationMinuteDescLabel © Codename One 2017 all rights reserved And has an even smaller font than that…
  • 15. public class BlackAndWhiteBorder extends Border { private static final String CACHE_KEY = "cn1$$-bwcache"; private final float shadowBlur = 10; private final float shadowSpread; private final int shadowOpacity = 110; private final float cornerRadius = 1f; private int blackLinePosition = -1; BlackAndWhiteBorder() { shadowSpread = Display.getInstance().convertToPixels(0.2f); } public static BlackAndWhiteBorder create() { return new BlackAndWhiteBorder(); } public BlackAndWhiteBorder blackLinePosition(int blackLinePosition) { this.blackLinePosition = blackLinePosition; return this; } private Image createTargetImage(Component c, int w, int h, boolean fast) { Image target = Image.createImage(w, h, 0); int shapeX = 0; int shapeY = 0; int shapeW = w; int shapeH = h; BlackAndWhiteBorder Now that these are out of the way let's take a look at the border. Notice we can just subclass the Border class just like we can implement painters etc. This provides a similar path for customization but is sometimes more flexible. Most of this code is based on the builtin RoundRectBorder class. Drawing this type of border is pretty expensive so we draw onto an image and place that image in cache within the component using putClientProperty we use this value as the key
  • 16. public class BlackAndWhiteBorder extends Border { private static final String CACHE_KEY = "cn1$$-bwcache"; private final float shadowBlur = 10; private final float shadowSpread; private final int shadowOpacity = 110; private final float cornerRadius = 1f; private int blackLinePosition = -1; BlackAndWhiteBorder() { shadowSpread = Display.getInstance().convertToPixels(0.2f); } public static BlackAndWhiteBorder create() { return new BlackAndWhiteBorder(); } public BlackAndWhiteBorder blackLinePosition(int blackLinePosition) { this.blackLinePosition = blackLinePosition; return this; } private Image createTargetImage(Component c, int w, int h, boolean fast) { Image target = Image.createImage(w, h, 0); int shapeX = 0; int shapeY = 0; int shapeW = w; int shapeH = h; BlackAndWhiteBorder The blackLinePosition is used in the version of this border that's partially black
  • 17. private Image createTargetImage(Component c, int w, int h, boolean fast) { Image target = Image.createImage(w, h, 0); int shapeX = 0; int shapeY = 0; int shapeW = w; int shapeH = h; Graphics tg = target.getGraphics(); tg.setAntiAliased(true); int shadowSpreadL = Display.getInstance().convertToPixels(shadowSpread); shapeW -= shadowSpreadL; shapeH -= shadowSpreadL; shapeX += Math.round(((float)shadowSpreadL) * 0.9); shapeY += Math.round(((float)shadowSpreadL) * 0.9); for(int iter = shadowSpreadL - 1 ; iter >= 0 ; iter--) { tg.translate(iter, iter); fillShape(tg, 0, shadowOpacity / shadowSpreadL, w-(iter*2),h - (iter * 2)); tg.translate(-iter, -iter); } if(Display.getInstance().isGaussianBlurSupported() && !fast) { Image blured = Display.getInstance().gaussianBlurImage(target,shadowBlur/2); target = Image.createImage(w, h, 0); tg = target.getGraphics(); tg.drawImage(blured, 0, 0); BlackAndWhiteBorder Here we create the border image that we will cache for the given component. Since a shadow is set on the border and that can take some processing power. To speed this up we have two versions of the method fast and slow. We call the fast one and invoke the slow one asynchronously to update the border
  • 18. private Image createTargetImage(Component c, int w, int h, boolean fast) { Image target = Image.createImage(w, h, 0); int shapeX = 0; int shapeY = 0; int shapeW = w; int shapeH = h; Graphics tg = target.getGraphics(); tg.setAntiAliased(true); int shadowSpreadL = Display.getInstance().convertToPixels(shadowSpread); shapeW -= shadowSpreadL; shapeH -= shadowSpreadL; shapeX += Math.round(((float)shadowSpreadL) * 0.9); shapeY += Math.round(((float)shadowSpreadL) * 0.9); for(int iter = shadowSpreadL - 1 ; iter >= 0 ; iter--) { tg.translate(iter, iter); fillShape(tg, 0, shadowOpacity / shadowSpreadL, w-(iter*2),h - (iter * 2)); tg.translate(-iter, -iter); } if(Display.getInstance().isGaussianBlurSupported() && !fast) { Image blured = Display.getInstance().gaussianBlurImage(target,shadowBlur/2); target = Image.createImage(w, h, 0); tg = target.getGraphics(); tg.drawImage(blured, 0, 0); BlackAndWhiteBorder We do a shadow effect by drawing a gradient with varying alpha degrees then blurring that out
  • 19. tg.drawImage(blured, 0, 0); tg.setAntiAliased(true); } tg.translate(shapeX, shapeY); c.getStyle().setBorder(Border.createEmpty()); GeneralPath gp = createShape(shapeW, shapeH); tg.setClip(gp); c.getStyle().getBgPainter().paint(tg, new Rectangle(0, 0, w, h)); c.getStyle().setBorder(this); return target; } public void paintBorderBackground(Graphics g, final Component c) { final int w = c.getWidth(); final int h = c.getHeight(); int x = c.getX(); int y = c.getY(); if(w > 0 && h > 0) { Image background = (Image)c.getClientProperty(CACHE_KEY); if(background!=null && background.getWidth()==w && background.getHeight()==h){ g.drawImage(background, x, y); return; } BlackAndWhiteBorder If we have a cached version of the border image we will just use that as the background of the component assuming the size of the component didn't change
  • 20. int y = c.getY(); if(w > 0 && h > 0) { Image background = (Image)c.getClientProperty(CACHE_KEY); if(background!=null && background.getWidth()==w && background.getHeight()==h){ g.drawImage(background, x, y); return; } } else { return; } Image target = createTargetImage(c, w, h, true); g.drawImage(target, x, y); c.putClientProperty(CACHE_KEY, target); Display.getInstance().callSeriallyOnIdle(new Runnable() { public void run() { if(w == c.getWidth() && h == c.getHeight()) { Image target = createTargetImage(c, w, h, false); c.putClientProperty(CACHE_KEY, target); c.repaint(); } } BlackAndWhiteBorder Otherwise we create that image and update it later with the slower version that includes the gradient shadow effect
  • 21. c.putClientProperty(CACHE_KEY, target); c.repaint(); } } }); } private GeneralPath createShape(int shapeW, int shapeH) { GeneralPath gp = new GeneralPath(); float radius = Display.getInstance().convertToPixels(cornerRadius); float x = 0; float y = 0; float widthF = shapeW; float heightF = shapeH; gp.moveTo(x + radius, y); if(blackLinePosition > -1) { gp.lineTo(x + widthF, y); } else { gp.lineTo(x + widthF - radius, y); gp.quadTo(x + widthF, y, x + widthF, y + radius); } gp.lineTo(x + widthF, y + heightF - radius); gp.quadTo(x + widthF, y + heightF, x + widthF - radius, y + heightF); if(blackLinePosition > -1) { BlackAndWhiteBorder We create the shape of the component. If it's the one with the black line we place the corner in the top right otherwise we place it in the bottom left
  • 22. gp.quadTo(x + widthF, y + heightF, x + widthF - radius, y + heightF); if(blackLinePosition > -1) { gp.lineTo(x + radius, y + heightF); gp.quadTo(x, y + heightF, x, y + heightF - radius); } else { gp.lineTo(x, y + heightF); } gp.lineTo(x, y + radius); gp.quadTo(x, y, x + radius, y); gp.closePath(); return gp; } public int getMinimumHeight() { return convertToPixels(shadowSpread) + convertToPixels(cornerRadius) * 2; } public int getMinimumWidth() { return convertToPixels(shadowSpread) + convertToPixels(cornerRadius) * 2; } private void fillShape(Graphics g, int color, int opacity, int width, int height) { g.setColor(0xffffff); g.setAlpha(255); GeneralPath gp = createShape(width, height); if(blackLinePosition > -1) { BlackAndWhiteBorder We can now fill out the shape as part of the image creation code if we have a black line we do the fill operation twice with different clip sizes to create that effect