SlideShare uma empresa Scribd logo
1 de 105
Baixar para ler offline
Building UI Consistent Android Apps
Nicola Corti
@cortinico
nco@yelp.com
Yelp Mission
Connecting people with great local businesses.
About me
Nicola Corti
Android @BizCore
nco@yelp.com
@cortinico
Community Addicted
!🍕🕹🎤📸✈🏞
What is
Consistency?
“Unified use of Design Elements, such as color,
typography, spatial layout and behaviors.
Functional
Internal Consistency
Visual
External Consistency - Across Product
External Consistency - Across Platform
Benefits
• Learnability
• Reduce frustrations
• Save money/time 💰
Photo by davelawler/CC BY - NC
How to tackle
Consistency?
⌘ R⇧+ +
Source: GIPHY
External Examples
• Google Material Design
• Apple Design Guidelines
• Github Primer
http://styleguides.io/
github.com/alexpate/awesome-design-systems
Consistency
@Yelp
Mobile Apps
yelp.com/styleguide
The Android
Styleguide
Library
Design Build Share
Design
Does it fit?
• Can it be reused?
• Is it visible to the user?
• Development plan?
User photo User name timestamp
friends, media
checkins
Elite badge
description
Attributes
<resources>

</resources>
Attributes
<resources>

<declare-styleable name="UserPassport">

</declare-styleable>

</resources>
Attributes
<resources>

<declare-styleable name="UserPassport">

<!-- Determines user's name -->

<attr name="userPassportName" format="string"/>

</declare-styleable>

</resources>
Attributes
<resources>

<declare-styleable name="UserPassport">

<!-- Determines user's name -->

<attr name="userPassportName" format="string"/>



<!-- Determines user's description/role -->

<attr name="userPassportDescription" format="string"/>

</declare-styleable>

</resources>
Attributes
<resources>

<declare-styleable name="UserPassport">

<!-- Determines user's name -->

<attr name="userPassportName" format="string"/>



<!-- Determines user's description/role -->

<attr name="userPassportDescription" format="string"/>

</declare-styleable>

<attr name="userPassportStyle" format="reference"/>

</resources>
Theme
Theme
<resources>

<!—- This theme is the parent of all themes of Yelp's android apps. —->

<style name="YelpStyleguideTheme"/>

</resources>
Theme
<resources>

<!—- This theme is the parent of all themes of Yelp's android apps. —->

<style name="YelpStyleguideTheme" parent=“Theme.AppCompat.Light.DarkActionBar"/>

</resources>
Theme
<resources>

<!—- This theme is the parent of all themes of Yelp's android apps. —->

<style name="YelpStyleguideTheme" parent=“Theme.AppCompat.Light.DarkActionBar">

<item name="userPassportStyle">@style/UserPassport</item>

</style>

</resources>
Styles
Styles
<style name=“UserPassport"/>
Styles
<style name=“UserPassport">

<item name="userPassportName">Joe Smith</item>

</style>
Styles
<style name=“UserPassport">

<item name="userPassportName">Joe Smith</item>

<item name="userPassportDescription">Owner of Sample Business</item>

</style>
UserPassport
public class UserPassport extends RelativeLayout {

public class UserPassport extends RelativeLayout {



private TextView mUserName;

private TextView mDescription;

public class UserPassport extends RelativeLayout {



private TextView mUserName;

private TextView mDescription;



public void setName(String name) {

mUserName.setText(name);

}





public class UserPassport extends RelativeLayout {



private TextView mUserName;

private TextView mDescription;



public void setName(String name) {

mUserName.setText(name);

}



public void setDescription(String description) {

if (TextUtils.isEmpty(description)) {

mDescription.setVisibility(GONE);

} else {

mDescription.setVisibility(VISIBLE);

mDescription.setText(description);

}

}



public class UserPassport extends RelativeLayout {



private TextView mUserName;

private TextView mDescription;

public class UserPassport extends RelativeLayout {



private TextView mUserName;

private TextView mDescription;



public UserPassport(final Context context) {

super(context);

init(context, null, 0);

}



public UserPassport(final Context context, final AttributeSet attrs) {

super(context, attrs);

init(context, attrs, R.attr.userPassportStyle);

}



public UserPassport(final Context context, final AttributeSet attrs,
final int defStyleAttr) {

super(context, attrs, defStyleAttr);

init(context, attrs, defStyleAttr);

}
public class UserPassport extends RelativeLayout {



private TextView mUserName;

private TextView mDescription;



public UserPassport(final Context context) {

super(context);

init(context, null, 0);

}



public UserPassport(final Context context, final AttributeSet attrs) {

super(context, attrs);

init(context, attrs, R.attr.userPassportStyle);

}



public UserPassport(final Context context, final AttributeSet attrs,
final int defStyleAttr) {

super(context, attrs, defStyleAttr);

init(context, attrs, defStyleAttr);

}
public class UserPassport extends RelativeLayout {



private TextView mUserName;

private TextView mDescription;



private void init(

final Context context, final AttributeSet attrs, final int defStyleAttr) {


}



public class UserPassport extends RelativeLayout {



private TextView mUserName;

private TextView mDescription;



private void init(

final Context context, final AttributeSet attrs, final int defStyleAttr) {


LayoutInflater.from(context).inflate(R.layout.user_passport, this, true);


}



public class UserPassport extends RelativeLayout {



private TextView mUserName;

private TextView mDescription;



private void init(

final Context context, final AttributeSet attrs, final int defStyleAttr) {


LayoutInflater.from(context).inflate(R.layout.user_passport, this, true);


mUserName = (TextView) findViewById(R.id.user_name);

mDescription = (TextView) findViewById(R.id.description);



}



public class UserPassport extends RelativeLayout {



private TextView mUserName;

private TextView mDescription;



private void init(

final Context context, final AttributeSet attrs, final int defStyleAttr) {


LayoutInflater.from(context).inflate(R.layout.user_passport, this, true);


mUserName = (TextView) findViewById(R.id.user_name);

mDescription = (TextView) findViewById(R.id.description);



final TypedArray styles = context.obtainStyledAttributes(attrs,
R.styleable.UserPassport, defStyleAttr, 0);



}

public class UserPassport extends RelativeLayout {



private TextView mUserName;

private TextView mDescription;



private void init(

final Context context, final AttributeSet attrs, final int defStyleAttr) {


LayoutInflater.from(context).inflate(R.layout.user_passport, this, true);


mUserName = (TextView) findViewById(R.id.user_name);

mDescription = (TextView) findViewById(R.id.description);



final TypedArray styles = context.obtainStyledAttributes(attrs,
R.styleable.UserPassport, defStyleAttr, 0);



setName(styles.getString(R.styleable.UserPassport_userPassportName));
setDescription(styles.getString(
R.styleable.UserPassport_userPassportDescription));



}



public class UserPassport extends RelativeLayout {



private TextView mUserName;

private TextView mDescription;



private void init(

final Context context, final AttributeSet attrs, final int defStyleAttr) {


LayoutInflater.from(context).inflate(R.layout.user_passport, this, true);


mUserName = (TextView) findViewById(R.id.user_name);

mDescription = (TextView) findViewById(R.id.description);



final TypedArray styles = context.obtainStyledAttributes(attrs,
R.styleable.UserPassport, defStyleAttr, 0);



setName(styles.getString(R.styleable.UserPassport_userPassportName));
setDescription(styles.getString(
R.styleable.UserPassport_userPassportDescription));



styles.recycle();

}



<style name="UserPassport">

<item name="userPassportName">Joe Smith</item>

<item name="userPassportDescription">@null</item>

<item name="userPassportTint">@color/orange_dark_interface</item>

<item name="userPassportNameColor">@color/black_regular_interface</item>

<item name="userPassportSize">Regular</item>

<item name="userPassportShowName">true</item>

<item name="userPassportShowIcons">true</item>

<item name="userPassportEliteYear">-1</item>

<item name="userPassportFriends">0</item>

<item name="userPassportReviews">0</item>

<item name="userPassportPhotos">0</item>

<item name="userPassportCheckIns">0</item>

<item name="userPassportShowCheckIn">false</item>

</style>
<style name="UserPassport.White">

<item name="userPassportName">Joe Smith</item>

<item name="userPassportDescription">@null</item>

<item name="userPassportTint">@color/orange_dark_interface</item>

<item name="userPassportNameColor">@color/black_regular_interface</item>

<item name="userPassportSize">Regular</item>

<item name="userPassportShowName">true</item>

<item name="userPassportShowIcons">true</item>

<item name="userPassportEliteYear">-1</item>

<item name="userPassportFriends">0</item>

<item name="userPassportReviews">0</item>

<item name="userPassportPhotos">0</item>

<item name="userPassportCheckIns">0</item>

<item name="userPassportShowCheckIn">false</item>

</style>
<style name="UserPassport.White">

<item name="userPassportName">Joe Smith</item>

<item name="userPassportDescription">@null</item>

<item name="userPassportTint">@color/white_interface</item>

<item name="userPassportNameColor">@color/white_interface</item>

<item name="userPassportSize">Regular</item>

<item name="userPassportShowName">true</item>

<item name="userPassportShowIcons">true</item>

<item name="userPassportEliteYear">-1</item>

<item name="userPassportFriends">0</item>

<item name="userPassportReviews">0</item>

<item name="userPassportPhotos">0</item>

<item name="userPassportCheckIns">0</item>

<item name="userPassportShowCheckIn">false</item>

</style>
<style name="UserPassport.White">

<item name="userPassportTint">@color/white_interface</item>

<item name="userPassportNameColor">@color/white_interface</item>

</style>
Color Palette
Illustrations
Assets
dependencies {



// Yelp asset libs

compile 'com.yelp:yelpicons:135.0.0'

compile ‘com.yelp:yelpdesign:4.0.4’
}
Assets
dependencies {



// Yelp asset libs

compile 'com.yelp:yelpicons:135.0.0'

compile ‘com.yelp:yelpdesign:4.0.4’
}
Color
Color
<color name="black_extra_light_interface">#666666</color>

<color name="black_regular_interface">#333333</color>

<color name="blue_dark_interface">#0073bb</color>

<color name="blue_extra_light_interface">#d0ecfb</color>

<color name="blue_regular_interface">#0097ec</color>

<color name="gray_dark_interface">#999999</color>

<color name="gray_extra_light_interface">#f5f5f5</color>

<color name="gray_light_interface">#e6e6e6</color>

<color name="gray_regular_interface">#cccccc</color>

<color name="green_extra_light_interface">#daecd2</color>

<color name="green_regular_interface">#41a700</color>

<color name="mocha_extra_light_interface">#f8e3c7</color>

<color name="mocha_light_interface">#f1bd79</color>

<color name="orange_dark_interface">#f15c00</color>

<color name="orange_extra_light_interface">#ffebcf</color>

<color name="purple_extra_light_interface">#dad1e4</color>

<color name="red_dark_interface">#d32323</color>

<color name="red_extra_light_interface">#fcd6d3</color>

<color name="slate_extra_light_interface">#cddae2</color>

<color name="white_interface">#ffffff</color>

<color name="yellow_dark_interface">#fec011</color>

<color name="yellow_extra_light_interface">#fff7cc</color>
Color
<color name="black_extra_light_interface">#666666</color>

<color name="black_regular_interface">#333333</color>

<color name="blue_dark_interface">#0073bb</color>

<color name="blue_extra_light_interface">#d0ecfb</color>

<color name="blue_regular_interface">#0097ec</color>

<color name="gray_dark_interface">#999999</color>

<color name="gray_extra_light_interface">#f5f5f5</color>

<color name="gray_light_interface">#e6e6e6</color>

<color name="gray_regular_interface">#cccccc</color>

<color name="green_extra_light_interface">#daecd2</color>

<color name="green_regular_interface">#41a700</color>

<color name="mocha_extra_light_interface">#f8e3c7</color>

<color name="mocha_light_interface">#f1bd79</color>

<color name="orange_dark_interface">#f15c00</color>

<color name="orange_extra_light_interface">#ffebcf</color>

<color name="purple_extra_light_interface">#dad1e4</color>

<color name="red_dark_interface">#d32323</color>

<color name="red_extra_light_interface">#fcd6d3</color>

<color name="slate_extra_light_interface">#cddae2</color>

<color name="white_interface">#ffffff</color>

<color name="yellow_dark_interface">#fec011</color>

<color name="yellow_extra_light_interface">#fff7cc</color>
Color
<color name="black_extra_light_interface">#666666</color>

<color name="black_regular_interface">#333333</color>

<color name="blue_dark_interface">#0073bb</color>

<color name="blue_extra_light_interface">#d0ecfb</color>

<color name="blue_regular_interface">#0097ec</color>

<color name="gray_dark_interface">#999999</color>

<color name="gray_extra_light_interface">#f5f5f5</color>

<color name="gray_light_interface">#e6e6e6</color>

<color name="gray_regular_interface">#cccccc</color>

<color name="green_extra_light_interface">#daecd2</color>

<color name="green_regular_interface">#41a700</color>

<color name="mocha_extra_light_interface">#f8e3c7</color>

<color name="mocha_light_interface">#f1bd79</color>

<color name="orange_dark_interface">#f15c00</color>

<color name="orange_extra_light_interface">#ffebcf</color>

<color name="purple_extra_light_interface">#dad1e4</color>

<color name="red_dark_interface">#d32323</color>

<color name="red_extra_light_interface">#fcd6d3</color>

<color name="slate_extra_light_interface">#cddae2</color>

<color name="white_interface">#ffffff</color>

<color name="yellow_dark_interface">#fec011</color>

<color name="yellow_extra_light_interface">#fff7cc</color>
Build
Review Template
VCS & CI
• git submodule
• Run the Build for
• submodule
• consumer app
• business app
Custom Lint Checks
Custom Lint Checks


Button b = new Button(context);



SwitchCompat switchCompat = new SwitchCompat(context);



Snackbar.make(getRootView(), “Test”, LENGTH_SHORT).show();
Custom Lint Checks
@SuppressLint("")

Button b = new Button(context);



@SuppressLint("")

SwitchCompat switchCompat = new SwitchCompat(context);



@SuppressLint("")

Snackbar.make(getRootView(), “Test”, LENGTH_SHORT).show();
Custom Lint Checks
@SuppressLint("NonStyleguideButtonInstance")

Button b = new Button(context);



@SuppressLint("")

SwitchCompat switchCompat = new SwitchCompat(context);



@SuppressLint("")

Snackbar.make(getRootView(), “Test”, LENGTH_SHORT).show();
Custom Lint Checks
@SuppressLint("NonStyleguideButtonInstance")

Button b = new Button(context);



@SuppressLint("NonStyleguideToggleInstance")

SwitchCompat switchCompat = new SwitchCompat(context);



@SuppressLint("")

Snackbar.make(getRootView(), “Test”, LENGTH_SHORT).show();
Custom Lint Checks
@SuppressLint("NonStyleguideButtonInstance")

Button b = new Button(context);



@SuppressLint("NonStyleguideToggleInstance")

SwitchCompat switchCompat = new SwitchCompat(context);



@SuppressLint("NonStyleguideSnackbarInstance")

Snackbar.make(getRootView(), “Test”, LENGTH_SHORT).show();
Custom Lint Checks
// Using stock Button because […] + Ticket number.
@SuppressLint("NonStyleguideButtonInstance")

Button b = new Button(context);



@SuppressLint("NonStyleguideToggleInstance")

SwitchCompat switchCompat = new SwitchCompat(context);



@SuppressLint("NonStyleguideSnackbarInstance")

Snackbar.make(getRootView(), “Test”, LENGTH_SHORT).show();
Custom Lint Checks
Custom Lint Checks
<Button

android:layout_width="match_parent"

android:layout_height="match_parent" />



<Switch

android:layout_width="match_parent"

android:layout_height="match_parent" />
Custom Lint Checks
<Button

android:layout_width="match_parent"

android:layout_height="match_parent"

tools:ignore="NonStyleguideButtonTag" />



<Switch

android:layout_width="match_parent"

android:layout_height="match_parent"

tools:ignore="NonStyleguideToggleTag" />
build.gradle
build.gradle
android {

lintOptions {



}

}
build.gradle
android {

lintOptions {

abortOnError true

warningsAsErrors true



}

}
build.gradle
android {

lintOptions {

abortOnError true

warningsAsErrors true



lintConfig file("lint.xml")

}

}
build.gradle
android {

lintOptions {

abortOnError true

warningsAsErrors true



lintConfig file("lint.xml")

baseline file("lint-baseline.xml")

}

}
Test your component
• Your component ❤ Espresso?
• Do you handle state changes?
• contentDescription ?
Share
Documentation
• Provide Javadoc
• Add Screenshots
• Document Attributes
• Document Styles
Screenshots capture
• v0.1: Manual Screenshots
• v0.2: Automated locally
• v0.3: Automated with CI 💫
StyleguideTestApp
• Components Showcase
• For Designer 🎨
• For Developer 🔧
Taking Screenshots with Espresso
public class ScreenshotViewActions {



}
Taking Screenshots with Espresso
public class ScreenshotViewActions {



public static ViewAction screenshot(final String folderName, final String fileName) {

return new ViewAction() {



};

}

}
Taking Screenshots with Espresso
public class ScreenshotViewActions {



public static ViewAction screenshot(final String folderName, final String fileName) {

return new ViewAction() {

// Other methods omitted.



@Override

public void perform(UiController uiController, View view) {

ScreenshotsUtil.takeScreenshot(folderName, fileName, view);

}

};

}

}
Sample Espresso Test
Sample Espresso Test
public class StarsViewActivityTests {



}
Sample Espresso Test
public class StarsViewActivityTests {



@Test

public void takeScreenshot() throws InterruptedException {

onView(withId(R.id.stars_view_4)).perform(setStarsNumber(4));



}

}
Sample Espresso Test
public class StarsViewActivityTests {



@Test

public void takeScreenshot() throws InterruptedException {

onView(withId(R.id.stars_view_4)).perform(setStarsNumber(4));

onView(withId(R.id.stars_view_5)).perform(setStarsNumber(5),

screenshot(FOLDER_NAME, "stars_with_text"));



}

}
Sample Espresso Test
public class StarsViewActivityTests {



@Test

public void takeScreenshot() throws InterruptedException {

onView(withId(R.id.stars_view_4)).perform(setStarsNumber(4));

onView(withId(R.id.stars_view_5)).perform(setStarsNumber(5),

screenshot(FOLDER_NAME, "stars_with_text"));



ScreenshotUtil.fullScreenshot(FOLDER_NAME, "stars_fullscreen");

}

}
Bend it, don’t break it!
Source: GIPHY
We are hiring!
www.yelp.com/careers/
Nicola Corti
@cortinico
nco@yelp.com
bit.ly/uiconsistency
@YelpEngineering
github.com/yelp
yelp.com/careers
engineeringblog.yelp.com

Mais conteúdo relacionado

Destaque

Anna Makarudze - Django Girls: Inspiring women to fall in love with programmi...
Anna Makarudze - Django Girls: Inspiring women to fall in love with programmi...Anna Makarudze - Django Girls: Inspiring women to fall in love with programmi...
Anna Makarudze - Django Girls: Inspiring women to fall in love with programmi...Codemotion
 
Alberto Maria Angelo Paro - Isomorphic programming in Scala and WebDevelopmen...
Alberto Maria Angelo Paro - Isomorphic programming in Scala and WebDevelopmen...Alberto Maria Angelo Paro - Isomorphic programming in Scala and WebDevelopmen...
Alberto Maria Angelo Paro - Isomorphic programming in Scala and WebDevelopmen...Codemotion
 
Claudio Carboni - ArcGIS platformthe foundation of your idea - Codemotion Mil...
Claudio Carboni - ArcGIS platformthe foundation of your idea - Codemotion Mil...Claudio Carboni - ArcGIS platformthe foundation of your idea - Codemotion Mil...
Claudio Carboni - ArcGIS platformthe foundation of your idea - Codemotion Mil...Codemotion
 
Giovanni Laquidara - Hello ARCore - Codemotion Milan 2017
Giovanni Laquidara - Hello ARCore - Codemotion Milan 2017Giovanni Laquidara - Hello ARCore - Codemotion Milan 2017
Giovanni Laquidara - Hello ARCore - Codemotion Milan 2017Codemotion
 
James Williams - Demystifying Constraint Layout - Codemotion Milan 2017
James Williams - Demystifying Constraint Layout - Codemotion Milan 2017James Williams - Demystifying Constraint Layout - Codemotion Milan 2017
James Williams - Demystifying Constraint Layout - Codemotion Milan 2017Codemotion
 
Tiffany Conroy - Remote device sign-in – Authenticating without a keyboard - ...
Tiffany Conroy - Remote device sign-in – Authenticating without a keyboard - ...Tiffany Conroy - Remote device sign-in – Authenticating without a keyboard - ...
Tiffany Conroy - Remote device sign-in – Authenticating without a keyboard - ...Codemotion
 
Matteo Manchi - React Native for multi-platform mobile applications - Codemot...
Matteo Manchi - React Native for multi-platform mobile applications - Codemot...Matteo Manchi - React Native for multi-platform mobile applications - Codemot...
Matteo Manchi - React Native for multi-platform mobile applications - Codemot...Codemotion
 
Erik Tiengo - Embedding Cisco Spark and Location applications (ESRI) into bus...
Erik Tiengo - Embedding Cisco Spark and Location applications (ESRI) into bus...Erik Tiengo - Embedding Cisco Spark and Location applications (ESRI) into bus...
Erik Tiengo - Embedding Cisco Spark and Location applications (ESRI) into bus...Codemotion
 
Erik Wendel - Beyond JavaScript Frameworks: Writing Reliable Web Apps With El...
Erik Wendel - Beyond JavaScript Frameworks: Writing Reliable Web Apps With El...Erik Wendel - Beyond JavaScript Frameworks: Writing Reliable Web Apps With El...
Erik Wendel - Beyond JavaScript Frameworks: Writing Reliable Web Apps With El...Codemotion
 
Agnieszka Naplocha - Breaking the norm with creative CSS - Codemotion Milan 2017
Agnieszka Naplocha - Breaking the norm with creative CSS - Codemotion Milan 2017Agnieszka Naplocha - Breaking the norm with creative CSS - Codemotion Milan 2017
Agnieszka Naplocha - Breaking the norm with creative CSS - Codemotion Milan 2017Codemotion
 
Oded Coster - Stack Overflow behind the scenes - how it's made - Codemotion M...
Oded Coster - Stack Overflow behind the scenes - how it's made - Codemotion M...Oded Coster - Stack Overflow behind the scenes - how it's made - Codemotion M...
Oded Coster - Stack Overflow behind the scenes - how it's made - Codemotion M...Codemotion
 
Cutting the Fat
Cutting the FatCutting the Fat
Cutting the FatCodemotion
 
Codemotion rome 2015 bluemix lab tutorial -- Codemotion Rome 2015
Codemotion rome 2015   bluemix lab tutorial -- Codemotion Rome 2015Codemotion rome 2015   bluemix lab tutorial -- Codemotion Rome 2015
Codemotion rome 2015 bluemix lab tutorial -- Codemotion Rome 2015Codemotion
 
Lean@core lean startup e cloud- - Codemotion Rome 2015
Lean@core   lean startup e cloud- - Codemotion Rome 2015Lean@core   lean startup e cloud- - Codemotion Rome 2015
Lean@core lean startup e cloud- - Codemotion Rome 2015Codemotion
 
Engineering Design for Facebook
Engineering Design for FacebookEngineering Design for Facebook
Engineering Design for FacebookCodemotion
 

Destaque (20)

Anna Makarudze - Django Girls: Inspiring women to fall in love with programmi...
Anna Makarudze - Django Girls: Inspiring women to fall in love with programmi...Anna Makarudze - Django Girls: Inspiring women to fall in love with programmi...
Anna Makarudze - Django Girls: Inspiring women to fall in love with programmi...
 
Alberto Maria Angelo Paro - Isomorphic programming in Scala and WebDevelopmen...
Alberto Maria Angelo Paro - Isomorphic programming in Scala and WebDevelopmen...Alberto Maria Angelo Paro - Isomorphic programming in Scala and WebDevelopmen...
Alberto Maria Angelo Paro - Isomorphic programming in Scala and WebDevelopmen...
 
Claudio Carboni - ArcGIS platformthe foundation of your idea - Codemotion Mil...
Claudio Carboni - ArcGIS platformthe foundation of your idea - Codemotion Mil...Claudio Carboni - ArcGIS platformthe foundation of your idea - Codemotion Mil...
Claudio Carboni - ArcGIS platformthe foundation of your idea - Codemotion Mil...
 
Giovanni Laquidara - Hello ARCore - Codemotion Milan 2017
Giovanni Laquidara - Hello ARCore - Codemotion Milan 2017Giovanni Laquidara - Hello ARCore - Codemotion Milan 2017
Giovanni Laquidara - Hello ARCore - Codemotion Milan 2017
 
James Williams - Demystifying Constraint Layout - Codemotion Milan 2017
James Williams - Demystifying Constraint Layout - Codemotion Milan 2017James Williams - Demystifying Constraint Layout - Codemotion Milan 2017
James Williams - Demystifying Constraint Layout - Codemotion Milan 2017
 
Tiffany Conroy - Remote device sign-in – Authenticating without a keyboard - ...
Tiffany Conroy - Remote device sign-in – Authenticating without a keyboard - ...Tiffany Conroy - Remote device sign-in – Authenticating without a keyboard - ...
Tiffany Conroy - Remote device sign-in – Authenticating without a keyboard - ...
 
Matteo Manchi - React Native for multi-platform mobile applications - Codemot...
Matteo Manchi - React Native for multi-platform mobile applications - Codemot...Matteo Manchi - React Native for multi-platform mobile applications - Codemot...
Matteo Manchi - React Native for multi-platform mobile applications - Codemot...
 
Erik Tiengo - Embedding Cisco Spark and Location applications (ESRI) into bus...
Erik Tiengo - Embedding Cisco Spark and Location applications (ESRI) into bus...Erik Tiengo - Embedding Cisco Spark and Location applications (ESRI) into bus...
Erik Tiengo - Embedding Cisco Spark and Location applications (ESRI) into bus...
 
Erik Wendel - Beyond JavaScript Frameworks: Writing Reliable Web Apps With El...
Erik Wendel - Beyond JavaScript Frameworks: Writing Reliable Web Apps With El...Erik Wendel - Beyond JavaScript Frameworks: Writing Reliable Web Apps With El...
Erik Wendel - Beyond JavaScript Frameworks: Writing Reliable Web Apps With El...
 
Agnieszka Naplocha - Breaking the norm with creative CSS - Codemotion Milan 2017
Agnieszka Naplocha - Breaking the norm with creative CSS - Codemotion Milan 2017Agnieszka Naplocha - Breaking the norm with creative CSS - Codemotion Milan 2017
Agnieszka Naplocha - Breaking the norm with creative CSS - Codemotion Milan 2017
 
Oded Coster - Stack Overflow behind the scenes - how it's made - Codemotion M...
Oded Coster - Stack Overflow behind the scenes - how it's made - Codemotion M...Oded Coster - Stack Overflow behind the scenes - how it's made - Codemotion M...
Oded Coster - Stack Overflow behind the scenes - how it's made - Codemotion M...
 
Cutting the Fat
Cutting the FatCutting the Fat
Cutting the Fat
 
9
99
9
 
Codemotion rome 2015 bluemix lab tutorial -- Codemotion Rome 2015
Codemotion rome 2015   bluemix lab tutorial -- Codemotion Rome 2015Codemotion rome 2015   bluemix lab tutorial -- Codemotion Rome 2015
Codemotion rome 2015 bluemix lab tutorial -- Codemotion Rome 2015
 
8
88
8
 
Lean@core lean startup e cloud- - Codemotion Rome 2015
Lean@core   lean startup e cloud- - Codemotion Rome 2015Lean@core   lean startup e cloud- - Codemotion Rome 2015
Lean@core lean startup e cloud- - Codemotion Rome 2015
 
5
55
5
 
Engineering Design for Facebook
Engineering Design for FacebookEngineering Design for Facebook
Engineering Design for Facebook
 
6
66
6
 
29
2929
29
 

Semelhante a Nicola Corti - Building UI Consistent Android Apps - Codemotion Milan 2017

Custom UI Components at Android Only 2011
Custom UI Components at Android Only 2011Custom UI Components at Android Only 2011
Custom UI Components at Android Only 2011Johan Nilsson
 
Data binding в массы! (1.2)
Data binding в массы! (1.2)Data binding в массы! (1.2)
Data binding в массы! (1.2)Yurii Kotov
 
Михаил Анохин "Data binding 2.0"
Михаил Анохин "Data binding 2.0"Михаил Анохин "Data binding 2.0"
Михаил Анохин "Data binding 2.0"Fwdays
 
"Android Data Binding в массы" Михаил Анохин
"Android Data Binding в массы" Михаил Анохин"Android Data Binding в массы" Михаил Анохин
"Android Data Binding в массы" Михаил АнохинFwdays
 
Intro to Dependency Injection - Or bar
Intro to Dependency Injection - Or bar Intro to Dependency Injection - Or bar
Intro to Dependency Injection - Or bar DroidConTLV
 
Architecture components - IT Talk
Architecture components - IT TalkArchitecture components - IT Talk
Architecture components - IT TalkConstantine Mars
 
Architecture Components
Architecture Components Architecture Components
Architecture Components DataArt
 
07_UIAndroid.pdf
07_UIAndroid.pdf07_UIAndroid.pdf
07_UIAndroid.pdfImranS18
 
Overview of Android Infrastructure
Overview of Android InfrastructureOverview of Android Infrastructure
Overview of Android InfrastructureAlexey Buzdin
 
Overview of Android Infrastructure
Overview of Android InfrastructureOverview of Android Infrastructure
Overview of Android InfrastructureC.T.Co
 
Boost Your Development With Proper API Design
Boost Your Development With Proper API DesignBoost Your Development With Proper API Design
Boost Your Development With Proper API DesignMarcusHeld1
 
Android Architecture Components - Guy Bar on, Vonage
Android Architecture Components - Guy Bar on, VonageAndroid Architecture Components - Guy Bar on, Vonage
Android Architecture Components - Guy Bar on, VonageDroidConTLV
 
Binding business data to vaadin components
Binding business data to vaadin componentsBinding business data to vaadin components
Binding business data to vaadin componentsPeter Lehto
 
Laravel - Speaking eloquent eloquently
Laravel - Speaking eloquent eloquentlyLaravel - Speaking eloquent eloquently
Laravel - Speaking eloquent eloquentlyLaravel Nigeria
 
05 content providers - Android
05   content providers - Android05   content providers - Android
05 content providers - AndroidWingston
 
Petcube epic battle: architecture vs product. UA Mobile 2017.
Petcube epic battle: architecture vs product. UA Mobile 2017.Petcube epic battle: architecture vs product. UA Mobile 2017.
Petcube epic battle: architecture vs product. UA Mobile 2017.UA Mobile
 
Android development for iOS developers
Android development for iOS developersAndroid development for iOS developers
Android development for iOS developersDarryl Bayliss
 

Semelhante a Nicola Corti - Building UI Consistent Android Apps - Codemotion Milan 2017 (20)

Custom UI Components at Android Only 2011
Custom UI Components at Android Only 2011Custom UI Components at Android Only 2011
Custom UI Components at Android Only 2011
 
Recyclerview in action
Recyclerview in action Recyclerview in action
Recyclerview in action
 
Data binding в массы! (1.2)
Data binding в массы! (1.2)Data binding в массы! (1.2)
Data binding в массы! (1.2)
 
Михаил Анохин "Data binding 2.0"
Михаил Анохин "Data binding 2.0"Михаил Анохин "Data binding 2.0"
Михаил Анохин "Data binding 2.0"
 
"Android Data Binding в массы" Михаил Анохин
"Android Data Binding в массы" Михаил Анохин"Android Data Binding в массы" Михаил Анохин
"Android Data Binding в массы" Михаил Анохин
 
Intro to Dependency Injection - Or bar
Intro to Dependency Injection - Or bar Intro to Dependency Injection - Or bar
Intro to Dependency Injection - Or bar
 
Architecture components - IT Talk
Architecture components - IT TalkArchitecture components - IT Talk
Architecture components - IT Talk
 
Architecture Components
Architecture Components Architecture Components
Architecture Components
 
07_UIAndroid.pdf
07_UIAndroid.pdf07_UIAndroid.pdf
07_UIAndroid.pdf
 
Overview of Android Infrastructure
Overview of Android InfrastructureOverview of Android Infrastructure
Overview of Android Infrastructure
 
Overview of Android Infrastructure
Overview of Android InfrastructureOverview of Android Infrastructure
Overview of Android Infrastructure
 
Boost Your Development With Proper API Design
Boost Your Development With Proper API DesignBoost Your Development With Proper API Design
Boost Your Development With Proper API Design
 
Android Architecture Components - Guy Bar on, Vonage
Android Architecture Components - Guy Bar on, VonageAndroid Architecture Components - Guy Bar on, Vonage
Android Architecture Components - Guy Bar on, Vonage
 
Binding business data to vaadin components
Binding business data to vaadin componentsBinding business data to vaadin components
Binding business data to vaadin components
 
Speaking Eloquent Eloquently
Speaking Eloquent EloquentlySpeaking Eloquent Eloquently
Speaking Eloquent Eloquently
 
Laravel - Speaking eloquent eloquently
Laravel - Speaking eloquent eloquentlyLaravel - Speaking eloquent eloquently
Laravel - Speaking eloquent eloquently
 
Codemotion appengine
Codemotion appengineCodemotion appengine
Codemotion appengine
 
05 content providers - Android
05   content providers - Android05   content providers - Android
05 content providers - Android
 
Petcube epic battle: architecture vs product. UA Mobile 2017.
Petcube epic battle: architecture vs product. UA Mobile 2017.Petcube epic battle: architecture vs product. UA Mobile 2017.
Petcube epic battle: architecture vs product. UA Mobile 2017.
 
Android development for iOS developers
Android development for iOS developersAndroid development for iOS developers
Android development for iOS developers
 

Mais de Codemotion

Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...
Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...
Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...Codemotion
 
Pompili - From hero to_zero: The FatalNoise neverending story
Pompili - From hero to_zero: The FatalNoise neverending storyPompili - From hero to_zero: The FatalNoise neverending story
Pompili - From hero to_zero: The FatalNoise neverending storyCodemotion
 
Pastore - Commodore 65 - La storia
Pastore - Commodore 65 - La storiaPastore - Commodore 65 - La storia
Pastore - Commodore 65 - La storiaCodemotion
 
Pennisi - Essere Richard Altwasser
Pennisi - Essere Richard AltwasserPennisi - Essere Richard Altwasser
Pennisi - Essere Richard AltwasserCodemotion
 
Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...
Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...
Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...Codemotion
 
Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019
Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019
Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019Codemotion
 
Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019
Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019
Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019Codemotion
 
Francesco Baldassarri - Deliver Data at Scale - Codemotion Amsterdam 2019 -
Francesco Baldassarri  - Deliver Data at Scale - Codemotion Amsterdam 2019 - Francesco Baldassarri  - Deliver Data at Scale - Codemotion Amsterdam 2019 -
Francesco Baldassarri - Deliver Data at Scale - Codemotion Amsterdam 2019 - Codemotion
 
Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...
Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...
Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...Codemotion
 
Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...
Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...
Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...Codemotion
 
Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...
Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...
Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...Codemotion
 
Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...
Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...
Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...Codemotion
 
Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019
Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019
Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019Codemotion
 
Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019
Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019
Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019Codemotion
 
Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019
Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019
Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019Codemotion
 
James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...
James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...
James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...Codemotion
 
Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...
Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...
Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...Codemotion
 
Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019
Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019
Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019Codemotion
 
Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019
Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019
Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019Codemotion
 
Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019
Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019
Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019Codemotion
 

Mais de Codemotion (20)

Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...
Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...
Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...
 
Pompili - From hero to_zero: The FatalNoise neverending story
Pompili - From hero to_zero: The FatalNoise neverending storyPompili - From hero to_zero: The FatalNoise neverending story
Pompili - From hero to_zero: The FatalNoise neverending story
 
Pastore - Commodore 65 - La storia
Pastore - Commodore 65 - La storiaPastore - Commodore 65 - La storia
Pastore - Commodore 65 - La storia
 
Pennisi - Essere Richard Altwasser
Pennisi - Essere Richard AltwasserPennisi - Essere Richard Altwasser
Pennisi - Essere Richard Altwasser
 
Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...
Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...
Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...
 
Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019
Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019
Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019
 
Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019
Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019
Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019
 
Francesco Baldassarri - Deliver Data at Scale - Codemotion Amsterdam 2019 -
Francesco Baldassarri  - Deliver Data at Scale - Codemotion Amsterdam 2019 - Francesco Baldassarri  - Deliver Data at Scale - Codemotion Amsterdam 2019 -
Francesco Baldassarri - Deliver Data at Scale - Codemotion Amsterdam 2019 -
 
Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...
Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...
Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...
 
Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...
Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...
Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...
 
Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...
Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...
Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...
 
Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...
Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...
Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...
 
Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019
Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019
Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019
 
Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019
Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019
Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019
 
Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019
Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019
Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019
 
James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...
James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...
James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...
 
Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...
Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...
Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...
 
Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019
Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019
Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019
 
Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019
Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019
Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019
 
Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019
Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019
Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019
 

Último

Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...Orbitshub
 
Exploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with MilvusExploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with MilvusZilliz
 
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 AmsterdamDEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 AmsterdamUiPathCommunity
 
Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024The Digital Insurer
 
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
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FMESafe Software
 
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
 
DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDropbox
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingEdi Saputra
 
[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdf[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdfSandro Moreira
 
MS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsMS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsNanddeep Nachan
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc
 
FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024The Digital Insurer
 
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWEREMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWERMadyBayot
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesrafiqahmad00786416
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfsudhanshuwaghmare1
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MIND CTI
 
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ..."I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...Zilliz
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
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
 

Último (20)

Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
 
Exploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with MilvusExploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with Milvus
 
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 AmsterdamDEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
 
Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024
 
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
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
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...
 
DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor Presentation
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
 
[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdf[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdf
 
MS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsMS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectors
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024
 
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWEREMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challenges
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ..."I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
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
 

Nicola Corti - Building UI Consistent Android Apps - Codemotion Milan 2017

  • 1. Building UI Consistent Android Apps Nicola Corti @cortinico nco@yelp.com
  • 2.
  • 3. Yelp Mission Connecting people with great local businesses.
  • 4. About me Nicola Corti Android @BizCore nco@yelp.com @cortinico Community Addicted !🍕🕹🎤📸✈🏞
  • 6. “Unified use of Design Elements, such as color, typography, spatial layout and behaviors.
  • 8. External Consistency - Across Product
  • 9. External Consistency - Across Platform
  • 10. Benefits • Learnability • Reduce frustrations • Save money/time 💰 Photo by davelawler/CC BY - NC
  • 14.
  • 15. External Examples • Google Material Design • Apple Design Guidelines • Github Primer http://styleguides.io/
  • 17.
  • 20.
  • 21.
  • 23.
  • 24.
  • 28. Does it fit? • Can it be reused? • Is it visible to the user? • Development plan?
  • 29. User photo User name timestamp friends, media checkins Elite badge description
  • 32. Attributes <resources>
 <declare-styleable name="UserPassport">
 <!-- Determines user's name -->
 <attr name="userPassportName" format="string"/>
 </declare-styleable>
 </resources>
  • 33. Attributes <resources>
 <declare-styleable name="UserPassport">
 <!-- Determines user's name -->
 <attr name="userPassportName" format="string"/>
 
 <!-- Determines user's description/role -->
 <attr name="userPassportDescription" format="string"/>
 </declare-styleable>
 </resources>
  • 34. Attributes <resources>
 <declare-styleable name="UserPassport">
 <!-- Determines user's name -->
 <attr name="userPassportName" format="string"/>
 
 <!-- Determines user's description/role -->
 <attr name="userPassportDescription" format="string"/>
 </declare-styleable>
 <attr name="userPassportStyle" format="reference"/>
 </resources>
  • 35. Theme
  • 36. Theme <resources>
 <!—- This theme is the parent of all themes of Yelp's android apps. —->
 <style name="YelpStyleguideTheme"/>
 </resources>
  • 37. Theme <resources>
 <!—- This theme is the parent of all themes of Yelp's android apps. —->
 <style name="YelpStyleguideTheme" parent=“Theme.AppCompat.Light.DarkActionBar"/>
 </resources>
  • 38. Theme <resources>
 <!—- This theme is the parent of all themes of Yelp's android apps. —->
 <style name="YelpStyleguideTheme" parent=“Theme.AppCompat.Light.DarkActionBar">
 <item name="userPassportStyle">@style/UserPassport</item>
 </style>
 </resources>
  • 42. Styles <style name=“UserPassport">
 <item name="userPassportName">Joe Smith</item>
 <item name="userPassportDescription">Owner of Sample Business</item>
 </style>
  • 44. public class UserPassport extends RelativeLayout {

  • 45. public class UserPassport extends RelativeLayout {
 
 private TextView mUserName;
 private TextView mDescription;

  • 46. public class UserPassport extends RelativeLayout {
 
 private TextView mUserName;
 private TextView mDescription;
 
 public void setName(String name) {
 mUserName.setText(name);
 }
 
 

  • 47. public class UserPassport extends RelativeLayout {
 
 private TextView mUserName;
 private TextView mDescription;
 
 public void setName(String name) {
 mUserName.setText(name);
 }
 
 public void setDescription(String description) {
 if (TextUtils.isEmpty(description)) {
 mDescription.setVisibility(GONE);
 } else {
 mDescription.setVisibility(VISIBLE);
 mDescription.setText(description);
 }
 }
 

  • 48. public class UserPassport extends RelativeLayout {
 
 private TextView mUserName;
 private TextView mDescription;

  • 49. public class UserPassport extends RelativeLayout {
 
 private TextView mUserName;
 private TextView mDescription;
 
 public UserPassport(final Context context) {
 super(context);
 init(context, null, 0);
 }
 
 public UserPassport(final Context context, final AttributeSet attrs) {
 super(context, attrs);
 init(context, attrs, R.attr.userPassportStyle);
 }
 
 public UserPassport(final Context context, final AttributeSet attrs, final int defStyleAttr) {
 super(context, attrs, defStyleAttr);
 init(context, attrs, defStyleAttr);
 }
  • 50. public class UserPassport extends RelativeLayout {
 
 private TextView mUserName;
 private TextView mDescription;
 
 public UserPassport(final Context context) {
 super(context);
 init(context, null, 0);
 }
 
 public UserPassport(final Context context, final AttributeSet attrs) {
 super(context, attrs);
 init(context, attrs, R.attr.userPassportStyle);
 }
 
 public UserPassport(final Context context, final AttributeSet attrs, final int defStyleAttr) {
 super(context, attrs, defStyleAttr);
 init(context, attrs, defStyleAttr);
 }
  • 51. public class UserPassport extends RelativeLayout {
 
 private TextView mUserName;
 private TextView mDescription;
 
 private void init(
 final Context context, final AttributeSet attrs, final int defStyleAttr) { 
 }
 

  • 52. public class UserPassport extends RelativeLayout {
 
 private TextView mUserName;
 private TextView mDescription;
 
 private void init(
 final Context context, final AttributeSet attrs, final int defStyleAttr) { 
 LayoutInflater.from(context).inflate(R.layout.user_passport, this, true); 
 }
 

  • 53. public class UserPassport extends RelativeLayout {
 
 private TextView mUserName;
 private TextView mDescription;
 
 private void init(
 final Context context, final AttributeSet attrs, final int defStyleAttr) { 
 LayoutInflater.from(context).inflate(R.layout.user_passport, this, true); 
 mUserName = (TextView) findViewById(R.id.user_name);
 mDescription = (TextView) findViewById(R.id.description);
 
 }
 

  • 54. public class UserPassport extends RelativeLayout {
 
 private TextView mUserName;
 private TextView mDescription;
 
 private void init(
 final Context context, final AttributeSet attrs, final int defStyleAttr) { 
 LayoutInflater.from(context).inflate(R.layout.user_passport, this, true); 
 mUserName = (TextView) findViewById(R.id.user_name);
 mDescription = (TextView) findViewById(R.id.description);
 
 final TypedArray styles = context.obtainStyledAttributes(attrs, R.styleable.UserPassport, defStyleAttr, 0);
 
 }

  • 55. public class UserPassport extends RelativeLayout {
 
 private TextView mUserName;
 private TextView mDescription;
 
 private void init(
 final Context context, final AttributeSet attrs, final int defStyleAttr) { 
 LayoutInflater.from(context).inflate(R.layout.user_passport, this, true); 
 mUserName = (TextView) findViewById(R.id.user_name);
 mDescription = (TextView) findViewById(R.id.description);
 
 final TypedArray styles = context.obtainStyledAttributes(attrs, R.styleable.UserPassport, defStyleAttr, 0);
 
 setName(styles.getString(R.styleable.UserPassport_userPassportName)); setDescription(styles.getString( R.styleable.UserPassport_userPassportDescription));
 
 }
 

  • 56. public class UserPassport extends RelativeLayout {
 
 private TextView mUserName;
 private TextView mDescription;
 
 private void init(
 final Context context, final AttributeSet attrs, final int defStyleAttr) { 
 LayoutInflater.from(context).inflate(R.layout.user_passport, this, true); 
 mUserName = (TextView) findViewById(R.id.user_name);
 mDescription = (TextView) findViewById(R.id.description);
 
 final TypedArray styles = context.obtainStyledAttributes(attrs, R.styleable.UserPassport, defStyleAttr, 0);
 
 setName(styles.getString(R.styleable.UserPassport_userPassportName)); setDescription(styles.getString( R.styleable.UserPassport_userPassportDescription));
 
 styles.recycle();
 }
 

  • 57. <style name="UserPassport">
 <item name="userPassportName">Joe Smith</item>
 <item name="userPassportDescription">@null</item>
 <item name="userPassportTint">@color/orange_dark_interface</item>
 <item name="userPassportNameColor">@color/black_regular_interface</item>
 <item name="userPassportSize">Regular</item>
 <item name="userPassportShowName">true</item>
 <item name="userPassportShowIcons">true</item>
 <item name="userPassportEliteYear">-1</item>
 <item name="userPassportFriends">0</item>
 <item name="userPassportReviews">0</item>
 <item name="userPassportPhotos">0</item>
 <item name="userPassportCheckIns">0</item>
 <item name="userPassportShowCheckIn">false</item>
 </style>
  • 58. <style name="UserPassport.White">
 <item name="userPassportName">Joe Smith</item>
 <item name="userPassportDescription">@null</item>
 <item name="userPassportTint">@color/orange_dark_interface</item>
 <item name="userPassportNameColor">@color/black_regular_interface</item>
 <item name="userPassportSize">Regular</item>
 <item name="userPassportShowName">true</item>
 <item name="userPassportShowIcons">true</item>
 <item name="userPassportEliteYear">-1</item>
 <item name="userPassportFriends">0</item>
 <item name="userPassportReviews">0</item>
 <item name="userPassportPhotos">0</item>
 <item name="userPassportCheckIns">0</item>
 <item name="userPassportShowCheckIn">false</item>
 </style>
  • 59. <style name="UserPassport.White">
 <item name="userPassportName">Joe Smith</item>
 <item name="userPassportDescription">@null</item>
 <item name="userPassportTint">@color/white_interface</item>
 <item name="userPassportNameColor">@color/white_interface</item>
 <item name="userPassportSize">Regular</item>
 <item name="userPassportShowName">true</item>
 <item name="userPassportShowIcons">true</item>
 <item name="userPassportEliteYear">-1</item>
 <item name="userPassportFriends">0</item>
 <item name="userPassportReviews">0</item>
 <item name="userPassportPhotos">0</item>
 <item name="userPassportCheckIns">0</item>
 <item name="userPassportShowCheckIn">false</item>
 </style>
  • 60. <style name="UserPassport.White">
 <item name="userPassportTint">@color/white_interface</item>
 <item name="userPassportNameColor">@color/white_interface</item>
 </style>
  • 63. Assets dependencies {
 
 // Yelp asset libs
 compile 'com.yelp:yelpicons:135.0.0'
 compile ‘com.yelp:yelpdesign:4.0.4’ }
  • 64. Assets dependencies {
 
 // Yelp asset libs
 compile 'com.yelp:yelpicons:135.0.0'
 compile ‘com.yelp:yelpdesign:4.0.4’ }
  • 65. Color
  • 66. Color <color name="black_extra_light_interface">#666666</color>
 <color name="black_regular_interface">#333333</color>
 <color name="blue_dark_interface">#0073bb</color>
 <color name="blue_extra_light_interface">#d0ecfb</color>
 <color name="blue_regular_interface">#0097ec</color>
 <color name="gray_dark_interface">#999999</color>
 <color name="gray_extra_light_interface">#f5f5f5</color>
 <color name="gray_light_interface">#e6e6e6</color>
 <color name="gray_regular_interface">#cccccc</color>
 <color name="green_extra_light_interface">#daecd2</color>
 <color name="green_regular_interface">#41a700</color>
 <color name="mocha_extra_light_interface">#f8e3c7</color>
 <color name="mocha_light_interface">#f1bd79</color>
 <color name="orange_dark_interface">#f15c00</color>
 <color name="orange_extra_light_interface">#ffebcf</color>
 <color name="purple_extra_light_interface">#dad1e4</color>
 <color name="red_dark_interface">#d32323</color>
 <color name="red_extra_light_interface">#fcd6d3</color>
 <color name="slate_extra_light_interface">#cddae2</color>
 <color name="white_interface">#ffffff</color>
 <color name="yellow_dark_interface">#fec011</color>
 <color name="yellow_extra_light_interface">#fff7cc</color>
  • 67. Color <color name="black_extra_light_interface">#666666</color>
 <color name="black_regular_interface">#333333</color>
 <color name="blue_dark_interface">#0073bb</color>
 <color name="blue_extra_light_interface">#d0ecfb</color>
 <color name="blue_regular_interface">#0097ec</color>
 <color name="gray_dark_interface">#999999</color>
 <color name="gray_extra_light_interface">#f5f5f5</color>
 <color name="gray_light_interface">#e6e6e6</color>
 <color name="gray_regular_interface">#cccccc</color>
 <color name="green_extra_light_interface">#daecd2</color>
 <color name="green_regular_interface">#41a700</color>
 <color name="mocha_extra_light_interface">#f8e3c7</color>
 <color name="mocha_light_interface">#f1bd79</color>
 <color name="orange_dark_interface">#f15c00</color>
 <color name="orange_extra_light_interface">#ffebcf</color>
 <color name="purple_extra_light_interface">#dad1e4</color>
 <color name="red_dark_interface">#d32323</color>
 <color name="red_extra_light_interface">#fcd6d3</color>
 <color name="slate_extra_light_interface">#cddae2</color>
 <color name="white_interface">#ffffff</color>
 <color name="yellow_dark_interface">#fec011</color>
 <color name="yellow_extra_light_interface">#fff7cc</color>
  • 68. Color <color name="black_extra_light_interface">#666666</color>
 <color name="black_regular_interface">#333333</color>
 <color name="blue_dark_interface">#0073bb</color>
 <color name="blue_extra_light_interface">#d0ecfb</color>
 <color name="blue_regular_interface">#0097ec</color>
 <color name="gray_dark_interface">#999999</color>
 <color name="gray_extra_light_interface">#f5f5f5</color>
 <color name="gray_light_interface">#e6e6e6</color>
 <color name="gray_regular_interface">#cccccc</color>
 <color name="green_extra_light_interface">#daecd2</color>
 <color name="green_regular_interface">#41a700</color>
 <color name="mocha_extra_light_interface">#f8e3c7</color>
 <color name="mocha_light_interface">#f1bd79</color>
 <color name="orange_dark_interface">#f15c00</color>
 <color name="orange_extra_light_interface">#ffebcf</color>
 <color name="purple_extra_light_interface">#dad1e4</color>
 <color name="red_dark_interface">#d32323</color>
 <color name="red_extra_light_interface">#fcd6d3</color>
 <color name="slate_extra_light_interface">#cddae2</color>
 <color name="white_interface">#ffffff</color>
 <color name="yellow_dark_interface">#fec011</color>
 <color name="yellow_extra_light_interface">#fff7cc</color>
  • 69. Build
  • 71. VCS & CI • git submodule • Run the Build for • submodule • consumer app • business app
  • 73. Custom Lint Checks 
 Button b = new Button(context);
 
 SwitchCompat switchCompat = new SwitchCompat(context);
 
 Snackbar.make(getRootView(), “Test”, LENGTH_SHORT).show();
  • 74. Custom Lint Checks @SuppressLint("")
 Button b = new Button(context);
 
 @SuppressLint("")
 SwitchCompat switchCompat = new SwitchCompat(context);
 
 @SuppressLint("")
 Snackbar.make(getRootView(), “Test”, LENGTH_SHORT).show();
  • 75. Custom Lint Checks @SuppressLint("NonStyleguideButtonInstance")
 Button b = new Button(context);
 
 @SuppressLint("")
 SwitchCompat switchCompat = new SwitchCompat(context);
 
 @SuppressLint("")
 Snackbar.make(getRootView(), “Test”, LENGTH_SHORT).show();
  • 76. Custom Lint Checks @SuppressLint("NonStyleguideButtonInstance")
 Button b = new Button(context);
 
 @SuppressLint("NonStyleguideToggleInstance")
 SwitchCompat switchCompat = new SwitchCompat(context);
 
 @SuppressLint("")
 Snackbar.make(getRootView(), “Test”, LENGTH_SHORT).show();
  • 77. Custom Lint Checks @SuppressLint("NonStyleguideButtonInstance")
 Button b = new Button(context);
 
 @SuppressLint("NonStyleguideToggleInstance")
 SwitchCompat switchCompat = new SwitchCompat(context);
 
 @SuppressLint("NonStyleguideSnackbarInstance")
 Snackbar.make(getRootView(), “Test”, LENGTH_SHORT).show();
  • 78. Custom Lint Checks // Using stock Button because […] + Ticket number. @SuppressLint("NonStyleguideButtonInstance")
 Button b = new Button(context);
 
 @SuppressLint("NonStyleguideToggleInstance")
 SwitchCompat switchCompat = new SwitchCompat(context);
 
 @SuppressLint("NonStyleguideSnackbarInstance")
 Snackbar.make(getRootView(), “Test”, LENGTH_SHORT).show();
  • 80. Custom Lint Checks <Button
 android:layout_width="match_parent"
 android:layout_height="match_parent" />
 
 <Switch
 android:layout_width="match_parent"
 android:layout_height="match_parent" />
  • 81. Custom Lint Checks <Button
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 tools:ignore="NonStyleguideButtonTag" />
 
 <Switch
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 tools:ignore="NonStyleguideToggleTag" />
  • 84. build.gradle android {
 lintOptions {
 abortOnError true
 warningsAsErrors true
 
 }
 }
  • 85. build.gradle android {
 lintOptions {
 abortOnError true
 warningsAsErrors true
 
 lintConfig file("lint.xml")
 }
 }
  • 86. build.gradle android {
 lintOptions {
 abortOnError true
 warningsAsErrors true
 
 lintConfig file("lint.xml")
 baseline file("lint-baseline.xml")
 }
 }
  • 87. Test your component • Your component ❤ Espresso? • Do you handle state changes? • contentDescription ?
  • 88. Share
  • 89. Documentation • Provide Javadoc • Add Screenshots • Document Attributes • Document Styles
  • 90. Screenshots capture • v0.1: Manual Screenshots • v0.2: Automated locally • v0.3: Automated with CI 💫
  • 91.
  • 92.
  • 93.
  • 94. StyleguideTestApp • Components Showcase • For Designer 🎨 • For Developer 🔧
  • 95. Taking Screenshots with Espresso public class ScreenshotViewActions {
 
 }
  • 96. Taking Screenshots with Espresso public class ScreenshotViewActions {
 
 public static ViewAction screenshot(final String folderName, final String fileName) {
 return new ViewAction() {
 
 };
 }
 }
  • 97. Taking Screenshots with Espresso public class ScreenshotViewActions {
 
 public static ViewAction screenshot(final String folderName, final String fileName) {
 return new ViewAction() {
 // Other methods omitted.
 
 @Override
 public void perform(UiController uiController, View view) {
 ScreenshotsUtil.takeScreenshot(folderName, fileName, view);
 }
 };
 }
 }
  • 99. Sample Espresso Test public class StarsViewActivityTests {
 
 }
  • 100. Sample Espresso Test public class StarsViewActivityTests {
 
 @Test
 public void takeScreenshot() throws InterruptedException {
 onView(withId(R.id.stars_view_4)).perform(setStarsNumber(4));
 
 }
 }
  • 101. Sample Espresso Test public class StarsViewActivityTests {
 
 @Test
 public void takeScreenshot() throws InterruptedException {
 onView(withId(R.id.stars_view_4)).perform(setStarsNumber(4));
 onView(withId(R.id.stars_view_5)).perform(setStarsNumber(5),
 screenshot(FOLDER_NAME, "stars_with_text"));
 
 }
 }
  • 102. Sample Espresso Test public class StarsViewActivityTests {
 
 @Test
 public void takeScreenshot() throws InterruptedException {
 onView(withId(R.id.stars_view_4)).perform(setStarsNumber(4));
 onView(withId(R.id.stars_view_5)).perform(setStarsNumber(5),
 screenshot(FOLDER_NAME, "stars_with_text"));
 
 ScreenshotUtil.fullScreenshot(FOLDER_NAME, "stars_fullscreen");
 }
 }
  • 103. Bend it, don’t break it! Source: GIPHY