Slide 1

Slide 1 text

Atomic Design in Android Yahya Bayramoglu Android Developer - XING @yahyabayramoglu

Slide 2

Slide 2 text

Atomic Design - Brad Frost “The thought is that; all matter (whether solid, liquid, gas, simple, complex, etc) is comprised of atoms. Those atomic units bond together to form molecules, which in turn combine into more complex organisms to ultimately create all matter in our universe.”

Slide 3

Slide 3 text

Atomic Design HABITAT Atomic Design by Brad Frost - https://goo.gl/hPtDCC

Slide 4

Slide 4 text

Atomic Design ● Atoms; are the basic building blocks of matter. ● Molecules; are groups of atoms bonded together and are the smallest fundamental units of a compound. ● Habitats; are to define attributes and resources. Such as; Color, Font, Size, Icon, Style, Animation, and so on. are provided by the Android framework and built with habitats.

Slide 5

Slide 5 text

Atomic Design Habitats Atoms

Slide 6

Slide 6 text

Atomic Design Atoms Molecule Habitats 8dp

Slide 7

Slide 7 text

Atomic Design https://goo.gl/922F8e

Slide 8

Slide 8 text

Complications

Slide 9

Slide 9 text

Text Styles What is a text style? ● Font ● Size ● Line Spacing ● Letter Spacing ● Color ● Alignment Gravity

Slide 10

Slide 10 text

Text Styles Keep Gravity out of styles! Since it depends on; ● `layout_width` value

Slide 11

Slide 11 text

Text Styles Keep Gravity out of styles! Since it depends on; ● `layout_width` value ● where the `gravity` defined

Slide 12

Slide 12 text

Text Styles Keep Gravity out of styles! Since it depends on; ● `layout_width` value ● where the `gravity` defined ● `layout_gravity` or `gravity` usage

Slide 13

Slide 13 text

Text Styles Keep Gravity out of styles! Since it depends on; ● `layout_width` value ● where the `gravity` defined ● `layout_gravity` or `gravity` usage ● in which layout it is defined

Slide 14

Slide 14 text

Text Styles Custom Typography in Android by Matt Raufman https://goo.gl/cEchMz Typesetter https://goo.gl/H1P7yo Line Spacing & Letter Spacing

Slide 15

Slide 15 text

Text Styles

Slide 16

Slide 16 text

Text Styles TextView.setStyle(R.style.textstyle) TextViewCompat.setTextAppearance(textView, R.style.textstyle) ● Font ● LineSpacing ● LetterSpacing Which does not set;

Slide 17

Slide 17 text

Paddings <item name="android:layout_width">@dimen/fourteen_grid_unit</item> <item name="android:layout_height">wrap_content</item> <item name="contentPadding">@dimen/one_grid_unit</item> <item name="android:background">@color/palette_white</item> <item name="cardElevation">@dimen/card_elevation</item> Molecules with no padding Containers with paddings

Slide 18

Slide 18 text

Paddings Molecules with padding included

Slide 19

Slide 19 text

Separators They are not abomination They might break Pixel Perfection In Static UI ● Include into molecules ● Extra padding In RecyclerView ● Not in molecule ● No padding

Slide 20

Slide 20 text

Separators ● Have basic separator ○ No Padding ○ No Restriction ● Have different styles ○ Use in Static Layout ○ Use w/o paddings ○ Have variations

Slide 21

Slide 21 text

Molecules

Slide 22

Slide 22 text

Molecules State1 State2 State3 State4

Slide 23

Slide 23 text

Molecules

Slide 24

Slide 24 text

Molecules ● Same elements ○ Text Styles ○ Colors ○ Padding ○ Size Same Molecule, Different States

Slide 25

Slide 25 text

Molecules ● Need different layout types ● More Different elements than common ● Complex to Maintain Different Molecule

Slide 26

Slide 26 text

Molecules ● Extra elements ○ Have a limit? ○ Have it completely separate? ○ Are they in same category? section? Grey Zone!

Slide 27

Slide 27 text

Molecules

Slide 28

Slide 28 text

Molecules ● Easy to build ● Reusable ● Different states ● No code duplication

Slide 29

Slide 29 text

Molecules State1 State2 State3 State4

Slide 30

Slide 30 text

Options

Slide 31

Slide 31 text

Options Litho https://github.com/facebook/litho

Slide 32

Slide 32 text

Options https://github.com/Kotlin/anko

Slide 33

Slide 33 text

Droid Design System

Slide 34

Slide 34 text

DDS ● Define molecule via xml ● Set different states through xml ● Do not redraw ● Do not make runtime change ● Final on the inflation

Slide 35

Slide 35 text

DDS ● Create custom attributes ● Read attribute values ● Inflate layout ● Configure ● Set values

Slide 36

Slide 36 text

DDS internal interface DDSContract { fun getStyleableId(): IntArray fun readAttributes(typedArray: TypedArray) fun getRelevantLayout(): Int fun configureLayout() fun setViewValues() fun getContext(): Context }

Slide 37

Slide 37 text

DDS internal fun DDSContract.initialize(attributeSet: AttributeSet?) { attributeSet?.let { val typedArray = getContext().theme .obtainStyledAttributes(attributeSet, getStyleableId(), 0, 0) readAttributes(typedArray) typedArray.recycle() } if (this is ViewGroup) { inflate(getContext(), getRelevantLayout(), this) } else { throw IllegalStateException("DDSContract is not a ViewGroup.") } configureLayout() setViewValues() }

Slide 38

Slide 38 text

DDS internal fun DDSContract.initialize(attributeSet: AttributeSet?) { attributeSet?.let { val typedArray = getContext().theme .obtainStyledAttributes(attributeSet, getStyleableId(), 0, 0) readAttributes(typedArray) typedArray.recycle() } if (this is ViewGroup) { inflate(getContext(), getRelevantLayout(), this) } else { throw IllegalStateException("DDSContract is not a ViewGroup.") } configureLayout() setViewValues() }

Slide 39

Slide 39 text

DDS internal fun DDSContract.initialize(attributeSet: AttributeSet?) { attributeSet?.let { val typedArray = getContext().theme .obtainStyledAttributes(attributeSet, getStyleableId(), 0, 0) readAttributes(typedArray) typedArray.recycle() } if (this is ViewGroup) { inflate(getContext(), getRelevantLayout(), this) } else { throw IllegalStateException("DDSContract is not a ViewGroup.") } configureLayout() setViewValues() }

Slide 40

Slide 40 text

DDS internal fun DDSContract.initialize(attributeSet: AttributeSet?) { attributeSet?.let { val typedArray = getContext().theme .obtainStyledAttributes(attributeSet, getStyleableId(), 0, 0) readAttributes(typedArray) typedArray.recycle() } if (this is ViewGroup) { inflate(getContext(), getRelevantLayout(), this) } else { throw IllegalStateException("DDSContract is not a ViewGroup.") } configureLayout() setViewValues() }

Slide 41

Slide 41 text

DDS internal fun DDSContract.initialize(attributeSet: AttributeSet?) { attributeSet?.let { val typedArray = getContext().theme .obtainStyledAttributes(attributeSet, getStyleableId(), 0, 0) readAttributes(typedArray) typedArray.recycle() } if (this is ViewGroup) { inflate(getContext(), getRelevantLayout(), this) } else { throw IllegalStateException("DDSContract is not a ViewGroup.") } configureLayout() setViewValues() }

Slide 42

Slide 42 text

DDS class AvatarInfo : LinearLayout, DDSContract { } ... constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { initialize(attrs) } ...

Slide 43

Slide 43 text

DDS class AvatarInfo : LinearLayout, DDSContract { } override fun getStyleableId(): IntArray = R.styleable.AvatarInfo override fun readAttributes(typedArray: TypedArray) { with(typedArray) { state = getEnum(R.styleable.AvatarInfo_avatarInfoState) // … } } override fun configureLayout() { orientation = HORIZONTAL gravity = Gravity.CENTER }

Slide 44

Slide 44 text

DDS class AvatarInfo : LinearLayout, DDSContract { } override fun getRelevantLayout() : Int = when(state) { AvatarInfoState.STATE_1 -> R.layout.avatar_info_state_1 AvatarInfoState.STATE_2 -> R.layout.avatar_info_state_2 AvatarInfoState.STATE_3 -> R.layout.avatar_info_state_3 AvatarInfoState.STATE_4 -> R.layout.avatar_info_state_4 } enum class AvatarInfoState : DDSState { STATE_1, STATE_2, STATE_3, STATE_4 }

Slide 45

Slide 45 text

DDS

Slide 46

Slide 46 text

DDS State1

Slide 47

Slide 47 text

DDS State2

Slide 48

Slide 48 text

DDS

Slide 49

Slide 49 text

DDS class AvatarInfo : LinearLayout, DDSContract { } val title: TextView by lazy { findViewById(R.id.avatar_info_title) }

Slide 50

Slide 50 text

DDS class AvatarInfo : LinearLayout, DDSContract { } val title: TextView by lazy { state.isRequired(AvatarInfoState.STATE_3) findViewById(R.id.avatar_info_title) } internal fun DDSState.isRequired(expected: DDSState) { check(this == expected, { "This element is restricted to $expected state." }) }

Slide 51

Slide 51 text

DDS

Slide 52

Slide 52 text

DDS

Slide 53

Slide 53 text

DDS

Slide 54

Slide 54 text

Discoverable

Slide 55

Slide 55 text

Discoverable com.xing.android.dds.molecule.content.AvatarInfo

Slide 56

Slide 56 text

Discoverable

Slide 57

Slide 57 text

Summary

Slide 58

Slide 58 text

Thanks! ➢ Have a Design System :) ➢ Decide how strict you want it to be ➢ Keep an eye on the performance ➢ Make it easy to find ➢ Keep it simple ➢ Work closely with Designers Happy Developers & Designers & User