efficient android layouts - goto conference · but i

94
Efficient Android Layouts Dan Lew

Upload: others

Post on 13-Jul-2020

10 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Efficient Android Layouts - GOTO Conference · But I

Efficient Android LayoutsDan Lew

Page 2: Efficient Android Layouts - GOTO Conference · But I
Page 3: Efficient Android Layouts - GOTO Conference · But I

“Give me the place to stand, and I shall move the earth.”~Archimedes

Page 4: Efficient Android Layouts - GOTO Conference · But I

“Give me a standing desk, and I shall write an Android app.”~Me

Page 5: Efficient Android Layouts - GOTO Conference · But I

ViewGroups

Page 6: Efficient Android Layouts - GOTO Conference · But I

RelativeLayoutConstraintLayout

LinearLayout

FrameLayout

Complex

Simple

Page 7: Efficient Android Layouts - GOTO Conference · But I

RelativeLayout / ConstraintLayout

• Position views relative to each other

• RelativeLayout: Slow

• ConstraintLayout: Alpha

Page 8: Efficient Android Layouts - GOTO Conference · But I

LinearLayout

• Stack views vertically/horizontally

• Weight distribution

Page 9: Efficient Android Layouts - GOTO Conference · But I

But I <3 RelativeLayout

• LinearLayout == sometimes slow

• RelativeLayout == always slow

• ConstraintLayout == savior

• Profile!

Page 10: Efficient Android Layouts - GOTO Conference · But I

FrameLayout

• Positioning based on parent bounds

• Overlapping Views

• Clickable item backgrounds

• Toggle container

Page 11: Efficient Android Layouts - GOTO Conference · But I
Page 12: Efficient Android Layouts - GOTO Conference · But I
Page 13: Efficient Android Layouts - GOTO Conference · But I

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" > <include layout="@layout/avatar_view" android:layout_width="48dp" android:layout_height="48dp" /> <!-- Rest of layout here... --></LinearLayout>

Page 14: Efficient Android Layouts - GOTO Conference · But I

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" > <include layout="@layout/avatar_view" android:layout_width="48dp" android:layout_height="48dp" /> <!-- Rest of layout here... --></LinearLayout>

Page 15: Efficient Android Layouts - GOTO Conference · But I

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" > <com.trello.view.AvatarView android:id="@+id/avatar_view" android:layout_width="48dp" android:layout_height="48dp" /> <!-- Rest of layout here... --></LinearLayout>

Page 16: Efficient Android Layouts - GOTO Conference · But I

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... } }

Page 17: Efficient Android Layouts - GOTO Conference · But I

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <TextView android:id="@+id/initials" android:layout_width="match_parent" android:layout_height="match_parent" /> <ImageView android:id="@+id/icon" android:layout_width="match_parent" android:layout_height="match_parent" /></FrameLayout>

Page 18: Efficient Android Layouts - GOTO Conference · But I

AvatarView (FrameLayout)

FrameLayout

ImageViewTextView

Page 19: Efficient Android Layouts - GOTO Conference · But I

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... } }

Page 20: Efficient Android Layouts - GOTO Conference · But I

<merge xmlns:android="http://schemas.android.com/apk/res/android" > <TextView android:id="@+id/initials" android:layout_width="match_parent" android:layout_height="match_parent" /> <ImageView android:id="@+id/icon" android:layout_width="match_parent" android:layout_height="match_parent" /></merge>

Page 21: Efficient Android Layouts - GOTO Conference · But I

AvatarView (Framelayout)

ImageViewTextView

Page 22: Efficient Android Layouts - GOTO Conference · But I

Custom Drawing

Page 23: Efficient Android Layouts - GOTO Conference · But I

Step #1: onMeasure()(…sometimes you can skip this…)

Page 24: Efficient Android Layouts - GOTO Conference · But I

onMeasure()

• onMeasure() signature

void onMeasure(int widthMeasureSpec, int heightMeasureSpec)

• measureSpec - packed integer

int widthMode = MeasureSpec.getMode(widthMeasureSpec);int widthSize = MeasureSpec.getSize(widthMeasureSpec);int heightMode = MeasureSpec.getMode(heightMeasureSpec);int heightSize = MeasureSpec.getSize(heightMeasureSpec);

Page 25: Efficient Android Layouts - GOTO Conference · But I

MeasureSpec

• EXACTLY - Must be that size

• AT_MOST - Maximum width

• UNDEFINED - Ideal width

Page 26: Efficient Android Layouts - GOTO Conference · But I

onMeasure()protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int widthMode = MeasureSpec.getMode(widthMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec);

int width; if (widthMode == MeasureSpec.EXACTLY) { width = widthSize; } else { int desiredWidth = 500; // Whatever calculation you want

if (widthMode == MeasureSpec.AT_MOST) { width = Math.min(desiredWidth, widthSize); } else { width = desiredWidth; } }

// ...to be continued...}

Page 27: Efficient Android Layouts - GOTO Conference · But I

onMeasure()

@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int width; int height;

// ...Calculate width and height...

setMeasuredDimension(width, height);}

Page 28: Efficient Android Layouts - GOTO Conference · But I

Step #2: onDraw()(this is up to you)

Page 29: Efficient Android Layouts - GOTO Conference · But I

Custom Drawables

• onMeasure() -> getIntrinsicHeight() / getIntrinsicWidth()

• onDraw() -> draw()

• https://speakerdeck.com/cyrilmottier/mastering-android-drawables

Page 30: Efficient Android Layouts - GOTO Conference · But I

Styles

Page 31: Efficient Android Layouts - GOTO Conference · But I

Styles• No style

<View android:background=“#FF0000” />

• Style

<!--- some_layout.xml --> <View style="@style/MyStyle" />

<!--- styles.xml --><style name="MyStyle"> <item name="android:background">#FF0000</item> </style>

Page 32: Efficient Android Layouts - GOTO Conference · But I

Efficient

• Semantically identical Views

• All styled Views should change at once

Page 33: Efficient Android Layouts - GOTO Conference · But I

Not Efficient• Single-use styles

• Coincidentally using the same attributes

<TextView android:id="@+id/title" android:textColor="@color/blue_200" android:textColorHint=“@color/grey_500" /> <TextView android:id="@+id/body" android:textColor="@color/blue_200" android:textColorHint=“@color/grey_500" />

Page 34: Efficient Android Layouts - GOTO Conference · But I

Not Efficient• Single-use styles

• Coincidentally using the same attributes

<TextView android:id="@+id/title" android:textColor="@color/blue_200" android:textColorHint=“@color/grey_500" /> <TextView android:id="@+id/body" android:textColor="@color/blue_200" android:textColorHint=“@color/grey_500" />

Page 35: Efficient Android Layouts - GOTO Conference · But I

Not Efficient• Single-use styles

• Coincidentally using the same attributes

<TextView android:id="@+id/title" android:textColor="@color/blue_200" android:textColorHint=“@color/grey_500" /> <TextView android:id="@+id/body" android:textColor="@color/blue_200" android:textColorHint=“@color/grey_500" />

Page 36: Efficient Android Layouts - GOTO Conference · But I

static final int NUM_COLUMNS = 3;

static final int NUM_RETRIES = 3;

static final int NUM_THREE = 3;

Page 37: Efficient Android Layouts - GOTO Conference · But I

// static final int NUM_COLUMNS = 3;

// static final int NUM_RETRIES = 3;

static final int NUM_THREE = 3;

Page 38: Efficient Android Layouts - GOTO Conference · But I

Themes

Page 39: Efficient Android Layouts - GOTO Conference · But I

Themes

• Affect multiple Views at once

• Default styles

• Configure system-created Views

Page 40: Efficient Android Layouts - GOTO Conference · But I

• Application

<application android:theme="@style/Theme.AppCompat">

• Activity

<activity android:theme=“@style/Theme.AppCompat.Light”>

• View

<Toolbar android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />

Page 41: Efficient Android Layouts - GOTO Conference · But I

AppCompat

• Material on all devices

• Baseline themes/styles

• Enables View theming pre-Lollipop

Page 42: Efficient Android Layouts - GOTO Conference · But I

<style name="ColorTheme" parent="Theme.AppCompat"> <item name="colorPrimary">#F00</item> <item name="colorPrimaryDark">#0F0</item> <item name="colorControlNormal">#00F</item> </style>

Page 43: Efficient Android Layouts - GOTO Conference · But I

<style name="AppTheme" parent="Theme.AppCompat"> <item name="buttonStyle">@style/MyButton</item> <item name="android:spinnerItemStyle">@style/MySpinnerItem</item> <item name="android:textAppearance">@style/MyText</item> <item name="android:textAppearanceInverse">@style/MyTextInverse</item> </style>

Page 44: Efficient Android Layouts - GOTO Conference · But I

<style name="AttrTheme" parent="Theme.AppCompat"> <item name="selectableItemBackground">@drawable/bg</item> </style>

<!-- some_layout.xml --><Button android:background="?attr/selectableItemBackground" />

Page 45: Efficient Android Layouts - GOTO Conference · But I

Resources

Page 46: Efficient Android Layouts - GOTO Conference · But I

v24

port

xxxhdpi

w411dp

h731dpen_US

Page 47: Efficient Android Layouts - GOTO Conference · But I
Page 48: Efficient Android Layouts - GOTO Conference · But I
Page 49: Efficient Android Layouts - GOTO Conference · But I
Page 50: Efficient Android Layouts - GOTO Conference · But I
Page 51: Efficient Android Layouts - GOTO Conference · But I

Resource Qualifier System

• Define alternative resources for device configurations

• Android automatically picks correct resource

Page 52: Efficient Android Layouts - GOTO Conference · But I
Page 53: Efficient Android Layouts - GOTO Conference · But I

values-sw600dp-port

values-port

values-sw600dp

values

not sw600dp or portrait

not sw600dp

not portrait

Page 54: Efficient Android Layouts - GOTO Conference · But I

Resources as code

• Resource == parameter

• Parameter <-- device configuration

Page 55: Efficient Android Layouts - GOTO Conference · But I

int square() { return 8 * 8;}

int squareLarge() { return 16 * 16; }

int square(int num) { return num * num;}

VS

Page 56: Efficient Android Layouts - GOTO Conference · But I

getResources().getBoolean(R.bool.is_portrait)

<bool name="is_portrait">false</bool>

<bool name="is_portrait">true</bool>

Page 57: Efficient Android Layouts - GOTO Conference · But I

setContentView(R.layout.activity_main)

Page 58: Efficient Android Layouts - GOTO Conference · But I

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <!-- ... --> <include layout="@layout/some_include" /> <!-- ... --></LinearLayout>

Page 59: Efficient Android Layouts - GOTO Conference · But I

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <!-- ... --> <include layout="@layout/some_include" /> <!-- ... --></LinearLayout>

Page 60: Efficient Android Layouts - GOTO Conference · But I

<TextView android:layout_width="wrap_content" android:layout_height="match_parent" android:textSize="24sp" android:textColor="#FF00FF" />

<TextView android:layout_width="wrap_content" android:layout_height="match_parent" android:textSize="16sp" android:textColor="#FF00FF" />

Page 61: Efficient Android Layouts - GOTO Conference · But I

<TextView android:layout_width="wrap_content" android:layout_height="match_parent" android:textSize="@dimen/welcome_text_size" android:textColor="#FF00FF" />

<dimen name="welcome_text_size">24sp</dimen>

<dimen name="welcome_text_size">16sp</dimen>

Page 62: Efficient Android Layouts - GOTO Conference · But I

<style name="WelcomeText" parent="TextAppearance.AppCompat"> <item name="android:textSize">24sp</item> <item name="android:textColor">#FF00FF</item> </style>

<style name="WelcomeText" parent="TextAppearance.AppCompat"> <item name="android:textSize">16sp</item> <item name="android:textColor">#FF00FF</item> </style>

Page 63: Efficient Android Layouts - GOTO Conference · But I

<style name="WelcomeText" parent="TextAppearance.AppCompat"> <item name="android:textSize">@dimen/welcome_text_size</item> <item name="android:textColor">#FF00FF</item> </style>

<dimen name="welcome_text_size">24sp</dimen>

<dimen name="welcome_text_size">16sp</dimen>

Page 64: Efficient Android Layouts - GOTO Conference · But I

activity_main.xml

TextView style=@style/WelcomeText

some_include.xml some_include.xml

portraitdefault

textSize=16sp textSize=24sp

sw600dpdefault

Page 65: Efficient Android Layouts - GOTO Conference · But I

Drawables

Page 66: Efficient Android Layouts - GOTO Conference · But I

Image: https://www.flickr.com/photos/ufv/8042499199

Design

“I need this”

Page 67: Efficient Android Layouts - GOTO Conference · But I

Design

“Not enough”

“I tweaked the color, here’s those assets again.”

Page 68: Efficient Android Layouts - GOTO Conference · But I

Assets as code

Page 69: Efficient Android Layouts - GOTO Conference · But I

Drawable XML

• Built into Android

• Simple shapes

• State selectors

• Layer lists

Page 70: Efficient Android Layouts - GOTO Conference · But I
Page 71: Efficient Android Layouts - GOTO Conference · But I

Button Outline

<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" > <solid android:color="@color/transparent" /> <stroke android:width="1dp" android:color="@color/white" /> <corners android:radius="@dimen/corner_radius_tiny" /> </shape>

Page 72: Efficient Android Layouts - GOTO Conference · But I

Button Outline

<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" > <solid android:color="@color/transparent" /> <stroke android:width="1dp" android:color="@color/white" /> <corners android:radius="@dimen/corner_radius_tiny" /> </shape>

Page 73: Efficient Android Layouts - GOTO Conference · But I

Button Outline

<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" > <solid android:color="@color/transparent" /> <stroke android:width="1dp" android:color="@color/white" /> <corners android:radius="@dimen/corner_radius_tiny" /> </shape>

Page 74: Efficient Android Layouts - GOTO Conference · But I

Button Outline

<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" > <solid android:color="@color/transparent" /> <stroke android:width="1dp" android:color="@color/white" /> <corners android:radius="@dimen/corner_radius_tiny" /> </shape>

Page 75: Efficient Android Layouts - GOTO Conference · But I

Button Outline

<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" > <solid android:color="@color/transparent" /> <stroke android:width="1dp" android:color="@color/white" /> <corners android:radius="@dimen/corner_radius_tiny" /> </shape>

Page 76: Efficient Android Layouts - GOTO Conference · But I

Button Selector<?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <item> <selector> <item android:state_pressed="true"> <shape android:shape="rectangle"> <solid android:color="@color/blue_200" /> <corners android:radius="@dimen/corner_radius_tiny" /> </shape> </item> <item android:drawable="@color/transparent" /> </selector> </item> <item android:drawable="@drawable/btn_welcome_outline" /></layer-list>

Page 77: Efficient Android Layouts - GOTO Conference · But I

Button Selector<?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <item> <selector> <item android:state_pressed="true"> <shape android:shape="rectangle"> <solid android:color="@color/blue_200" /> <corners android:radius="@dimen/corner_radius_tiny" /> </shape> </item> <item android:drawable="@color/transparent" /> </selector> </item> <item android:drawable="@drawable/btn_welcome_outline" /></layer-list>

Page 78: Efficient Android Layouts - GOTO Conference · But I

Button Selector<?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <item> <selector> <item android:state_pressed="true"> <shape android:shape="rectangle"> <solid android:color="@color/blue_200" /> <corners android:radius="@dimen/corner_radius_tiny" /> </shape> </item> <item android:drawable="@color/transparent" /> </selector> </item> <item android:drawable="@drawable/btn_welcome_outline" /></layer-list>

Page 79: Efficient Android Layouts - GOTO Conference · But I

Button Selector<?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <item> <selector> <item android:state_pressed="true"> <shape android:shape="rectangle"> <solid android:color="@color/blue_200" /> <corners android:radius="@dimen/corner_radius_tiny" /> </shape> </item> <item android:drawable="@color/transparent" /> </selector> </item> <item android:drawable="@drawable/btn_welcome_outline" /></layer-list>

Page 80: Efficient Android Layouts - GOTO Conference · But I

Button Selector<?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <item> <selector> <item android:state_pressed="true"> <shape android:shape="rectangle"> <solid android:color="@color/blue_200" /> <corners android:radius="@dimen/corner_radius_tiny" /> </shape> </item> <item android:drawable="@color/transparent" /> </selector> </item> <item android:drawable="@drawable/btn_welcome_outline" /></layer-list>

Page 81: Efficient Android Layouts - GOTO Conference · But I

Button Selector<?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <item> <selector> <item android:state_pressed="true"> <shape android:shape="rectangle"> <solid android:color="@color/blue_200" /> <corners android:radius="@dimen/corner_radius_tiny" /> </shape> </item> <item android:drawable="@color/transparent" /> </selector> </item> <item android:drawable="@drawable/btn_welcome_outline" /></layer-list>

Page 82: Efficient Android Layouts - GOTO Conference · But I

<?xml version="1.0" encoding="utf-8"?> <ripple xmlns:android="http://schemas.android.com/apk/res/android" android:color="@color/blue_200" > <item android:drawable="@drawable/btn_welcome_outline" /> <item android:id="@android:id/mask"> <shape android:shape="rectangle"> <solid android:color="@color/white" /> <corners android:radius="@dimen/corner_radius_tiny" /> </shape> </item> </ripple>

Button Selector (v21)

Page 83: Efficient Android Layouts - GOTO Conference · But I

<?xml version="1.0" encoding="utf-8"?> <ripple xmlns:android="http://schemas.android.com/apk/res/android" android:color="@color/blue_200" > <item android:drawable="@drawable/btn_welcome_outline" /> <item android:id="@android:id/mask"> <shape android:shape="rectangle"> <solid android:color="@color/white" /> <corners android:radius="@dimen/corner_radius_tiny" /> </shape> </item> </ripple>

Button Selector (v21)

Page 84: Efficient Android Layouts - GOTO Conference · But I

<?xml version="1.0" encoding="utf-8"?> <ripple xmlns:android="http://schemas.android.com/apk/res/android" android:color="@color/blue_200" > <item android:drawable="@drawable/btn_welcome_outline" /> <item android:id="@android:id/mask"> <shape android:shape="rectangle"> <solid android:color="@color/white" /> <corners android:radius="@dimen/corner_radius_tiny" /> </shape> </item> </ripple>

Button Selector (v21)

Page 85: Efficient Android Layouts - GOTO Conference · But I

<?xml version="1.0" encoding="utf-8"?> <ripple xmlns:android="http://schemas.android.com/apk/res/android" android:color="@color/blue_200" > <item android:drawable="@drawable/btn_welcome_outline" /> <item android:id="@android:id/mask"> <shape android:shape="rectangle"> <solid android:color="@color/white" /> <corners android:radius="@dimen/corner_radius_tiny" /> </shape> </item> </ripple>

Button Selector (v21)

Page 86: Efficient Android Layouts - GOTO Conference · But I

Button Versions

button_welcome_outline.xml

button_welcome.xml button_welcome.xml (with ripple)

Page 87: Efficient Android Layouts - GOTO Conference · But I

Vector drawables

Page 88: Efficient Android Layouts - GOTO Conference · But I

VectorDrawable !=

SVG

Design

:(

Page 89: Efficient Android Layouts - GOTO Conference · But I

SVG -> VectorDrawable

• Android Studio: New Vector Asset

• Victor: github.com/trello/victor

android { sourceSets { main { svg.srcDir 'src/main/svg' } }}

Page 90: Efficient Android Layouts - GOTO Conference · But I

vs

Page 91: Efficient Android Layouts - GOTO Conference · But I
Page 92: Efficient Android Layouts - GOTO Conference · But I

Tinting Images

• XML

• Simple drawable.setColorFilter(color, PorterDuff.Mode.SRC_IN);

• Comprehensive Drawable wrappedDrawable = DrawableCompat.wrap(drawable);DrawableCompat.setTint(wrappedDrawable, color);

Not backwards compatible

Page 93: Efficient Android Layouts - GOTO Conference · But I
Page 94: Efficient Android Layouts - GOTO Conference · But I

Thank You!

• @danlew42

• danlew.net

• speakerdeck.com/dlew