Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Efficient Sad Puppy Layouts

Daniel Lew
September 30, 2016

Efficient Sad Puppy Layouts

Talk given about Android layouts at Droidcon NYC 2016.

(Real name of talk was "Efficient Android Layouts", but the iOS Droidcon app called it "Efficient Sad Puppy Layouts" so I matched.)

Daniel Lew

September 30, 2016
Tweet

More Decks by Daniel Lew

Other Decks in Research

Transcript

  1. Efficient Sad Puppy Layouts
    Dan Lew
    Image: https://commons.wikimedia.org/wiki/File:Sad-pug.jpg

    View Slide

  2. View Slide

  3. $$$

    View Slide

  4. ViewGroups

    View Slide

  5. RelativeLayout
    ConstraintLayout
    LinearLayout
    FrameLayout
    Complex
    Simple

    View Slide

  6. RelativeLayout / ConstraintLayout
    • Position views relative to each other
    • RelativeLayout: Slow
    • ConstraintLayout: Alpha

    View Slide

  7. LinearLayout
    • Stack views vertically/horizontally
    • Weight distribution

    View Slide

  8. FrameLayout
    • Positioning based on parent bounds
    • Overlapping Views
    • Clickable item backgrounds
    • Toggle container

    View Slide

  9. View Slide

  10. View Slide

  11. xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="match_parent"

    android:layout_height="wrap_content"

    android:orientation="horizontal"

    >


    layout="@layout/avatar_view"

    android:layout_width="48dp"

    android:layout_height="48dp"

    />




    View Slide

  12. xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="match_parent"

    android:layout_height="wrap_content"

    android:orientation="horizontal"

    >


    layout="@layout/avatar_view"

    android:layout_width="48dp"

    android:layout_height="48dp"

    />




    View Slide

  13. xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="match_parent"

    android:layout_height="wrap_content"

    android:orientation="horizontal"

    >


    android:id="@+id/avatar_view"

    android:layout_width="48dp"

    android:layout_height="48dp"

    />




    View Slide

  14. public class AvatarView extends FrameLayout {


    ImageView icon;

    TextView initials;


    public AvatarView(Context context, AttributeSet attrs) {

    super(context, attrs);


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


    icon = (ImageView) findViewById(R.id.icon);

    initials = (TextView) findViewById(R.id.initials);

    }


    public void bind(Member member) {

    // ...Load icon into ImageView...

    // OR

    // ...Setup initials in TextView...

    }

    }

    View Slide

  15. android:layout_width="match_parent"

    android:layout_height="match_parent"

    >


    android:id="@+id/initials"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    />


    android:id="@+id/icon"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    />



    View Slide

  16. AvatarView
    (FrameLayout)
    FrameLayout
    ImageView
    TextView

    View Slide

  17. public class AvatarView extends FrameLayout {


    ImageView icon;

    TextView initials;


    public AvatarView(Context context, AttributeSet attrs) {

    super(context, attrs);


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


    icon = (TextView) findViewById(R.id.icon);

    initials = (TextView) findViewById(R.id.initials);

    }


    public void bind(Member member) {

    // ...Load icon into ImageView...

    // OR

    // ...Setup initials in TextView...

    }

    }

    View Slide

  18. >


    android:id="@+id/initials"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    />


    android:id="@+id/icon"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    />



    View Slide

  19. AvatarView
    (Framelayout)
    ImageView
    TextView

    View Slide

  20. Styles

    View Slide

  21. Styles
    • No style

    • Style



    
<br/><item name="android:background">#FF0000</item>
<br/>

    View Slide

  22. Efficient
    • Semantically identical Views
    • All styled Views should change at
    once

    View Slide

  23. Not Efficient
    • Single-use styles
    • Coincidentally using the same attributes
    android:id="@+id/title"

    android:textColor="@color/blue_200"

    android:textColorHint=“@color/grey_500" />


    android:id="@+id/body"

    android:textColor="@color/blue_200"

    android:textColorHint=“@color/grey_500" />

    View Slide

  24. Not Efficient
    • Single-use styles
    • Coincidentally using the same attributes
    android:id="@+id/title"

    android:textColor="@color/blue_200"

    android:textColorHint=“@color/grey_500" />


    android:id="@+id/body"

    android:textColor="@color/blue_200"

    android:textColorHint=“@color/grey_500" />

    View Slide

  25. Not Efficient
    • Single-use styles
    • Coincidentally using the same attributes
    android:id="@+id/title"

    android:textColor="@color/blue_200"

    android:textColorHint=“@color/grey_500" />


    android:id="@+id/body"

    android:textColor="@color/blue_200"

    android:textColorHint=“@color/grey_500" />

    View Slide

  26. static final int NUM_COLUMNS = 3;


    static final int NUM_RETRIES = 3;
    static final int NUM_THREE = 3;

    View Slide

  27. // static final int NUM_COLUMNS = 3;


    // static final int NUM_RETRIES = 3;

    static final int NUM_THREE = 3;

    View Slide

  28. Themes

    View Slide

  29. Themes
    • Affect multiple Views at once
    • Default styles
    • Configure system-created Views

    View Slide

  30. • Application
    android:theme="@style/Theme.AppCompat">
    • Activity
    android:theme=“@style/Theme.AppCompat.Light”>
    • View
    android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"

    app:popupTheme="@style/ThemeOverlay.AppCompat.Light"

    />

    View Slide

  31. AppCompat
    • Material on all devices
    • Baseline themes/styles
    • Enables View theming pre-Lollipop

    View Slide

  32. 
<br/><item name="colorPrimary">#F00</item>
<br/><item name="colorPrimaryDark">#0F0</item>
<br/><item name="colorControlNormal">#00F</item>
<br/>

    View Slide

  33. 
<br/><item name="buttonStyle">@style/MyButton</item>
<br/><item name="android:spinnerItemStyle">@style/MySpinnerItem</item>
<br/>
<br/><item name="android:textAppearance">@style/MyText</item>
<br/><item name="android:textAppearanceInverse">@style/MyTextInverse</item>
<br/>

    View Slide

  34. 
<br/><item name="selectableItemBackground">@drawable/bg</item>
<br/>


    View Slide

  35. Resources
    Image: https://www.flickr.com/photos/mcerasoli/6261957970

    View Slide

  36. v24
    port
    xxxhdpi
    w411dp
    h731dp
    en_US

    View Slide

  37. View Slide

  38. View Slide

  39. View Slide

  40. View Slide

  41. Resource Qualifier System
    • Define alternative resources for device configurations
    • Android automatically picks correct resource

    View Slide

  42. View Slide

  43. values-sw600dp-port
    values-port
    values-sw600dp
    values
    not sw600dp or portrait
    not sw600dp
    not portrait

    View Slide

  44. Resources as code
    • Resource == parameter
    • Parameter <-- device configuration

    View Slide

  45. int square() {

    return 8 * 8;

    }

    int squareLarge() {

    return 16 * 16;

    }
    int square(int num) {

    return num * num;

    }
    VS

    View Slide

  46. getResources().getBoolean(R.bool.is_portrait)
    false
    true

    View Slide

  47. setContentView(R.layout.activity_main)

    View Slide

  48. xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    >









    View Slide

  49. xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    >









    View Slide

  50. android:layout_width="wrap_content"

    android:layout_height="match_parent"

    android:textSize="24sp"

    android:textColor="#FF00FF"

    />
    android:layout_width="wrap_content"

    android:layout_height="match_parent"

    android:textSize="16sp"

    android:textColor="#FF00FF"

    />

    View Slide

  51. android:layout_width="wrap_content"

    android:layout_height="match_parent"

    android:textSize="@dimen/welcome_text_size"

    android:textColor="#FF00FF"

    />
    24sp
    16sp

    View Slide

  52. 
<br/><item name="android:textSize">24sp</item><br/><item name="android:textColor">#FF00FF</item>
<br/>
    
<br/><item name="android:textSize">16sp</item><br/><item name="android:textColor">#FF00FF</item>
<br/>

    View Slide

  53. 
<br/><item name="android:textSize">@dimen/welcome_text_size</item>
<br/><item name="android:textColor">#FF00FF</item>
<br/>
    24sp
    16sp

    View Slide

  54. activity_main.xml
    TextView
    [email protected]/WelcomeText
    some_include.xml some_include.xml
    portrait
    default
    textSize=16sp textSize=24sp
    sw600dp
    default

    View Slide

  55. Drawables
    Image: https://www.flickr.com/photos/suckamc/3047183157

    View Slide

  56. Image: https://www.flickr.com/photos/ufv/8042499199
    Design
    “I need this”

    View Slide

  57. Design
    “Not enough”
    “I tweaked the color,

    here’s those assets again.”

    View Slide

  58. Assets as code

    View Slide

  59. Drawable XML
    • Built into Android
    • Simple shapes
    • State selectors
    • Layer lists

    View Slide

  60. View Slide

  61. Button Outline

    android:shape="rectangle"

    >




    android:width="1dp"

    android:color="@color/white"

    />





    View Slide

  62. Button Outline

    android:shape="rectangle"

    >




    android:width="1dp"

    android:color="@color/white"

    />





    View Slide

  63. Button Outline

    android:shape="rectangle"

    >




    android:width="1dp"

    android:color="@color/white"

    />





    View Slide

  64. Button Outline

    android:shape="rectangle"

    >




    android:width="1dp"

    android:color="@color/white"

    />





    View Slide

  65. Button Outline

    android:shape="rectangle"

    >




    android:width="1dp"

    android:color="@color/white"

    />





    View Slide

  66. Button Selector




















    View Slide

  67. Button Selector




















    View Slide

  68. Button Selector




















    View Slide

  69. Button Selector




















    View Slide

  70. Button Selector




















    View Slide

  71. Button Selector




















    View Slide


  72. android:color="@color/blue_200"

    >












    Button Selector (v21)

    View Slide


  73. android:color="@color/blue_200"

    >












    Button Selector (v21)

    View Slide


  74. android:color="@color/blue_200"

    >












    Button Selector (v21)

    View Slide


  75. android:color="@color/blue_200"

    >












    Button Selector (v21)

    View Slide

  76. Button Versions
    button_welcome_outline.xml
    button_welcome.xml button_welcome.xml (with ripple)

    View Slide

  77. Vector drawables

    View Slide

  78. VectorDrawable
    !=
    SVG
    Design
    :(

    View Slide

  79. SVG -> VectorDrawable
    • Android Studio: New Vector Asset
    • Victor: github.com/trello/victor
    android {

    sourceSets {

    main {

    svg.srcDir 'src/main/svg'

    }

    }

    }

    View Slide

  80. vs

    View Slide

  81. View Slide

  82. Tinting Images
    • XML
    • Simple
    drawable.setColorFilter(color, PorterDuff.Mode.SRC_IN);
    • Comprehensive
    Drawable wrappedDrawable = DrawableCompat.wrap(drawable);

    DrawableCompat.setTint(wrappedDrawable, color);
    Not backwards compatible

    View Slide

  83. Thank You!
    • @danlew42
    • danlew.net
    • speakerdeck.com/dlew
    • github.com/dlew

    View Slide