# 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| |--|--|--|--| |![](https://image.ibb.co/k5W3tL/Screenshot-Anko-Material-Sample-20181106-024651.png)|![](https://image.ibb.co/jmtKHf/Screenshot-Anko-Material-Sample-20181106-024736.png)|![](https://image.ibb.co/fdqzHf/image.png)|![](https://image.ibb.co/ijFAOL/Screenshot-Anko-Material-Sample-20181106-024832.png)| ## 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.
![](https://image.ibb.co/bOfsV0/image.png) ### 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| |--|--| | ![](https://image.ibb.co/gGA1q0/20181102-214433.gif) | ![](https://image.ibb.co/j13eA0/20181102-214453.gif) | [Link code ripple](https://github.com/kucingapes/AnkoMaterialSample/blob/master/app/src/main/java/com/kucingapes/ankomaterialsample/MaterialUtils.kt#L52) ## 4.
StatusBar dan Toolbar |![](https://image.ibb.co/dsCToL/image.png)|![](https://image.ibb.co/bGsuTL/image.png)|![](https://image.ibb.co/eAQba0/image.png)| |--|--|--| |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 ![](https://image.ibb.co/iNSi50/image.png) [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. |![](https://image.ibb.co/f6w2yL/gifeditor-20181103-161700.gif)| |--| |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| |--|--| |![](https://image.ibb.co/k4Vg8L/image.png)|![](https://image.ibb.co/ddbJNf/image.png)| ## 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 ``` |![](https://image.ibb.co/chiJ50/image.png)| |--| |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 ... } ``` |![](https://image.ibb.co/jxWXXf/image.png)| |--| |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``` |![](https://image.ibb.co/hkJMsf/image.png)| |--| |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.
|![source: material.io](https://image.ibb.co/kDKqL0/image.png)| |--| |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