Top Banner
190

David Bilík: Anko – modern way to build your layouts?

Jan 22, 2018

Download

Mobile

mdevtalk
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: David Bilík: Anko – modern way to build your layouts?
Page 2: David Bilík: Anko – modern way to build your layouts?

DAVID BILÍKAnDev@Ackee

Page 3: David Bilík: Anko – modern way to build your layouts?

Anko - a modern way to build your layouts?

Page 4: David Bilík: Anko – modern way to build your layouts?

Anko

Page 5: David Bilík: Anko – modern way to build your layouts?

Anko• Android + Kotlin = Anko

Page 6: David Bilík: Anko – modern way to build your layouts?

Anko• Android + Kotlin = Anko

• Set of methods/extensions/helpers to make Android development easier

Page 7: David Bilík: Anko – modern way to build your layouts?

Anko• Android + Kotlin = Anko

• Set of methods/extensions/helpers to make Android development easier

• Library consists of multiple parts

Page 8: David Bilík: Anko – modern way to build your layouts?

Anko• Android + Kotlin = Anko

• Set of methods/extensions/helpers to make Android development easier

• Library consists of multiple parts

• Commons - general helpers for intents, dialogs, etc.

Page 9: David Bilík: Anko – modern way to build your layouts?

Anko• Android + Kotlin = Anko

• Set of methods/extensions/helpers to make Android development easier

• Library consists of multiple parts

• Commons - general helpers for intents, dialogs, etc.

• Sqlite - DSL for creating Sqlite Queries and helpers for parsing results

Page 10: David Bilík: Anko – modern way to build your layouts?

Anko• Android + Kotlin = Anko

• Set of methods/extensions/helpers to make Android development easier

• Library consists of multiple parts

• Commons - general helpers for intents, dialogs, etc.

• Sqlite - DSL for creating Sqlite Queries and helpers for parsing results

• Coroutines - utilities based on Kotlin Coroutines

Page 11: David Bilík: Anko – modern way to build your layouts?

Anko• Android + Kotlin = Anko

• Set of methods/extensions/helpers to make Android development easier

• Library consists of multiple parts

• Commons - general helpers for intents, dialogs, etc.

• Sqlite - DSL for creating Sqlite Queries and helpers for parsing results

• Coroutines - utilities based on Kotlin Coroutines

• Layouts - typesafe way to create layouts

Page 12: David Bilík: Anko – modern way to build your layouts?

Anko - Layouts

• Anko aims to replace XML for building UI of an app

Page 13: David Bilík: Anko – modern way to build your layouts?

Anko - Layouts

• Anko aims to replace XML for building UI of an app

• XML has several disadvantages

Page 14: David Bilík: Anko – modern way to build your layouts?

Anko - Layouts

• Anko aims to replace XML for building UI of an app

• XML has several disadvantages

• Its not typesafe and nullsafe

Page 15: David Bilík: Anko – modern way to build your layouts?

Anko - Layouts

• Anko aims to replace XML for building UI of an app

• XML has several disadvantages

• Its not typesafe and nullsafe

• Forces you to write almost the same code for every layout

you make and it allows almost no code reuse

Page 16: David Bilík: Anko – modern way to build your layouts?

Anko - Layouts

• Anko aims to replace XML for building UI of an app

• XML has several disadvantages

• Its not typesafe and nullsafe

• Forces you to write almost the same code for every layout

you make and it allows almost no code reuse

• Waste of computational resources because of parsing of

XML file in runtime

Page 17: David Bilík: Anko – modern way to build your layouts?

Performance

Page 18: David Bilík: Anko – modern way to build your layouts?

Performance

• There is couple of articles about performance comparison

between Anko and XML, all in favor of Anko

Page 19: David Bilík: Anko – modern way to build your layouts?

Performance

• There is couple of articles about performance comparison

between Anko and XML, all in favor of Anko

• One of them describes 400% speed improvement when

inflating layout using Anko instead of with LayoutInflater

Page 20: David Bilík: Anko – modern way to build your layouts?

Performance

• There is couple of articles about performance comparison

between Anko and XML, all in favor of Anko

• One of them describes 400% speed improvement when

inflating layout using Anko instead of with LayoutInflater

• I was curious if the results are really that good or if author is just a big fan of Anko

Page 21: David Bilík: Anko – modern way to build your layouts?

Performance

Page 22: David Bilík: Anko – modern way to build your layouts?

Performance• I’ve created a simple RecyclerView.Adapter with different

viewItemType for each row and I measured execution time of onCreateViewHolder method

Page 23: David Bilík: Anko – modern way to build your layouts?

Performance• I’ve created a simple RecyclerView.Adapter with different

viewItemType for each row and I measured execution time of onCreateViewHolder method

• I’ve measured 1000 creations and marked down min, max and average

values for couple of different devices

Page 24: David Bilík: Anko – modern way to build your layouts?

Performance• I’ve created a simple RecyclerView.Adapter with different

viewItemType for each row and I measured execution time of onCreateViewHolder method

• I’ve measured 1000 creations and marked down min, max and average

values for couple of different devices

Measurement results

Emulator N5X An 7.1,

SGS8 An 7.0

Nexus 5X An 8.0

GSmrad (GSmart Roma R2)

An 4.3

Huawei Y330

An 4.2.2

MiniSráč (SG Young S6310)

An 4.4.4Anko 0/57/4.3 0/54/4.7 0/32/7.4 0/226/15.2 0/558/16.7 0/206/19.8

XML 0/122/7.4 0/327/8.3 0/31/11.2 0/332/24.9 0/494/22.6 0/154/37.9

Page 25: David Bilík: Anko – modern way to build your layouts?

Example

Page 26: David Bilík: Anko – modern way to build your layouts?

</LinearLayout> </ScrollView>

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical">

Page 27: David Bilík: Anko – modern way to build your layouts?

</LinearLayout> </ScrollView>

<FrameLayout android:layout_width="match_parent" android:layout_height="180dp"> <ImageView android:layout_width="match_parent" android:layout_height="180dp" android:scaleType="fitXY" android:src="@drawable/castle"/> <ImageView android:layout_width="match_parent" android:layout_height="100dp" android:layout_gravity="bottom" android:background="@drawable/bottom_gradient"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" android:padding="16dp" android:text="Awesome title" android:textColor="@android:color/white" android:textSize="26sp"/></FrameLayout>

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical">

Page 28: David Bilík: Anko – modern way to build your layouts?

</LinearLayout> </ScrollView>

<FrameLayout android:layout_width="match_parent" android:layout_height="180dp"> <ImageView android:layout_width="match_parent" android:layout_height="180dp" android:scaleType="fitXY" android:src="@drawable/castle"/> <ImageView android:layout_width="match_parent" android:layout_height="100dp" android:layout_gravity="bottom" android:background="@drawable/bottom_gradient"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" android:padding="16dp" android:text="Awesome title" android:textColor="@android:color/white" android:textSize="26sp"/></FrameLayout>

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical">

<TextView android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="12dp" android:paddingLeft="16dp" android:paddingRight="16dp" android:paddingTop="12dp" android:text="@string/lorem_ipsum"/>

Page 29: David Bilík: Anko – modern way to build your layouts?

val scrollView = ScrollView(this) val linearLayout = LinearLayout(this).apply { orientation = LinearLayout.VERTICAL} val frameLayout = FrameLayout(this) val castleImageView = ImageView(this).apply { setImageResource(R.drawable.castle) scaleType = ImageView.ScaleType.FIT_XY} val gradientImageView = ImageView(this).apply { setImageResource(R.drawable.bottom_gradient) } val titleTextView = TextView(this).apply { val padding = dpToPx(16) setPadding(padding, padding, padding, padding) text = "Awesome title" setTextColor(ContextCompat.getColor(context, android.R.color.white)) textSize = 26f} val bodyTextView = TextView(this).apply { val horizontalPadding = dpToPx(16) val verticalPadding = dpToPx(12) setPadding(horizontalPadding, verticalPadding, horizontalPadding, verticalPadding) setText(R.string.lorem_ipsum) } frameLayout.addView(castleImageView, FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)) frameLayout.addView(gradientImageView, FrameLayout.LayoutParams(MATCH_PARENT, dpToPx(100), Gravity.BOTTOM))frameLayout.addView(titleTextView, FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT, Gravity.BOTTOM))linearLayout.addView(frameLayout, LinearLayout.LayoutParams(MATCH_PARENT, dpToPx(180)))linearLayout.addView(bodyTextView)scrollView.addView(linearLayout)setContentView(scrollView)

Page 30: David Bilík: Anko – modern way to build your layouts?

scrollView { verticalLayout { } }

Page 31: David Bilík: Anko – modern way to build your layouts?

scrollView { verticalLayout {

} }

frameLayout { imageView(R.drawable.castle) { scaleType = ImageView.ScaleType.FIT_XY }.lparams(matchParent, matchParent) imageView(R.drawable.bottom_gradient) .lparams(width = matchParent, height = dip(100), gravity = Gravity.BOTTOM) textView { padding = dip(16) text = "Awesome title" textColor = color(android.R.color.white) textSize = 26f }.lparams(gravity = Gravity.BOTTOM) }.lparams(width = matchParent, height = dip(180))

Page 32: David Bilík: Anko – modern way to build your layouts?

scrollView { verticalLayout {

} }

frameLayout { imageView(R.drawable.castle) { scaleType = ImageView.ScaleType.FIT_XY }.lparams(matchParent, matchParent) imageView(R.drawable.bottom_gradient) .lparams(width = matchParent, height = dip(100), gravity = Gravity.BOTTOM) textView { padding = dip(16) text = "Awesome title" textColor = color(android.R.color.white) textSize = 26f }.lparams(gravity = Gravity.BOTTOM) }.lparams(width = matchParent, height = dip(180))

textView { horizontalPadding = dip(16) verticalPadding = dip(12) textResource = R.string.lorem_ipsum}.lparams(matchParent, matchParent)

Page 33: David Bilík: Anko – modern way to build your layouts?

How does it work?• Because of Anko is Kotlin Library it can benefit from the easy

creation of TypeSafe builders

Page 34: David Bilík: Anko – modern way to build your layouts?

How does it work?• Because of Anko is Kotlin Library it can benefit from the easy

creation of TypeSafe builders

• Lets create a very small and stupid subset of Anko on our own

Page 35: David Bilík: Anko – modern way to build your layouts?

How does it work?• Because of Anko is Kotlin Library it can benefit from the easy

creation of TypeSafe builders

• Lets create a very small and stupid subset of Anko on our own

verticalLayout { textView { text = "Hello" }} textView(R.string.app_name) { textSize = 26f }} }}

Page 36: David Bilík: Anko – modern way to build your layouts?

DSL verticalLayout { textView { text = "Hello" }} textView(R.string.app_name) { textSize = 26f }} }}

Page 37: David Bilík: Anko – modern way to build your layouts?

DSL

• We need 2 functions, verticalLayout and textView

verticalLayout { textView { text = "Hello" }} textView(R.string.app_name) { textSize = 26f }} }}

Page 38: David Bilík: Anko – modern way to build your layouts?

DSL

• We need 2 functions, verticalLayout and textViewfun Activity.verticalLayout( ): LinearLayout { val layout = LinearLayout(this) with(layout) { orientation = LinearLayout.VERTICAL init() } return layout}

init: LinearLayout.() -> Unit

verticalLayout { textView { text = "Hello" }} textView(R.string.app_name) { textSize = 26f }} }}

Page 39: David Bilík: Anko – modern way to build your layouts?

DSL

• We need 2 functions, verticalLayout and textViewfun Activity.verticalLayout( ): LinearLayout { val layout = LinearLayout(this) with(layout) { orientation = LinearLayout.VERTICAL init() } return layout}

init: LinearLayout.() -> Unit

verticalLayout { textView { text = "Hello" }} textView(R.string.app_name) { textSize = 26f }} }}

Page 40: David Bilík: Anko – modern way to build your layouts?

DSL

• We need 2 functions, verticalLayout and textViewfun Activity.verticalLayout( ): LinearLayout { val layout = LinearLayout(this) with(layout) { orientation = LinearLayout.VERTICAL init() } return layout}

init: LinearLayout.() -> Unit

verticalLayout { textView { text = "Hello" }} textView(R.string.app_name) { textSize = 26f }} }}

Page 41: David Bilík: Anko – modern way to build your layouts?

DSL

• We need 2 functions, verticalLayout and textViewfun Activity.verticalLayout( ): LinearLayout { val layout = LinearLayout(this) with(layout) { orientation = LinearLayout.VERTICAL init() } return layout}

fun ViewGroup.textView(init: TextView.() -> Unit): TextView { val textView = TextView(context) textView.init() addView(textView) return textView}

init: LinearLayout.() -> Unit

verticalLayout { textView { text = "Hello" }} textView(R.string.app_name) { textSize = 26f }} }}

Page 42: David Bilík: Anko – modern way to build your layouts?

DSL

• init has a type that is called function type with receiver T.() -> Unit

Page 43: David Bilík: Anko – modern way to build your layouts?

DSL

• init has a type that is called function type with receiver T.() -> Unit

• we need to pass an instance of T (receiver) to the function and we can access members of that instnace

Page 44: David Bilík: Anko – modern way to build your layouts?

DSL

• init has a type that is called function type with receiver T.() -> Unit

• we need to pass an instance of T (receiver) to the function and we can access members of that instnace

• The same restrictions applies as for Extensions functions - only public members and methods can be accessed

Page 45: David Bilík: Anko – modern way to build your layouts?

DSL• There is a little annoying “bug” that was also in Anko

Page 46: David Bilík: Anko – modern way to build your layouts?

DSL• There is a little annoying “bug” that was also in Anko

• Nothing stops us from doing this

textView { text = "Hello" textView { text = "World" } }

Page 47: David Bilík: Anko – modern way to build your layouts?

DSL• There is a little annoying “bug” that was also in Anko

• Nothing stops us from doing this

• We can generate syntactically incorrect results

textView { text = "Hello" textView { text = "World" } }

Page 48: David Bilík: Anko – modern way to build your layouts?

DSL• There is a little annoying “bug” that was also in Anko

• Nothing stops us from doing this

• We can generate syntactically incorrect results

• It’s possible because we are still inside the context of the outer verticalLayout

textView { text = "Hello" textView { text = "World" } }

Page 49: David Bilík: Anko – modern way to build your layouts?

DSL• Kotlin has a solution from v1.1

• We need to create annotation with which we mark our init methods

LinearLayout.() -> Unit): LinearLayout {LinearLayout).() -> Unit): LinearLayout {(@UIDSLMaker

Page 50: David Bilík: Anko – modern way to build your layouts?

DSL• Kotlin has a solution from v1.1

• We need to create annotation with which we mark our init methods

@DslMarker@Target(AnnotationTarget.TYPE) annotation class UIDSLMaker

LinearLayout.() -> Unit): LinearLayout {LinearLayout).() -> Unit): LinearLayout {(@UIDSLMaker

Page 51: David Bilík: Anko – modern way to build your layouts?

DSL• Kotlin has a solution from v1.1

• We need to create annotation with which we mark our init methods

@DslMarker@Target(AnnotationTarget.TYPE) annotation class UIDSLMaker

fun Activity.verticalLayout(init: val layout = LinearLayout(this) with(layout) { orientation = LinearLayout.VERTICAL init() } return layout}

LinearLayout.() -> Unit): LinearLayout {LinearLayout).() -> Unit): LinearLayout {(@UIDSLMaker

Page 52: David Bilík: Anko – modern way to build your layouts?

DSL• Kotlin has a solution from v1.1

• We need to create annotation with which we mark our init methods

@DslMarker@Target(AnnotationTarget.TYPE) annotation class UIDSLMaker

fun Activity.verticalLayout(init: val layout = LinearLayout(this) with(layout) { orientation = LinearLayout.VERTICAL init() } return layout}

LinearLayout.() -> Unit): LinearLayout {LinearLayout).() -> Unit): LinearLayout {(@UIDSLMaker

Page 53: David Bilík: Anko – modern way to build your layouts?

DSL• Kotlin has a solution from v1.1

• We need to create annotation with which we mark our init methods

@DslMarker@Target(AnnotationTarget.TYPE) annotation class UIDSLMaker

fun Activity.verticalLayout(init: val layout = LinearLayout(this) with(layout) { orientation = LinearLayout.VERTICAL init() } return layout}

LinearLayout.() -> Unit): LinearLayout {LinearLayout).() -> Unit): LinearLayout {(@UIDSLMaker

Page 54: David Bilík: Anko – modern way to build your layouts?

How does it work #2?

• DSL explains why the layout looks structurized but there is

more in Anko (or Kotlin) that makes building layouts easier

• Lets take a look at our first Anko sample

Page 55: David Bilík: Anko – modern way to build your layouts?

How does it work #2?

• DSL explains why the layout looks structurized but there is

more in Anko (or Kotlin) that makes building layouts easier

• Lets take a look at our first Anko sample

textView { padding = dip(16) text = "Awesome title" textColor = color(android.R.color.white) textSize = 26f}.lparams(gravity = Gravity.BOTTOM)

Page 56: David Bilík: Anko – modern way to build your layouts?

How does it work #2?textView { padding = dip(16) text = "Awesome title" textColor = color(android.R.color.white) textSize = 26f}.lparams(gravity = Gravity.BOTTOM)

Page 57: David Bilík: Anko – modern way to build your layouts?

How does it work #2?

• text and textSize are synthetic extension properties bound to the getters and setters from Java. Both of these must exists for compiler to create these properties

textView { padding = dip(16) text = "Awesome title" textColor = color(android.R.color.white) textSize = 26f}.lparams(gravity = Gravity.BOTTOM)

Page 58: David Bilík: Anko – modern way to build your layouts?

How does it work #2?

• text and textSize are synthetic extension properties bound to the getters and setters from Java. Both of these must exists for compiler to create these properties

• padding and textColor are extension properties built in Anko. They exists for the most used properties in views that don’t provide getters/setters for given property

textView { padding = dip(16) text = "Awesome title" textColor = color(android.R.color.white) textSize = 26f}.lparams(gravity = Gravity.BOTTOM)

Page 59: David Bilík: Anko – modern way to build your layouts?

How does it work #2?

• text and textSize are synthetic extension properties bound to the getters and setters from Java. Both of these must exists for compiler to create these properties

• padding and textColor are extension properties built in Anko. They exists for the most used properties in views that don’t provide getters/setters for given property

• dip(Int) is an extension property from Anko. Converts integer argument from dps to pxs

textView { padding = dip(16) text = "Awesome title" textColor = color(android.R.color.white) textSize = 26f}.lparams(gravity = Gravity.BOTTOM)

Page 60: David Bilík: Anko – modern way to build your layouts?

How does it work #2?

• text and textSize are synthetic extension properties bound to the getters and setters from Java. Both of these must exists for compiler to create these properties

• padding and textColor are extension properties built in Anko. They exists for the most used properties in views that don’t provide getters/setters for given property

• dip(Int) is an extension property from Anko. Converts integer argument from dps to pxs

• color(Int) is our extension function for retrieving color resource

@ColorIntfun View.color(@ColorRes colorRes: Int) = ContextCompat.getColor(context, colorRes)

textView { padding = dip(16) text = "Awesome title" textColor = color(android.R.color.white) textSize = 26f}.lparams(gravity = Gravity.BOTTOM)

Page 61: David Bilík: Anko – modern way to build your layouts?

How does it work #3?verticalLayout { frameLayout { //rest of the views }.lparams(width = matchParent, height = dip(180)) textView(R.string.lorem_ipsum) { horizontalPadding = dip(16) verticalPadding = dip(12) }.lparams(matchParent, matchParent) }

Page 62: David Bilík: Anko – modern way to build your layouts?

How does it work #3?

• horizontalPadding and verticalPadding are also extension properties, but for attributes that don’t exist in View definition.

verticalLayout { frameLayout { //rest of the views }.lparams(width = matchParent, height = dip(180)) textView(R.string.lorem_ipsum) { horizontalPadding = dip(16) verticalPadding = dip(12) }.lparams(matchParent, matchParent) }

Page 63: David Bilík: Anko – modern way to build your layouts?

How does it work #3?

• horizontalPadding and verticalPadding are also extension properties, but for attributes that don’t exist in View definition.

• verticalLayout (as in our own DSL) is a LinearLayout with orientation set to VERTICAL

verticalLayout { frameLayout { //rest of the views }.lparams(width = matchParent, height = dip(180)) textView(R.string.lorem_ipsum) { horizontalPadding = dip(16) verticalPadding = dip(12) }.lparams(matchParent, matchParent) }

Page 64: David Bilík: Anko – modern way to build your layouts?

How does it work #3?

• horizontalPadding and verticalPadding are also extension properties, but for attributes that don’t exist in View definition.

• verticalLayout (as in our own DSL) is a LinearLayout with orientation set to VERTICAL

• textView(Int) is a helper block constructor that takes string resource as a parameter. These helper blocks exist for some of the views like editText, textView, imageView, …

verticalLayout { frameLayout { //rest of the views }.lparams(width = matchParent, height = dip(180)) textView(R.string.lorem_ipsum) { horizontalPadding = dip(16) verticalPadding = dip(12) }.lparams(matchParent, matchParent) }

Page 65: David Bilík: Anko – modern way to build your layouts?

How does it work #4?verticalLayout { frameLayout { //rest of the views

textView { }.lparams(gravity = Gravity.BOTTOM)

}.lparams(width = matchParent, height = dip(180)) textView(R.string.lorem_ipsum) { horizontalPadding = dip(16) verticalPadding = dip(12) }.lparams(matchParent, matchParent) { bottomMargin = dip(8) }}

Page 66: David Bilík: Anko – modern way to build your layouts?

How does it work #4?

• lparams is a function for definition of Layout Parameters in the context of current ViewGroup

verticalLayout { frameLayout { //rest of the views

textView { }.lparams(gravity = Gravity.BOTTOM)

}.lparams(width = matchParent, height = dip(180)) textView(R.string.lorem_ipsum) { horizontalPadding = dip(16) verticalPadding = dip(12) }.lparams(matchParent, matchParent) { bottomMargin = dip(8) }}

Page 67: David Bilík: Anko – modern way to build your layouts?

How does it work #4?

• lparams is a function for definition of Layout Parameters in the context of current ViewGroup

• It should be defined after the View definition

verticalLayout { frameLayout { //rest of the views

textView { }.lparams(gravity = Gravity.BOTTOM)

}.lparams(width = matchParent, height = dip(180)) textView(R.string.lorem_ipsum) { horizontalPadding = dip(16) verticalPadding = dip(12) }.lparams(matchParent, matchParent) { bottomMargin = dip(8) }}

Page 68: David Bilík: Anko – modern way to build your layouts?

How does it work #4?

• lparams is a function for definition of Layout Parameters in the context of current ViewGroup

• It should be defined after the View definition

• All lparams accepts width and height parameters. Default value is wrapContent (extension property of WRAP_CONTENT, same for matchParent)

verticalLayout { frameLayout { //rest of the views

textView { }.lparams(gravity = Gravity.BOTTOM)

}.lparams(width = matchParent, height = dip(180)) textView(R.string.lorem_ipsum) { horizontalPadding = dip(16) verticalPadding = dip(12) }.lparams(matchParent, matchParent) { bottomMargin = dip(8) }}

Page 69: David Bilík: Anko – modern way to build your layouts?

How does it work #4?

• lparams is a function for definition of Layout Parameters in the context of current ViewGroup

• It should be defined after the View definition

• All lparams accepts width and height parameters. Default value is wrapContent (extension property of WRAP_CONTENT, same for matchParent)

• Some lparams have overloads, eg. LinearLayout.lparams accepts weight: Float or

FrameLayout.lparams accepts gravity: Int

verticalLayout { frameLayout { //rest of the views

textView { }.lparams(gravity = Gravity.BOTTOM)

}.lparams(width = matchParent, height = dip(180)) textView(R.string.lorem_ipsum) { horizontalPadding = dip(16) verticalPadding = dip(12) }.lparams(matchParent, matchParent) { bottomMargin = dip(8) }}

Page 70: David Bilík: Anko – modern way to build your layouts?

How does it work #4?

• lparams is a function for definition of Layout Parameters in the context of current ViewGroup

• It should be defined after the View definition

• All lparams accepts width and height parameters. Default value is wrapContent (extension property of WRAP_CONTENT, same for matchParent)

• Some lparams have overloads, eg. LinearLayout.lparams accepts weight: Float or

FrameLayout.lparams accepts gravity: Int

• lparams also accepts lambda with parameters definition just as functions for View definitions

verticalLayout { frameLayout { //rest of the views

textView { }.lparams(gravity = Gravity.BOTTOM)

}.lparams(width = matchParent, height = dip(180)) textView(R.string.lorem_ipsum) { horizontalPadding = dip(16) verticalPadding = dip(12) }.lparams(matchParent, matchParent) { bottomMargin = dip(8) }}

Page 71: David Bilík: Anko – modern way to build your layouts?

Layout Parameters• In some tutorials you can see lparams block inside of view definition

textView(R.string.lorem_ipsum) { horizontalPadding = dip(16) verticalPadding = dip(12) }.lparams(matchParent, matchParent) { bottomMargin = dip(8) }

Page 72: David Bilík: Anko – modern way to build your layouts?

Layout Parameters• In some tutorials you can see lparams block inside of view definition

textView(R.string.lorem_ipsum) { horizontalPadding = dip(16) verticalPadding = dip(12) }.lparams(matchParent, matchParent) { bottomMargin = dip(8) }

lparams(matchParent, matchParent) { bottomMargin = dip(8) } }

Page 73: David Bilík: Anko – modern way to build your layouts?

Layout Parameters• In some tutorials you can see lparams block inside of view definition

textView(R.string.lorem_ipsum) { horizontalPadding = dip(16) verticalPadding = dip(12) }.lparams(matchParent, matchParent) { bottomMargin = dip(8) }

lparams(matchParent, matchParent) { bottomMargin = dip(8) } }

• Sometimes it works, but sometimes it doesn’t and you don’t know why 🤔. What happens in this case?

verticalLayout { lparams { } frameLayout { lparams { } } }

Page 74: David Bilík: Anko – modern way to build your layouts?

Layout Parameters• In some tutorials you can see lparams block inside of view definition

textView(R.string.lorem_ipsum) { horizontalPadding = dip(16) verticalPadding = dip(12) }.lparams(matchParent, matchParent) { bottomMargin = dip(8) }

lparams(matchParent, matchParent) { bottomMargin = dip(8) } }

• Sometimes it works, but sometimes it doesn’t and you don’t know why 🤔. What happens in this case?

verticalLayout { lparams { } frameLayout { lparams { } } }

// lparams is LinearLayout.LayoutParams

Page 75: David Bilík: Anko – modern way to build your layouts?

Layout Parameters• In some tutorials you can see lparams block inside of view definition

textView(R.string.lorem_ipsum) { horizontalPadding = dip(16) verticalPadding = dip(12) }.lparams(matchParent, matchParent) { bottomMargin = dip(8) }

lparams(matchParent, matchParent) { bottomMargin = dip(8) } }

• Sometimes it works, but sometimes it doesn’t and you don’t know why 🤔. What happens in this case?

verticalLayout { lparams { } frameLayout { lparams { } } }

// lparams is LinearLayout.LayoutParams

// lparams is FrameLayout.LayoutParams => INCORRECT, it should be LinearLayout.LayoutParams

Page 76: David Bilík: Anko – modern way to build your layouts?

Layout Parameters• In some tutorials you can see lparams block inside of view definition

textView(R.string.lorem_ipsum) { horizontalPadding = dip(16) verticalPadding = dip(12) }.lparams(matchParent, matchParent) { bottomMargin = dip(8) }

lparams(matchParent, matchParent) { bottomMargin = dip(8) } }

• Sometimes it works, but sometimes it doesn’t and you don’t know why 🤔. What happens in this case?

verticalLayout { lparams { } frameLayout { lparams { } } }

// lparams is LinearLayout.LayoutParams

// lparams is FrameLayout.LayoutParams => INCORRECT, it should be LinearLayout.LayoutParams

• Because of that, you need to define lparams for the most outer ViewGroup just like without Anko

Page 77: David Bilík: Anko – modern way to build your layouts?

Layout Parameters• Because of that, you need to define lparams for the most outer ViewGroup just like without Anko

verticalLayout { layoutParams = ViewGroup.LayoutParams(matchParent, dip(180)) frameLayout { }.lparams { }}

Page 78: David Bilík: Anko – modern way to build your layouts?

Beyond the Anko• If you find a View that doesn’t have corresponding extension fnc in

Anko or you have your own custom view, you can use customView extension

Page 79: David Bilík: Anko – modern way to build your layouts?

Beyond the Anko• If you find a View that doesn’t have corresponding extension fnc in

Anko or you have your own custom view, you can use customView extension

customView<SquaredFrameLayout> { backgroundResource = android.R.color.black}

Page 80: David Bilík: Anko – modern way to build your layouts?

Beyond the Anko• If you find a View that doesn’t have corresponding extension fnc in

Anko or you have your own custom view, you can use customView extension

customView<SquaredFrameLayout> { backgroundResource = android.R.color.black}

• If you have a view that is used multiple times it may be convenient to

define your own extension function

Page 81: David Bilík: Anko – modern way to build your layouts?

Beyond the Anko• If you find a View that doesn’t have corresponding extension fnc in

Anko or you have your own custom view, you can use customView extension

customView<SquaredFrameLayout> { backgroundResource = android.R.color.black}

• If you have a view that is used multiple times it may be convenient to

define your own extension function

inline fun ViewManager.squaredFrameLayout(init: SquaredFrameLayout.() -> Unit): SquaredFrameLayout { return ankoView(::SquaredFrameLayout, theme = 0, init = init)}

Page 82: David Bilík: Anko – modern way to build your layouts?

Beyond the Anko• If you find a View that doesn’t have corresponding extension fnc in

Anko or you have your own custom view, you can use customView extension

customView<SquaredFrameLayout> { backgroundResource = android.R.color.black}

• If you have a view that is used multiple times it may be convenient to

define your own extension function

inline fun ViewManager.squaredFrameLayout(init: SquaredFrameLayout.() -> Unit): SquaredFrameLayout { return ankoView(::SquaredFrameLayout, theme = 0, init = init)}

squaredFrameLayout { backgroundResource = android.R.color.black}

Page 83: David Bilík: Anko – modern way to build your layouts?

Anko Components

Page 84: David Bilík: Anko – modern way to build your layouts?

Anko Components

• Every View extension is defined for ViewManager interface. That’s

convenient because every ViewGroup implements this interface. A few of them are also defined for Activities (mostly ViewGroups eg.

linearLayout)

Page 85: David Bilík: Anko – modern way to build your layouts?

Anko Components

• Every View extension is defined for ViewManager interface. That’s

convenient because every ViewGroup implements this interface. A few of them are also defined for Activities (mostly ViewGroups eg.

linearLayout)

• You can define your UI right inside an Activity or Fragment, but that

leads to loose coupling between your presentation logic and view

definition

Page 86: David Bilík: Anko – modern way to build your layouts?

Anko Components

• Every View extension is defined for ViewManager interface. That’s

convenient because every ViewGroup implements this interface. A few of them are also defined for Activities (mostly ViewGroups eg.

linearLayout)

• You can define your UI right inside an Activity or Fragment, but that

leads to loose coupling between your presentation logic and view

definition

• Anko has concept of AnkoComponents

Page 87: David Bilík: Anko – modern way to build your layouts?

Anko Components• AnkoComponent is meant to be a reusable piece of UI

Page 88: David Bilík: Anko – modern way to build your layouts?

Anko Components• AnkoComponent is meant to be a reusable piece of UI

interface AnkoComponent<in T> { fun createView(ui: AnkoContext<T>): View}

Page 89: David Bilík: Anko – modern way to build your layouts?

Anko Components• AnkoComponent is meant to be a reusable piece of UI

interface AnkoComponent<in T> { fun createView(ui: AnkoContext<T>): View}

• You must provide AnkoContext which allows you to create views

without Activity or any particular ViewGroup. It implements ViewManager

Page 90: David Bilík: Anko – modern way to build your layouts?

Anko Components• AnkoComponent is meant to be a reusable piece of UI

interface AnkoComponent<in T> { fun createView(ui: AnkoContext<T>): View}

• You must provide AnkoContext which allows you to create views

without Activity or any particular ViewGroup. It implements ViewManager

• With AnkoComponent you can see Preview of your layout.

Page 91: David Bilík: Anko – modern way to build your layouts?

Anko Components• AnkoComponent is meant to be a reusable piece of UI

interface AnkoComponent<in T> { fun createView(ui: AnkoContext<T>): View}

• You must provide AnkoContext which allows you to create views

without Activity or any particular ViewGroup. It implements ViewManager

• With AnkoComponent you can see Preview of your layout.

• Unfortunately not now. Preview has been broken since AS 1.6, then fixed in 2.4 but now its broken once again :(

Page 92: David Bilík: Anko – modern way to build your layouts?

Anko Componentsclass SampleComponent : AnkoComponent<AnkoComponentActivity> { override fun createView(ui: AnkoContext<AnkoComponentActivity>): View { return with(ui) {

frameLayout { layoutParams = ViewGroup.LayoutParams(matchParent, dip(180)) imageView(R.drawable.castle) { scaleType = ImageView.ScaleType.FIT_XY }.lparams(matchParent, matchParent) imageView(R.drawable.bottom_gradient) .lparams(width = matchParent, height = dip(100), gravity = Gravity.BOTTOM) textView { padding = dip(16) text = "Awesome title" textColor = color(android.R.color.white) textSize = 26f }.lparams(gravity = Gravity.BOTTOM) }

} } }

Page 93: David Bilík: Anko – modern way to build your layouts?

Anko Componentsclass SampleComponent : AnkoComponent<AnkoComponentActivity> { override fun createView(ui: AnkoContext<AnkoComponentActivity>): View { return with(ui) {

frameLayout { layoutParams = ViewGroup.LayoutParams(matchParent, dip(180)) imageView(R.drawable.castle) { scaleType = ImageView.ScaleType.FIT_XY }.lparams(matchParent, matchParent) imageView(R.drawable.bottom_gradient) .lparams(width = matchParent, height = dip(100), gravity = Gravity.BOTTOM) textView { padding = dip(16) text = "Awesome title" textColor = color(android.R.color.white) textSize = 26f }.lparams(gravity = Gravity.BOTTOM) }

} } }

Page 94: David Bilík: Anko – modern way to build your layouts?

Anko Componentsclass SampleComponent : AnkoComponent<AnkoComponentActivity> { override fun createView(ui: AnkoContext<AnkoComponentActivity>): View {

layoutParams = ViewGroup.LayoutParams(matchParent, dip(180)) imageView(R.drawable.castle) { scaleType = ImageView.ScaleType.FIT_XY }.lparams(matchParent, matchParent) imageView(R.drawable.bottom_gradient) .lparams(width = matchParent, height = dip(100), gravity = Gravity.BOTTOM) textView { padding = dip(16) text = "Awesome title" textColor = color(android.R.color.white) textSize = 26f }.lparams(gravity = Gravity.BOTTOM) }

} }

return ui.frameLayout {

Page 95: David Bilík: Anko – modern way to build your layouts?

Mixing with XML• If you would like to try Anko, but you have part of your layout in XML

and its not the right time to convert it you can use <include> tag

Page 96: David Bilík: Anko – modern way to build your layouts?

Mixing with XML• If you would like to try Anko, but you have part of your layout in XML

and its not the right time to convert it you can use <include> tag

include<View>(R.layout.something) { backgroundColor = Color.RED }.lparams(width = matchParent)

Page 97: David Bilík: Anko – modern way to build your layouts?

Mixing with XML• If you would like to try Anko, but you have part of your layout in XML

and its not the right time to convert it you can use <include> tag

include<View>(R.layout.something) { backgroundColor = Color.RED }.lparams(width = matchParent)

• You can specify the type of the parent View in XML and you can set

properties bound to this type

Page 98: David Bilík: Anko – modern way to build your layouts?

Mixing with XML• If you would like to try Anko, but you have part of your layout in XML

and its not the right time to convert it you can use <include> tag

include<View>(R.layout.something) { backgroundColor = Color.RED }.lparams(width = matchParent)

• You can specify the type of the parent View in XML and you can set

properties bound to this type

include<TextView>(R.layout.item_text) { textSize = 24f }.lparams(width = matchParent)

Page 99: David Bilík: Anko – modern way to build your layouts?

And that's where the official docs ends

Page 100: David Bilík: Anko – modern way to build your layouts?

And that's where the official docs ends

What else?

Page 101: David Bilík: Anko – modern way to build your layouts?

Styling

• “So, how do you style with Anko?”

Page 102: David Bilík: Anko – modern way to build your layouts?

Styling

• “So, how do you style with Anko?”

• We are in code, so the same rules apply as in programming anything else

Page 103: David Bilík: Anko – modern way to build your layouts?

textView(R.string.title_user) {

textView {

textView {

textView(R.string.title_address) {

textSize = 24f textColor = R.color.black horizontalPadding = dip(12) verticalPadding = dip(16) typeface = bold}

textSize = 18f textColor = R.color.semiblack horizontalPadding = dip(16) verticalPadding = dip(8) typeface = medium}

textSize = 24f textColor = R.color.black horizontalPadding = dip(12) verticalPadding = dip(16) typeface = bold}

textSize = 18f textColor = R.color.semiblack horizontalPadding = dip(16) verticalPadding = dip(8) typeface = medium }

Page 104: David Bilík: Anko – modern way to build your layouts?

textView(R.string.title_user) {

textView {

textView {

textView(R.string.title_address) {

textSize = 24f textColor = R.color.black horizontalPadding = dip(12) verticalPadding = dip(16) typeface = bold}

textSize = 18f textColor = R.color.semiblack horizontalPadding = dip(16) verticalPadding = dip(8) typeface = medium}

textSize = 24f textColor = R.color.black horizontalPadding = dip(12) verticalPadding = dip(16) typeface = bold}

textSize = 18f textColor = R.color.semiblack horizontalPadding = dip(16) verticalPadding = dip(8) typeface = medium }

Page 105: David Bilík: Anko – modern way to build your layouts?

textView(R.string.title_user) {

textView {

textView {

textView(R.string.title_address) {

textSize = 24f textColor = R.color.black horizontalPadding = dip(12) verticalPadding = dip(16) typeface = bold}

textSize = 18f textColor = R.color.semiblack horizontalPadding = dip(16) verticalPadding = dip(8) typeface = medium}

textSize = 24f textColor = R.color.black horizontalPadding = dip(12) verticalPadding = dip(16) typeface = bold}

textSize = 18f textColor = R.color.semiblack horizontalPadding = dip(16) verticalPadding = dip(8) typeface = medium }

Page 106: David Bilík: Anko – modern way to build your layouts?

private fun TextView.valueStyle() { textSize = 18f textColor = R.color.semiblack horizontalPadding = dip(16) verticalPadding = dip(8) typeface = medium} private fun TextView.titleStyle() { textSize = 24f textColor = R.color.black horizontalPadding = dip(12) verticalPadding = dip(16) typeface = bold}

Page 107: David Bilík: Anko – modern way to build your layouts?

private fun TextView.valueStyle() { textSize = 18f textColor = R.color.semiblack horizontalPadding = dip(16) verticalPadding = dip(8) typeface = medium} private fun TextView.titleStyle() { textSize = 24f textColor = R.color.black horizontalPadding = dip(12) verticalPadding = dip(16) typeface = bold}

textView(R.string.title_user) { titleStyle()} textView { valueStyle()} textView(R.string.title_address) { titleStyle()} textView { valueStyle()}

Page 108: David Bilík: Anko – modern way to build your layouts?

Custom view attributes

• The same way how horizontalPadding and verticalPadding are

defined, we can create own extensions that simplify work

• How many times have you wrote variation of this?

Page 109: David Bilík: Anko – modern way to build your layouts?

Custom view attributes

• The same way how horizontalPadding and verticalPadding are

defined, we can create own extensions that simplify work

• How many times have you wrote variation of this?

fun showProgress(show: Boolean) { progress.visibility = if (show) View.VISIBLE else View.GONE}

Page 110: David Bilík: Anko – modern way to build your layouts?

Custom view attributes

• The same way how horizontalPadding and verticalPadding are

defined, we can create own extensions that simplify work

• How many times have you wrote variation of this?

fun showProgress(show: Boolean) { progress.visibility = if (show) View.VISIBLE else View.GONE}

• Don’t you (sometimes of course) wish that it would look like this?

fun showProgress(show: Boolean) { progress.visible = show}}

Page 111: David Bilík: Anko – modern way to build your layouts?

Custom view attributesfun showProgress(show: Boolean) { progress.visible = show}}

var View.visible: Boolean set(value) { visibility = if (value) View.VISIBLE else View.GONE } get() = visibility == View.VISIBLE

Page 112: David Bilík: Anko – modern way to build your layouts?

Custom extensions• Recap: Extension for retrieving color from resources

@ColorIntfun View.color(@ColorRes colorRes: Int) = ContextCompat.getColor(context, colorRes)

Page 113: David Bilík: Anko – modern way to build your layouts?

Custom extensions• Recap: Extension for retrieving color from resources

@ColorIntfun View.color(@ColorRes colorRes: Int) = ContextCompat.getColor(context, colorRes)

• We have these methods for all types of resources (drawable, string, dimension), but we can go further…

Page 114: David Bilík: Anko – modern way to build your layouts?

Custom extensions• Recap: Extension for retrieving color from resources

@ColorIntfun View.color(@ColorRes colorRes: Int) = ContextCompat.getColor(context, colorRes)

• We have these methods for all types of resources (drawable, string, dimension), but we can go further…

• Our designers have a weird fetish: Reuse the same color but with different opacity

Page 115: David Bilík: Anko – modern way to build your layouts?

Custom extensions• Recap: Extension for retrieving color from resources

@ColorIntfun View.color(@ColorRes colorRes: Int) = ContextCompat.getColor(context, colorRes)

• We have these methods for all types of resources (drawable, string, dimension), but we can go further…

• Our designers have a weird fetish: Reuse the same color but with different opacity<color name="color_primary_40_alpha">#662d3241</color> <color name="color_primary_50_alpha">#7f2d3241</color> <color name="color_primary_30_alpha">#4d2d3241</color> <color name="color_primary_20_alpha">#332d3241</color> <color name="color_primary_70_alpha">#b32d3241</color> <color name="color_primary_80_alpha">#cc2d3241</color> <color name="color_primary_90_alpha">#e52d3241</color>

Page 116: David Bilík: Anko – modern way to build your layouts?

Custom extensions• It would be really awesome to not redefine the same color, compute the

hex number from percentages etc.

Page 117: David Bilík: Anko – modern way to build your layouts?

Custom extensions• It would be really awesome to not redefine the same color, compute the

hex number from percentages etc.

@ColorIntfun View.color(@ColorRes colorRes: Int, alpha: Int = 100): Int { val color = ContextCompat.getColor(context, colorRes) if (alpha != 100) { return Color.argb((alpha / 100f * 255).toInt(), Color.red(color), Color.green(color), Color.blue(color)) } else { return color }}

Page 118: David Bilík: Anko – modern way to build your layouts?

Custom extensions

textView { padding = dip(16) text = "Awesome title" textColor = color(R.color.color_primary, alpha = 50) textSize = 26f}

Page 119: David Bilík: Anko – modern way to build your layouts?

Custom extensions

fun View.tintedDrawable(@DrawableRes drawableId: Int, @ColorRes colorId: Int): Drawable { val tint: Int = ContextCompat.getColor(context, colorId) val drawable: Drawable = ContextCompat.getDrawable(context, drawableId) drawable.mutate() DrawableCompat.setTint(drawable, tint) return drawable}

Page 120: David Bilík: Anko – modern way to build your layouts?

Custom extensions

fun View.tintedDrawable(@DrawableRes drawableId: Int, @ColorRes colorId: Int): Drawable { val tint: Int = ContextCompat.getColor(context, colorId) val drawable: Drawable = ContextCompat.getDrawable(context, drawableId) drawable.mutate() DrawableCompat.setTint(drawable, tint) return drawable}

imageView { image = tintedDrawable(R.drawable.ic_plus, R.color.white)}.lparams(dip(20), dip(20))

Page 121: David Bilík: Anko – modern way to build your layouts?

Configurations

Page 122: David Bilík: Anko – modern way to build your layouts?

Configurations• Anko has a function configuration() that takes configurations

attributes (screenSize, orientation, density,…) and lambda and it

execute given lambda only if current configuration matches attributes

Page 123: David Bilík: Anko – modern way to build your layouts?

Configurations• Anko has a function configuration() that takes configurations

attributes (screenSize, orientation, density,…) and lambda and it

execute given lambda only if current configuration matches attributes

var isLandscape = falseconfiguration(orientation = Orientation.LANDSCAPE) { isLandscape = true}

Page 124: David Bilík: Anko – modern way to build your layouts?

Configurations• Anko has a function configuration() that takes configurations

attributes (screenSize, orientation, density,…) and lambda and it

execute given lambda only if current configuration matches attributes

var isLandscape = falseconfiguration(orientation = Orientation.LANDSCAPE) { isLandscape = true}

• You can put a few ifs to your layout to change it according to device orientation

Page 125: David Bilík: Anko – modern way to build your layouts?

linearLayout { orientation = if (isLandscape) LinearLayout.HORIZONTAL else LinearLayout.VERTICAL if (!isLandscape) { padding = dip(16) } imageView(R.drawable.castle) { }.lparams { if (isLandscape) { width = 0 weight = 1f } } verticalLayout { editText { hint = "Email" } editText { hint = "Password" } button("Login") }.lparams { if (isLandscape) { width = 0 weight = 1f } else { width = matchParent } height = wrapContent }}

Page 126: David Bilík: Anko – modern way to build your layouts?

linearLayout { orientation = if (isLandscape) LinearLayout.HORIZONTAL else LinearLayout.VERTICAL if (!isLandscape) { padding = dip(16) } imageView(R.drawable.castle) { }.lparams { if (isLandscape) { width = 0 weight = 1f } } verticalLayout { editText { hint = "Email" } editText { hint = "Password" } button("Login") }.lparams { if (isLandscape) { width = 0 weight = 1f } else { width = matchParent } height = wrapContent }}

SPAGHETTI

Page 127: David Bilík: Anko – modern way to build your layouts?

Configurations• Its better to apply good old OOP principles.

abstract class ScreenLayout : AnkoComponent<ConfigChangeActivity> { abstract var imageLogo: ImageView abstract var editEmail: EditText abstract var editPassword: EditText abstract var btnLogin: Button

}

Page 128: David Bilík: Anko – modern way to build your layouts?

Configurations• Its better to apply good old OOP principles.

abstract class ScreenLayout : AnkoComponent<ConfigChangeActivity> { abstract var imageLogo: ImageView abstract var editEmail: EditText abstract var editPassword: EditText abstract var btnLogin: Button

class LayoutPortrait : ScreenLayout() { override lateinit var imageLogo: ImageView override lateinit var editEmail: EditText override lateinit var editPassword: EditText override lateinit var btnLogin: Button override fun createView(ui: AnkoContext<ConfigChangeActivity>): View { return with(ui) { verticalLayout { padding = dip(16) imageLogo = imageView(R.drawable.castle) editEmail = editText { hint = "Email" } editPassword = editText { hint = "Password" } btnLogin = button("Login") } } } }

}

Page 129: David Bilík: Anko – modern way to build your layouts?

Configurations• Its better to apply good old OOP principles.

abstract class ScreenLayout : AnkoComponent<ConfigChangeActivity> { abstract var imageLogo: ImageView abstract var editEmail: EditText abstract var editPassword: EditText abstract var btnLogin: Button

class LayoutPortrait : ScreenLayout() { override lateinit var imageLogo: ImageView override lateinit var editEmail: EditText override lateinit var editPassword: EditText override lateinit var btnLogin: Button override fun createView(ui: AnkoContext<ConfigChangeActivity>): View { return with(ui) { verticalLayout { padding = dip(16) imageLogo = imageView(R.drawable.castle) editEmail = editText { hint = "Email" } editPassword = editText { hint = "Password" } btnLogin = button("Login") } } } }

class LayoutLandscape : ScreenLayout() { override lateinit var imageLogo: ImageView override lateinit var editEmail: EditText override lateinit var editPassword: EditText override lateinit var btnLogin: Button override fun createView(ui: AnkoContext<ConfigChangeActivity>): View { return with(ui) { linearLayout { imageLogo = imageView(R.drawable.castle).lparams(width = 0, weight = 1f) verticalLayout { padding = dip(16) editEmail = editText { hint = "Email" } editPassword = editText { hint = "Password" } btnLogin = button("Login") }.lparams(width = 0, weight = 1f) } } }}

}

Page 130: David Bilík: Anko – modern way to build your layouts?

Configurations• Its better to apply good old OOP principles.

abstract class ScreenLayout : AnkoComponent<ConfigChangeActivity> { abstract var imageLogo: ImageView abstract var editEmail: EditText abstract var editPassword: EditText abstract var btnLogin: Button

class LayoutPortrait : ScreenLayout() { override lateinit var imageLogo: ImageView override lateinit var editEmail: EditText override lateinit var editPassword: EditText override lateinit var btnLogin: Button override fun createView(ui: AnkoContext<ConfigChangeActivity>): View { return with(ui) { verticalLayout { padding = dip(16) imageLogo = imageView(R.drawable.castle) editEmail = editText { hint = "Email" } editPassword = editText { hint = "Password" } btnLogin = button("Login") } } } }

class LayoutLandscape : ScreenLayout() { override lateinit var imageLogo: ImageView override lateinit var editEmail: EditText override lateinit var editPassword: EditText override lateinit var btnLogin: Button override fun createView(ui: AnkoContext<ConfigChangeActivity>): View { return with(ui) { linearLayout { imageLogo = imageView(R.drawable.castle).lparams(width = 0, weight = 1f) verticalLayout { padding = dip(16) editEmail = editText { hint = "Email" } editPassword = editText { hint = "Password" } btnLogin = button("Login") }.lparams(width = 0, weight = 1f) } } }}

companion object { fun createLayout(context: Context): ScreenLayout { context.configuration(orientation = Orientation.LANDSCAPE) { return LayoutLandscape() } return LayoutPortrait() }}

}

Page 131: David Bilík: Anko – modern way to build your layouts?

LayoutInflater

Page 132: David Bilík: Anko – modern way to build your layouts?

LayoutInflater

• Because Anko create views programmatically, LayoutInflater is not

in the game. What does it mean?

Page 133: David Bilík: Anko – modern way to build your layouts?

LayoutInflater

• Because Anko create views programmatically, LayoutInflater is not

in the game. What does it mean?

• Libraries like Calligraphy doesn't work, because they inject into inflation

process and replace TextViews typeface

Page 134: David Bilík: Anko – modern way to build your layouts?

LayoutInflater

• Because Anko create views programmatically, LayoutInflater is not

in the game. What does it mean?

• Libraries like Calligraphy doesn't work, because they inject into inflation

process and replace TextViews typeface

• But more importantly, AppCompat library doesn't work either

Page 135: David Bilík: Anko – modern way to build your layouts?

AppCompat

• AppCompat has its own LayoutInflater which replaces platform

Views with AppCompat equivalents. eg. if you have <Button/> definition in your layout, it actually creates AppCompatButton instance

Page 136: David Bilík: Anko – modern way to build your layouts?

AppCompat

• AppCompat has its own LayoutInflater which replaces platform

Views with AppCompat equivalents. eg. if you have <Button/> definition in your layout, it actually creates AppCompatButton instance

• Its convenient because you don't have to worry about backward

compatibility of tinting/theming and it “just works” on all version of Androids.

Page 137: David Bilík: Anko – modern way to build your layouts?

AppCompat

• AppCompat has its own LayoutInflater which replaces platform

Views with AppCompat equivalents. eg. if you have <Button/> definition in your layout, it actually creates AppCompatButton instance

• Its convenient because you don't have to worry about backward

compatibility of tinting/theming and it “just works” on all version of Androids.

• But what if we don't have LayoutInflater?

Page 138: David Bilík: Anko – modern way to build your layouts?

AppCompat

• Anko has a set of extensions with prefix tinted, eg. tintedButton

Page 139: David Bilík: Anko – modern way to build your layouts?

AppCompat

• Anko has a set of extensions with prefix tinted, eg. tintedButton

• It creates AppCompat version of view for preLollipop versions and platform version otherwise

Page 140: David Bilík: Anko – modern way to build your layouts?

AppCompat

• Anko has a set of extensions with prefix tinted, eg. tintedButton

• It creates AppCompat version of view for preLollipop versions and platform version otherwise

• If you want to use AppCompat version everytime, you have to do it the

same as with custom view

Page 141: David Bilík: Anko – modern way to build your layouts?

ConstraintLayout• ConstraintLayout is Hot stuff right now

Page 142: David Bilík: Anko – modern way to build your layouts?

ConstraintLayout• ConstraintLayout is Hot stuff right now

• Even the maintainer of Anko thinks so

Page 143: David Bilík: Anko – modern way to build your layouts?

ConstraintLayout• ConstraintLayout is Hot stuff right now

• Even the maintainer of Anko thinks so

Page 144: David Bilík: Anko – modern way to build your layouts?

ConstraintLayout• ConstraintLayout is Hot stuff right now

• Even the maintainer of Anko thinks so

• Unfortunately nothing has happened since then

Page 145: David Bilík: Anko – modern way to build your layouts?

ConstraintLayout• How does the code look without any additional support?

Page 146: David Bilík: Anko – modern way to build your layouts?

ConstraintLayout• How does the code look without any additional support?

• Lets build another simple UI example

Page 147: David Bilík: Anko – modern way to build your layouts?

ConstraintLayout• How does the code look without any additional support?

• Lets build another simple UI example

Page 148: David Bilík: Anko – modern way to build your layouts?

ConstraintLayoutcustomView<ConstraintLayout> { layoutParams = ViewGroup.LayoutParams(matchParent, matchParent)

val constraintSet = ConstraintSet() constraintSet.clone(this@customView)

constraintSet.connect(image.id, START, PARENT_ID, START, dip(16)) constraintSet.connect(image.id, TOP, PARENT_ID, TOP, dip(16))

constraintSet.connect(title.id, START, image.id, END, dip(16))

constraintSet.connect(subtitle.id, START, title.id, START)

constraintSet.createVerticalChain(image.id, TOP, image.id, BOTTOM intArrayOf(title.id, subtitle.id), null, CHAIN_SPREAD)

constraintSet.applyTo(this@customView)

val image = imageView(R.mipmap.ic_launcher) { id = 1 layoutParams = ConstraintLayout.LayoutParams(dip(68), dip(68)) }

val title = textView("Title") { id = 2 } val subtitle = textView("Subtitle") { id = 3 }

}

Page 149: David Bilík: Anko – modern way to build your layouts?

ConstraintLayoutcustomView<ConstraintLayout> { layoutParams = ViewGroup.LayoutParams(matchParent, matchParent)

val constraintSet = ConstraintSet() constraintSet.clone(this@customView)

constraintSet.connect(image.id, START, PARENT_ID, START, dip(16)) constraintSet.connect(image.id, TOP, PARENT_ID, TOP, dip(16))

constraintSet.connect(title.id, START, image.id, END, dip(16))

constraintSet.connect(subtitle.id, START, title.id, START)

constraintSet.createVerticalChain(image.id, TOP, image.id, BOTTOM intArrayOf(title.id, subtitle.id), null, CHAIN_SPREAD)

constraintSet.applyTo(this@customView)

val image = imageView(R.mipmap.ic_launcher) { id = 1 layoutParams = ConstraintLayout.LayoutParams(dip(68), dip(68)) }

val title = textView("Title") { id = 2 } val subtitle = textView("Subtitle") { id = 3 }

}

Page 150: David Bilík: Anko – modern way to build your layouts?

ConstraintLayoutcustomView<ConstraintLayout> { layoutParams = ViewGroup.LayoutParams(matchParent, matchParent)

val constraintSet = ConstraintSet() constraintSet.clone(this@customView)

constraintSet.connect(image.id, START, PARENT_ID, START, dip(16)) constraintSet.connect(image.id, TOP, PARENT_ID, TOP, dip(16))

constraintSet.connect(title.id, START, image.id, END, dip(16))

constraintSet.connect(subtitle.id, START, title.id, START)

constraintSet.createVerticalChain(image.id, TOP, image.id, BOTTOM intArrayOf(title.id, subtitle.id), null, CHAIN_SPREAD)

constraintSet.applyTo(this@customView)

val image = imageView(R.mipmap.ic_launcher) { id = 1 layoutParams = ConstraintLayout.LayoutParams(dip(68), dip(68)) }

val title = textView("Title") { id = 2 } val subtitle = textView("Subtitle") { id = 3 }

}

Page 151: David Bilík: Anko – modern way to build your layouts?

ConstraintLayout• Fortunately, our colleague David (other than me) likes ConstraintLayout

so much that he developed library that is compatible with Anko

Page 152: David Bilík: Anko – modern way to build your layouts?

ConstraintLayoutconstraintLayout { layoutParams = ViewGroup.LayoutParams(matchParent, matchParent) val image = imageView(R.mipmap.ic_launcher).lparams(dip(68), dip(68)) val title = textView("Title") val subtitle = textView("Subtitle")

}

constraints { image.connect(START to START of parentId with dip(16), TOP to TOP of parentId with dip(16)) title.connect(START to END of image with dip(16)) subtitle.connect(LEFT to LEFT of title) chain(TOP of image, BOTTOM of image) { views(title, subtitle) } }

constraints { image.connect(STARS of parentId with dip(16), TOPS of parentId with dip(16)) title.connect(START to END of image with dip(16)) subtitle.connect(LEFTS of title) chain(TOP of image, BOTTOM of image) { views(title, subtitle) } }

Page 153: David Bilík: Anko – modern way to build your layouts?

ConstraintLayoutconstraintLayout { layoutParams = ViewGroup.LayoutParams(matchParent, matchParent) val image = imageView(R.mipmap.ic_launcher).lparams(dip(68), dip(68)) val title = textView("Title") val subtitle = textView("Subtitle")

}

constraints { image.connect(START to START of parentId with dip(16), TOP to TOP of parentId with dip(16)) title.connect(START to END of image with dip(16)) subtitle.connect(LEFT to LEFT of title) chain(TOP of image, BOTTOM of image) { views(title, subtitle) } }

constraints { image.connect(STARS of parentId with dip(16), TOPS of parentId with dip(16)) title.connect(START to END of image with dip(16)) subtitle.connect(LEFTS of title) chain(TOP of image, BOTTOM of image) { views(title, subtitle) } }

Page 154: David Bilík: Anko – modern way to build your layouts?

ConstraintLayoutconstraintLayout { layoutParams = ViewGroup.LayoutParams(matchParent, matchParent) val image = imageView(R.mipmap.ic_launcher).lparams(dip(68), dip(68)) val title = textView("Title") val subtitle = textView("Subtitle")

}

constraints { image.connect(START to START of parentId with dip(16), TOP to TOP of parentId with dip(16)) title.connect(START to END of image with dip(16)) subtitle.connect(LEFT to LEFT of title) chain(TOP of image, BOTTOM of image) { views(title, subtitle) } }

constraints { image.connect(STARS of parentId with dip(16), TOPS of parentId with dip(16)) title.connect(START to END of image with dip(16)) subtitle.connect(LEFTS of title) chain(TOP of image, BOTTOM of image) { views(title, subtitle) } }

Page 155: David Bilík: Anko – modern way to build your layouts?

AnkoComponent• We don't use AnkoComponents, because they have no practical use for

us

Page 156: David Bilík: Anko – modern way to build your layouts?

AnkoComponent• We don't use AnkoComponents, because they have no practical use for

us

• We've developed our own definition called ViewLayout

Page 157: David Bilík: Anko – modern way to build your layouts?

AnkoComponent• We don't use AnkoComponents, because they have no practical use for

us

• We've developed our own definition called ViewLayout

abstract class ViewLayout(private val parent: ViewGroup) { lateinit var itemView: View val context = parent.context fun createView(): View { return createViewInternal(AnkoContext.create(parent.context, parent)) .also { itemView = it } } abstract protected fun createViewInternal(ui: AnkoContext<ViewGroup>): View}

Page 158: David Bilík: Anko – modern way to build your layouts?

ViewHolder pattern• Everybody knows ViewHolders. What's the best practice in Anko?

Page 159: David Bilík: Anko – modern way to build your layouts?

ViewHolder pattern• Everybody knows ViewHolders. What's the best practice in Anko?

class ItemLayout(parent: ViewGroup) : ViewLayout(parent) { lateinit var txtTitle: TextView lateinit var txtSubtitle: TextView override fun createViewInternal(ui: AnkoContext<ViewGroup>): View { return with(ui) { verticalLayout { txtTitle = textView {} txtSubtitle = textView {} } } } }

Page 160: David Bilík: Anko – modern way to build your layouts?

ViewHolder pattern• Everybody knows ViewHolders. What's the best practice in Anko?

class ItemLayout(parent: ViewGroup) : ViewLayout(parent) { lateinit var txtTitle: TextView lateinit var txtSubtitle: TextView override fun createViewInternal(ui: AnkoContext<ViewGroup>): View { return with(ui) { verticalLayout { txtTitle = textView {} txtSubtitle = textView {} } } } } class ItemHolder(val layout: ItemLayout) : ViewHolder (layout.createView()) { fun bind(title: String, subtitle: String) { with(layout) { txtTitle.text = title txtSubtitle.text = subtitle }}}

Page 161: David Bilík: Anko – modern way to build your layouts?

ViewHolder pattern• Everybody knows ViewHolders. What's the best practice in Anko?

class ItemLayout(parent: ViewGroup) : ViewLayout(parent) { lateinit var txtTitle: TextView lateinit var txtSubtitle: TextView override fun createViewInternal(ui: AnkoContext<ViewGroup>): View { return with(ui) { verticalLayout { txtTitle = textView {} txtSubtitle = textView {} } } } }

class ItemHolder(val layout: ItemLayout) : ViewHolder (layout.createView()) { fun bind(title: String, subtitle: String) { with(layout) { txtTitle.text = title txtSubtitle.text = subtitle }}}

class Adapter : RecyclerView.Adapter<ItemHolder>() { … override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ItemHolder(ItemLayout(parent))}

Page 162: David Bilík: Anko – modern way to build your layouts?

Finally - disadvantages

Page 163: David Bilík: Anko – modern way to build your layouts?

Missing attributes• Every polite View has setter for each attribute that can be set in XML

Page 164: David Bilík: Anko – modern way to build your layouts?

Missing attributes• Every polite View has setter for each attribute that can be set in XML

• Unfortunately, rude views exists. Even in Android or Support Library

Page 165: David Bilík: Anko – modern way to build your layouts?

Missing attributes• Every polite View has setter for each attribute that can be set in XML

• Unfortunately, rude views exists. Even in Android or Support Library

• eg. tabMaxWidth in TabLayout class.

Page 166: David Bilík: Anko – modern way to build your layouts?

Missing attributes• Every polite View has setter for each attribute that can be set in XML

• Unfortunately, rude views exists. Even in Android or Support Library

• eg. tabMaxWidth in TabLayout class.

• Solution?

Page 167: David Bilík: Anko – modern way to build your layouts?

Missing attributes• Every polite View has setter for each attribute that can be set in XML

• Unfortunately, rude views exists. Even in Android or Support Library

• eg. tabMaxWidth in TabLayout class.

• Solution?

• Use include function as described earlier and define your view in XML

Page 168: David Bilík: Anko – modern way to build your layouts?

Missing attributes• Every polite View has setter for each attribute that can be set in XML

• Unfortunately, rude views exists. Even in Android or Support Library

• eg. tabMaxWidth in TabLayout class.

• Solution?

• Use include function as described earlier and define your view in XML

• Check the source code and perform reflection to set desired attribute

Page 169: David Bilík: Anko – modern way to build your layouts?

Weird platform bugs• Sometimes you are facing very weird behavior of your layouts,

especially on older versions of Android

Page 170: David Bilík: Anko – modern way to build your layouts?

Weird platform bugs• Sometimes you are facing very weird behavior of your layouts,

especially on older versions of Android

• Example: On preKitKat versions, some views didn’t have padding even

when defined in code

Page 171: David Bilík: Anko – modern way to build your layouts?

Weird platform bugs• Sometimes you are facing very weird behavior of your layouts,

especially on older versions of Android

• Example: On preKitKat versions, some views didn’t have padding even

when defined in code

• Several hours later we've found this SO question “Where'd padding go, when setting background Drawable?"

Page 172: David Bilík: Anko – modern way to build your layouts?

Weird platform bugs• Sometimes you are facing very weird behavior of your layouts,

especially on older versions of Android

• Example: On preKitKat versions, some views didn’t have padding even

when defined in code

• Several hours later we've found this SO question “Where'd padding go, when setting background Drawable?"

• It turns out that if you set background after the padding, padding is lost

Page 173: David Bilík: Anko – modern way to build your layouts?

Weird platform bugs• Sometimes you are facing very weird behavior of your layouts,

especially on older versions of Android

• Example: On preKitKat versions, some views didn’t have padding even

when defined in code

• Several hours later we've found this SO question “Where'd padding go, when setting background Drawable?"

• It turns out that if you set background after the padding, padding is lost

• There is no such problem with XML because it sets attributes always in

the same order

Page 174: David Bilík: Anko – modern way to build your layouts?

Anko maintanence

• In the moment of writing there is 113 opened issues on Github and 18

pull request.

Page 175: David Bilík: Anko – modern way to build your layouts?

Anko maintanence

• In the moment of writing there is 113 opened issues on Github and 18

pull request.

• Contributions are very rare and since June there is no major feature/

bugfix

Page 176: David Bilík: Anko – modern way to build your layouts?

Anko maintanence

• In the moment of writing there is 113 opened issues on Github and 18

pull request.

• Contributions are very rare and since June there is no major feature/

bugfix

• Members of JB said in YouTrack that Anko is one-man project and that one man doesn't have time for that right now :(

Page 177: David Bilík: Anko – modern way to build your layouts?

Anko maintanence

• In the moment of writing there is 113 opened issues on Github and 18

pull request.

• Contributions are very rare and since June there is no major feature/

bugfix

• Members of JB said in YouTrack that Anko is one-man project and that one man doesn't have time for that right now :(

• Preview was broken since AS 1.6, fixed in 2.4 but broke once again in 3.0. But couple of days ago…

Page 178: David Bilík: Anko – modern way to build your layouts?

Anko maintanence

• Commit that fixed Preview appeared!

Page 179: David Bilík: Anko – modern way to build your layouts?

Anko maintanence

• Commit that fixed Preview appeared!

• Unfortunately no version with that fix was released …

Page 180: David Bilík: Anko – modern way to build your layouts?

Anko maintanence

• Commit that fixed Preview appeared!

• Unfortunately no version with that fix was released …

• but that did not stopped me

Page 181: David Bilík: Anko – modern way to build your layouts?

Anko maintanence

• Commit that fixed Preview appeared!

• Unfortunately no version with that fix was released …

• but that did not stopped me

• I built Anko from scratch and after apprx 1 hour later … PREVIEW IS WORKING

Page 182: David Bilík: Anko – modern way to build your layouts?

Anko preview

• To see the most recent changes in view you must always rebuild project

Page 183: David Bilík: Anko – modern way to build your layouts?

Anko preview

• To see the most recent changes in view you must always rebuild project

• Works only with AnkoComponent as a class of your layout definition

Page 184: David Bilík: Anko – modern way to build your layouts?

Anko preview

• To see the most recent changes in view you must always rebuild project

• Works only with AnkoComponent as a class of your layout definition

• Does not provide Visual Editor of your layout or its view attributes

Page 185: David Bilík: Anko – modern way to build your layouts?

Final tips• Don't forget to use ids of your views. Framework doesn’t retain View

state without them.

Page 186: David Bilík: Anko – modern way to build your layouts?

Final tips• Don't forget to use ids of your views. Framework doesn’t retain View

state without them.

• With XML you can AutoFormat your layout and reorder attributes. There

is no such luxury in Anko. Codestyle needed.

Page 187: David Bilík: Anko – modern way to build your layouts?

Final tips• Don't forget to use ids of your views. Framework doesn’t retain View

state without them.

• With XML you can AutoFormat your layout and reorder attributes. There

is no such luxury in Anko. Codestyle needed.

• Do not mix Anko with XML in one project. It really confuse newcomer to the project or your future self

Page 188: David Bilík: Anko – modern way to build your layouts?

Final tips• Don't forget to use ids of your views. Framework doesn’t retain View

state without them.

• With XML you can AutoFormat your layout and reorder attributes. There

is no such luxury in Anko. Codestyle needed.

• Do not mix Anko with XML in one project. It really confuse newcomer to the project or your future self

• Always define your layout in separate class. It allows abstraction and it strictly defines coupling between logic and UI definition

Page 190: David Bilík: Anko – modern way to build your layouts?

WWW.MDEVTALK.CZ

mdevtalk