# AnkoMaterialSample
**Repository Path**: zhouyu260/AnkoMaterialSample
## Basic Information
- **Project Name**: AnkoMaterialSample
- **Description**: Implementation New Material Design on Anko Layout
- **Primary Language**: Kotlin
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2019-07-09
- **Last Updated**: 2020-12-19
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# Anko New Material Design Sample
Kita akan mencoba mengadaptasi Material Design versi baru (https://material.io) pada Anko Layout
## Preview
|Drawer Material|Typography|SnackBar Material|Bottom AppBar|
|--|--|--|--|
|||||
## APK Preview
[Download apk (4mb)](https://github.com/kucingapes/AnkoMaterialSample/blob/master/app-debug-anko-material-sample.apk?raw=true)
## Index
- [BaseView](#baseview)
- [Tipografi](#typo)
- [Ripple](#ripple)
- [Statusbar dan toolbar](#toolbar)
- [ProgressBar on toolbar](#progress)
- [CardView](#card)
- [Bottom AppBar](#bottom_appbar)
- [Material Snackbar](#snackbar)
- [Material Drawer](#drawer)
## 1. BaseView
Baseview membuat pada tiap-tiap view konsisten, kita hanya membuat satu master view untuk digunakan pada tiap-tiap view.
Misalnye kita buat object ```BaseUi``` yang isinya fungsi ```baseText()``` untuk master textview dengan menerapkan typeface.
```kotlin
object BaseUi {
...
fun ViewManager.baseText() = textView {
typeface = Typeface.SANS_SERIF
}
...
}
```
dan untuk menggunakannya
```kotlin
import com.contoh.package.BaseUi.baseText
baseText().apply {
text = "contoh text dengan typeface sans serif"
}
```
## 2. Typografi
Material design mempunyai ciri tipografi yang jelas dan efisien yang mencangkup typeface, font dan letterspacing.
Typeface yang digunakan biasanya 'sans-serif' dengan font light sampe medium (jarang yg bold) dan letterspace yang ideal.
Dalam hal ini kita tidak perlu lagi menambahkan third-font, karena secara default typeface sudah tersedia sans-serif.

### Penerapan
Cukup seting typeface dan letterspacing pada ```baseText()``` tadi
```kotlin
typeface = Typeface.SANS_SERIF
letterSpacing = 0.03f
```
Kita juga dapat membuat fungsi untuk material tipografi tersebut dalam class ```Utils```
```kotlin
fun materialFont(view: TextView) {
view.apply {
typeface = Typeface.SANS_SERIF
letterSpacing = 0.03f
}
}
```
Nah sekarang fungsi ```materialFont``` sudah bisa di pake untuk tiap textView dan Button
```kotlin
textView("textnya") {
Utils.materialFont(this)
}
```
[Link code material text](https://github.com/kucingapes/AnkoMaterialSample/blob/master/app/src/main/java/com/kucingapes/ankomaterialsample/MaterialUtils.kt#L42)
## 3. Ripple
Jika kita menggunakan xml, untuk mengaktifkan animasi ripple cukup dengan menambahkan ```?android:attr/selectableItemBackground``` pada foreground atau background view.
Lalu untuk penggunaan pada Anko, kodenya sebagai berikut
```kotlin
val rippleValue = TypedValue()
context.theme.resolveAttribute(android.R.attr.selectableItemBackground, rippleValue, true)
foreground = ContextCompat.getDrawable(context, rippleValue.resourceId)
// atau di background
// background = ContextCompat.getDrawable(context, rippleValue.resourceId)
```
Kita dapat membuat fungsi tersebut di dalam class ```Utils``` kemudian dipanggil pada view di anko sehingga bisa dipakai berulang
```kotlin
fun ripple(view: View, type: Int) {
view.apply {
val rippleValue = TypedValue()
context.theme.resolveAttribute(android.R.attr.selectableItemBackground, rippleValue, true)
when (type) {
0 -> foreground = ContextCompat.getDrawable(context, rippleValue.resourceId)
1 -> background = ContextCompat.getDrawable(context, rippleValue.resourceId)
}
}
}
```
Fungsinya dapat dipanggil seperti ini
```kotlin
cardView {
Utils.ripple(this, 0) // 0 untuk foreground dan 1 untuk foreground
}
```
| not ripple |ripple|
|--|--|
|  |  |
[Link code ripple](https://github.com/kucingapes/AnkoMaterialSample/blob/master/app/src/main/java/com/kucingapes/ankomaterialsample/MaterialUtils.kt#L52)
## 4. StatusBar dan Toolbar
||||
|--|--|--|
|Chrome|Play Games|Keep|
Pada banyak aplikasi google yang menerapkan Material Design 2, status bar dan toolbar memiliki warna yang sama. Caranya adalah dengan menyamakan ```colorPrimary``` dengan ```colorPrimaryDark```. Kemudian pada kita juga akan mengapikasikan tipografi pada title toolbar, caranya dengan custom toolbar yg pake theme ```themedToolbar```.
Kita buat sebuah baseView ```baseToolbar```
```kotlin
fun ViewManager.baseToolbar() = themedToolbar(R.style.ThemeOverlay_AppCompat_Dark) {
id = R.id.toolbar
title = resources.getString(R.string.app_name)
val viewTitle = this.getChildAt(0) as TextView
materialFont(viewTitle)
}
```
Pada custom toolbar tersebut, kita memanggil textView untuk diaplikasikan fungsi tipografi

[Link code toolbar](https://github.com/kucingapes/AnkoMaterialSample/blob/0ae2d43d4d84ddc42e8b5405baceac05d127b3a3/app/src/main/java/com/kucingapes/ankomaterialsample/BaseUi.kt#L46)
[Link code fake status bar](https://github.com/kucingapes/AnkoMaterialSample/blob/0ae2d43d4d84ddc42e8b5405baceac05d127b3a3/app/src/main/java/com/kucingapes/ankomaterialsample/BaseUi.kt#L72)
[Link code disable statusbar](https://github.com/kucingapes/AnkoMaterialSample/blob/0ae2d43d4d84ddc42e8b5405baceac05d127b3a3/app/src/main/java/com/kucingapes/ankomaterialsample/BaseActivity.kt#L20)
## 5. ProgressBar in Toolbar
ProgressDialog sudah deprecated di level api 26 karena kata google itu menutup interaksi user dengan aplikasi. Maka solusi nya adalah menggunakan progressbar yang diletakan secara baik, salah satunya di Toolbar. Caranya tambahkan progressbar ke dalam toolbar.
```kotlin
horizontalProgressBar {
bottomPadding = dip(-7)
topPadding = dip(-7)
isIndeterminate = true
visibility = View.VISIBLE
backgroundColorResource = android.R.color.white
}.lparams(matchParent, wrapContent)
```
Visible dapat di setel jika progress on, jika sudah off, bisa disetel ```View.GONE```, ```bottomPadding``` dan ```topPadding``` menghilangkan background putih di atas dan dibawahnya. Background putih disarankan agar membedakan dengan background toolbar dan progress primary.
||
|--|
|progressbar in toolbar|
[link code progressbar](https://github.com/kucingapes/AnkoMaterialSample/blob/0ae2d43d4d84ddc42e8b5405baceac05d127b3a3/app/src/main/java/com/kucingapes/ankomaterialsample/BaseUi.kt#L61)
## 6. CardView
Tidak banyak perbedaan cardview pada Material Design 2, cuman pada roundcorner nya yang lebih bulet.
```kotlin
cardView {
radius = 10f
}
```
|sebelum|sesudah|
|--|--|
|||
## 7. Bottom AppBar
Salah satu komponen yang ditambahkan pada material design adalah BottomAppBar, komponen ini berbeda dengan bottom navigation. Kalo di android material (AndroidX) kita gak usah bikin custom view lagi, nah untuk Anko kita harus bikin custom view dengan komposisi
```
cordinator layout
----- vertical layout
---------- view shadow top
---------- toolbar v7
----- fab anchor ke vertical layout di atas
```
Maka kodenya kurang lebih kaya begini
```kotlin
coordinatorLayout{
// parent layout
...
verticalLayout {
id = bottom_app_bar
view {
background = ContextCompat.getDrawable(context, R.drawable.shadow)
}
toolbar {
id = bottom_toolbar
backgroundColorResource = R.color.colorPrimary
}
}.lparams { gravity = Gravity.Bottom }
floatingActionButton {
setImageResource(R.drawable.ic_plus)
}.lparams {
anchorId = bottom_app_bar
anchorGravity = Gravity.CENTER_HORIZONTAL
margin = dip(8)
}
}
```
Untuk view shadow codenya
```xml
```
||
|--|
|Custom bottom appbar|
### Menambahkan menu dan navigasi
Pada toolbar yang ada di atas (id bottom_toolbar) bisa kita pasang navigasi icon dan menu, caranya sama kaya toolbar biasa
```kotlin
...
override fun onCreate(...) {
...
val bottomToolbar = find(bottom_toolbar)
bottomToolbar.navigationIconResource = R.drawable.ic_menu // setup navigasi
bottomToolbar.inflateMenu(R.menu.bottom_menu) // setup menu
...
}
```
||
|--|
|custom bottom appbar with menu and navigation|
Kita juga bisa mengganti floatingActionButton dengan CardView seperti aplikasi [Google Tasks](https://play.google.com/store/apps/details?id=com.google.android.apps.tasks&hl=en). Seting cardview dengan ```radius = 50f```
||
|--|
|custom bottom appbar with cardview|
[Link code bottom appbar](https://github.com/kucingapes/AnkoMaterialSample/blob/master/app/src/main/java/com/kucingapes/ankomaterialsample/BottomAppBarActivity.kt#L110)
## 8. Snackbar
Perubahan tampilan untuk snackbar pada Material Design 2 cukup terlihat, snackbar jadi bergaya card.
||
|--|
|material snackbar|
Nah kita akan mencoba merubah snackbar biasa menjadi lebih material. Untuk itu kita perlu menambahkan view snackbar ke view custom yang kita buat dan mendisable child view asli seperti textView dan button, Kemudian membuat fungsi untuk textview dan button pada view custom.
Pertama buat class ```SnackbarUi``` untuk layout snackbar
```kotlin
class SnackBarUi(private val marginBottom: Int) : AnkoComponent {
override fun createView(ui: AnkoContext): View = with(ui) {
relativeLayout {
id = R.id.snackbar_layout
lparams(matchParent, wrapContent)
cardView {
radius = 7f
linearLayout {
gravity = Gravity.CENTER_VERTICAL
backgroundColor = Color.parseColor("#323232")
textView {
id = R.id.snackbar_text
textColorResource = android.R.color.white
BaseUi.materialFont(this)
}.lparams(matchParent, wrapContent) {
weight = 3f
leftMargin = dip(16)
rightMargin = dip(16)
}
styledButton(R.style.Widget_AppCompat_Button_Borderless) {
id = R.id.snackbar_action
textColorResource = R.color.colorAccent
}.lparams(wrapContent, wrapContent)
}.lparams(matchParent, wrapContent)
}.lparams(matchParent, wrapContent) {
leftMargin = dip(12)
rightMargin = dip(12)
topMargin = dip(12)
bottomMargin = dip(marginBottom)
}
}
}
inline fun ViewManager.styledButton(styleRes: Int = 0, init: Button.() -> Unit): Button = ankoView({
if (styleRes == 0) Button(it)
else Button(ContextThemeWrapper(it, styleRes), null, 0)
}, 0, init)
}
```
Class ```SnackBarUi``` membawa kontruktor ```marginBottom``` agar margin bottom dari card sifatnya dinamis. Hal ini berguna karena pengaturan dalam Snackbar yang baru **tidak mengizinkan mengoverlap actionview** dibawah layar seperti appbar bottom atau bottom navigasi, jadi perlu ketiggian yang dinamis.
Setelah itu kita buat class ```MaterialSnackbar```
```kotlin
class MaterialSnackbar private constructor(context: Context) {
private var background: Int = 0
var contentView: View? = null
private set
private var duration: LENGTH? = null
private var swipe: Boolean = false
private var bottomMargin: Int = 12
private var snackbar: Snackbar? = null
private var ctx = context
val isShowing: Boolean
get() = snackbar != null && snackbar!!.isShown
init {
this.duration = LENGTH.LONG
this.background = -1
this.swipe = true
}
fun duration(duration: LENGTH): MaterialSnackbar {
this.duration = duration
return this
}
fun swipe(swipe: Boolean): MaterialSnackbar {
this.swipe = swipe
return this
}
fun bottomMargin(bottomMargin: Int) : MaterialSnackbar {
this.bottomMargin = bottomMargin
return this
}
fun build(view: View): MaterialSnackbar {
when (duration) {
MaterialSnackbar.LENGTH.INDEFINITE -> snackbar = Snackbar.make(view, "", Snackbar.LENGTH_INDEFINITE)
MaterialSnackbar.LENGTH.SHORT -> snackbar = Snackbar.make(view, "", Snackbar.LENGTH_SHORT)
MaterialSnackbar.LENGTH.LONG -> snackbar = Snackbar.make(view, "", Snackbar.LENGTH_LONG)
}
val snackbarView = snackbar?.view as Snackbar.SnackbarLayout
if (!swipe) {
snackbarView.viewTreeObserver.addOnPreDrawListener(object : ViewTreeObserver.OnPreDrawListener {
override fun onPreDraw(): Boolean {
snackbarView.viewTreeObserver.removeOnPreDrawListener(this)
(snackbarView.layoutParams as CoordinatorLayout.LayoutParams).behavior = null
return true
}
})
}
snackbarView.setPadding(0, 0, 0, 0)
snackbarView.setBackgroundResource(android.R.color.transparent)
val text = snackbarView.findViewById(android.support.design.R.id.snackbar_text) as TextView
text.visibility = View.INVISIBLE
val action = snackbarView.findViewById(android.support.design.R.id.snackbar_action) as TextView
action.visibility = View.INVISIBLE
contentView = SnackBarUi(bottomMargin).createView(AnkoContext.create(ctx, snackbarView))
snackbarView.addView(contentView, 0)
return this
}
fun setText(text: CharSequence): MaterialSnackbar {
val textView = contentView?.find(R.id.snackbar_text)
textView?.text = text
return this
}
fun setAction(text: CharSequence, listener: View.OnClickListener): MaterialSnackbar {
val actionView = contentView?.find