Genel

Android – Kotlin ile BottomAppBar Örneği

Merhabalar,

Bugünki dersimizde Google I/O2018 ‘de tanıtılan ve benim yeni yeni projelerimde kullandığım BottomAppBar ‘ı detaylı bir şekilde inceleyeceğiz.

BottomAppBar Tasarım olarak aşağıdaki gibidir.

Resim : //medium.com/@emre.tekin/bottomappbar-new-material-components-for-android-5040e7a608f0

Mevcuttaki toolbar ‘lar en üst ‘te konumlanmış ve kullanım açısından zorken, BottomAppBar kullanım açısından kullanıcılara daha kolay bir arayüz sunuyor. En önemli özelliği tek el kullanımı sağlamasıdır.

MaterialComponent kütüphanesini projemize dahil etmek için;

  • Build.gradle (Project) ‘i açın.
  • allproject altında google’ ın ekli olduğuna emin olun.

allprojects {
repositories {
google()
jcenter()
}
}

  • Projeyi implement ‘e edin.
implementation 'com.google.android.material:material:1.2.0-alpha02

Daha detaylı bilgiye aşağıdaki adresten erişebilirsiniz.

//material.io/develop/android/docs/getting-started/

Son Versiyonları aşağıdan öğrenebilirsiniz.

//maven.google.com/web/index.html

//mvnrepository.com/artifact/com.google.android.material/material

Unutmayın ! : BottomAppBar her zaman Coordinator Layout ‘un içerisinde olmak zorundadır. Detaylı Bilgi için;

//developer.android.com/reference/android/support/design/widget/CoordinatorLayout

Gelelim Tasarımımızı yapmaya,

Layout Dosyamız –> activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="//schemas.android.com/apk/res/android"
    xmlns:app="//schemas.android.com/apk/res-auto"
    xmlns:tools="//schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/tv_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent">

    <androidx.coordinatorlayout.widget.CoordinatorLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <com.google.android.material.bottomappbar.BottomAppBar
            android:id="@+id/bottom_app_bar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:layout_gravity="bottom"
            app:backgroundTint="@color/colorPrimary"
            style="@style/Widget.MaterialComponents.BottomAppBar"
            app:fabAlignmentMode="center"
            app:navigationIcon="@drawable/ic_menu"/>
    <com.google.android.material.floatingactionbutton.FloatingActionButton
            android:id="@+id/fab"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/ic_add_black_24dp"
            app:fabSize="normal"
            app:layout_anchor="@id/bottom_app_bar">

    </androidx.coordinatorlayout.widget.CoordinatorLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

Burada neler yaptığımızı anlatırsak. Bir tane constraintLayout içerisine text view ve coordinatorLayout ekledik. BottomAppBar Coordinator layout ile entegre ‘dir. Yukarıda daha detaylı bilgiye erişebilirsiniz. İçerisine de bir fab button attık.

Tasarımımız aşağıdaki şekilde olacaktır.

Resim : //medium.com/material-design-in-action/implementing-bottomappbar-material-components-for-android-f490c4a01708

BottomAppBar aşağıdaki özelliklere sahiptir. Sizde bu özellikleri kendi tasarımınıza uygun olacak şekilde güncelleyebilirsiniz.

Resim : //medium.com/material-design-in-action/implementing-bottomappbar-material-components-for-android-f490c4a01708

app:backgroundTint –> Arka Plan rengi için kullanılır.

app:fabAlignmentMode –> End ve Center özelliği sahiptir. Yukardaki resimde center iken herhangi bir işlemde end yapabilirsiniz. Örnek aşağıdaki resimdedir. Bu proje de de örnek olarak uygulanmıştır.

Resim : //medium.com/material-design-in-action/implementing-bottomappbar-material-components-for-android-f490c4a01708

app:fabAttached –> Fab button’un bottomappbar ile bütünleşik mi olacağı yoksa ayrı olarak mı sunulacağına ilişkin ayardır.

Resim : //medium.com/material-design-in-action/implementing-bottomappbar-material-components-for-android-f490c4a01708

app:fabCradleDiameter –> Fab button ile bottomAppBar arasındaki açıyı ayarlıyor.

Resim : //medium.com/material-design-in-action/implementing-bottomappbar-material-components-for-android-f490c4a01708

app:fabCradleRoundedCornerRadius –> Köşe eğrisinin yarıçapının buluşma noktasındaki yarıçapını ve BottomAppBar’ın yatay kısmını belirtir.

Resim : //medium.com/material-design-in-action/implementing-bottomappbar-material-components-for-android-f490c4a01708

app:fabCradleVerticalOffSet –> fab Buttonunun aşağıdaki yerini belirtir.

Gelelim MainActivity Kısmına :

package com.umiitkose.todolist.bottomappbarexample

import android.os.Build
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import android.widget.Toast
import androidx.annotation.RequiresApi
import com.google.android.material.bottomappbar.BottomAppBar
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.umiitkose.todolist.bottomappbarexample.utils.toast
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

    private var currentFabAlignmentMode = BottomAppBar.FAB_ALIGNMENT_MODE_CENTER

    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        setSupportActionBar(bottom_app_bar)

        val addVisibilityChanged: FloatingActionButton.OnVisibilityChangedListener = object : FloatingActionButton.OnVisibilityChangedListener() {
            override fun onShown(fab: FloatingActionButton?) {
                super.onShown(fab)
            }
            override fun onHidden(fab: FloatingActionButton?) {
                super.onHidden(fab)
                bottom_app_bar.toggleFabAlignment()
                bottom_app_bar.replaceMenu(
                    if(currentFabAlignmentMode == BottomAppBar.FAB_ALIGNMENT_MODE_CENTER) R.menu.bottomappbar_menu_two
                    else R.menu.bottomappbar_menu
                )
                fab?.setImageDrawable(
                    if(currentFabAlignmentMode == BottomAppBar.FAB_ALIGNMENT_MODE_CENTER) getDrawable(R.drawable.ic_save_black_24dp)
                    else getDrawable(R.drawable.ic_add_black_24dp)
                )
                fab?.show()
            }
        }

        fab.setOnClickListener {
            Toast.makeText(this,"Fab Click", Toast.LENGTH_LONG).show()
            fab.hide(addVisibilityChanged)
            invalidateOptionsMenu()
            bottom_app_bar.navigationIcon = if (bottom_app_bar.navigationIcon != null) null
            else getDrawable(R.drawable.ic_search)
            when(tv_text.text) {
                getString(R.string.primary_screen_text) -> tv_text.text = getString(R.string.secondary_sceen_text)
                getString(R.string.secondary_sceen_text) -> tv_text.text = getString(R.string.primary_screen_text)
            }
        }

    }

    private fun BottomAppBar.toggleFabAlignment() {
        currentFabAlignmentMode = fabAlignmentMode
        fabAlignmentMode = currentFabAlignmentMode.xor(1)
    }

    override fun onCreateOptionsMenu(menu: Menu?): Boolean {
     val inflater = menuInflater.inflate(R.menu.bottomappbar_menu,menu)
        return true
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        when(item!!.itemId){
            R.id.app_bar_fav ->toast("Fav Menu item ",this)
            R.id.app_bar_settings ->toast("Settings Menu item ",this)
            R.id.app_bar_search ->toast("Search Menu item ",this)
            android.R.id.home -> {
                val bottomNavDrawerFragment = BottomNavigationDrawerFragment()
                bottomNavDrawerFragment.show(supportFragmentManager, bottomNavDrawerFragment.tag)
            }
        }
        return true
    }

}

menu kısmı için –> bottomappbar

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:tools="//schemas.android.com/tools"
    xmlns:app="//schemas.android.com/apk/res-auto"
    xmlns:android="//schemas.android.com/apk/res/android">

    <item
        android:id="@+id/app_bar_fav"
        android:icon="@drawable/ic_favorite_border_black_24dp"
        android:title="Favori"
        app:showAsAction="ifRoom"/>

    <item
        android:id="@+id/app_bar_search"
        android:icon="@drawable/ic_search"
        android:title="Search"
        app:showAsAction="ifRoom"/>
    <item
        android:id="@+id/app_bar_settings"
        android:title="Settings"
        app:showAsAction="never"/>
</menu>

CoordinatorLayout ‘un bir child elemanı olan BottomSheet ‘i ekleyeceğiz. Detaylı Bilgi için;

//material.io/develop/android/components/bottom-sheet-behavior/

O zaman hadi başlayalım tasarıma :

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="//schemas.android.com/apk/res/android"
    xmlns:app="//schemas.android.com/apk/res-auto"
    xmlns:tools="//schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/tv_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent">

    <androidx.coordinatorlayout.widget.CoordinatorLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <com.google.android.material.bottomappbar.BottomAppBar
            android:id="@+id/bottom_app_bar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:layout_gravity="bottom"
            app:backgroundTint="@color/colorPrimary"
            style="@style/Widget.MaterialComponents.BottomAppBar"
            app:fabAlignmentMode="center"
            app:navigationIcon="@drawable/ic_menu"/>


        <com.google.android.material.floatingactionbutton.FloatingActionButton
            android:id="@+id/fab"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/ic_add_black_24dp"
            app:fabSize="normal"
            app:layout_anchor="@id/bottom_app_bar">

    </androidx.coordinatorlayout.widget.CoordinatorLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

Menü Kısmı :

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="//schemas.android.com/apk/res/android"
    xmlns:app="//schemas.android.com/apk/res-auto">
    <group android:checkableBehavior="none">
        <item
            android:id="@+id/nav1"
            android:icon="@drawable/ic_search"
            android:title="@string/nav_item1">
        <item
            android:id="@+id/nav2"
            android:icon="@drawable/ic_search"
            android:title="@string/nav_item2">
        <item
            android:id="@+id/nav3"
            android:icon="@drawable/ic_search"
            android:title="@string/nav_item3">
        <item
            android:id="@+id/nav4"
            android:icon="@drawable/ic_search"
            android:title="@string/nav_item1">
        <item
            android:id="@+id/nav5"
            android:icon="@drawable/ic_search"
            android:title="@string/nav_item1">
        <item
            android:id="@+id/nav6"
            android:icon="@drawable/ic_search"
            android:title="@string/nav_item1">
        <item
            android:id="@+id/nav7"
            android:icon="@drawable/ic_search"
            android:title="@string/nav_item1">
        <item
            android:id="@+id/nav8"
            android:icon="@drawable/ic_search"
            android:title="@string/nav_item1">
        <item
            android:id="@+id/nav9"
            android:icon="@drawable/ic_search"
            android:title="@string/nav_item1">
        <item
            android:id="@+id/nav10"
            android:icon="@drawable/ic_search"
            android:title="@string/nav_item1">
        <item
            android:id="@+id/nav11"
            android:icon="@drawable/ic_search"
            android:title="@string/nav_item1">
        <item
            android:id="@+id/nav12"
            android:icon="@drawable/ic_search"
            android:title="@string/nav_item1">
        <item
            android:id="@+id/nav13"
            android:icon="@drawable/ic_search"
            android:title="@string/nav_item1">
        <item
            android:id="@+id/nav14"
            android:icon="@drawable/ic_search"
            android:title="@string/nav_item1">

    </group>
</menu>

ve son olarak Bottom Navigation Drawer ‘ı görüntülemek için Fragment yazmaya..


    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_bottomsheet, container, false)
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)

        navigation_view.setNavigationItemSelectedListener { menuItem ->
            // Bottom Navigation Drawer menu item clicks
            when (menuItem.itemId) {
              R.id.nav1 -> toast(getString(R.string.nav_item1),requireContext())

            }
            // Add code here to update the UI based on the item selected
            // For example, swap UI fragments here
            true
        }

        close_imageview.setOnClickListener {
            this.dismiss()
        }

        disableNavigationViewScrollbars(navigation_view)

    }

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        val dialog = super.onCreateDialog(savedInstanceState) as BottomSheetDialog

        dialog.setOnShowListener { dialog ->
            val d = dialog as BottomSheetDialog

            val bottomSheet = d.findViewById<View>(R.id.design_bottom_sheet) as FrameLayout?
            val bottomSheetBehavior = BottomSheetBehavior.from(bottomSheet!!)
            bottomSheetBehavior.setBottomSheetCallback(object :
                BottomSheetBehavior.BottomSheetCallback() {
                override fun onSlide(bottomSheet: View, slideOffset: Float) {
                    if (slideOffset > 0.5) {
                        close_imageview.visibility = View.VISIBLE
                    } else {
                        close_imageview.visibility = View.GONE
                    }
                }

                override fun onStateChanged(bottomSheet: View, newState: Int) {
                    when (newState) {
                        BottomSheetBehavior.STATE_HIDDEN -> dismiss()
//                        else -> close_imageview.visibility = View.GONE
                    }
                }
            })
        }

        return dialog
    }

    private fun disableNavigationViewScrollbars(navigationView: NavigationView?) {
        val navigationMenuView = navigationView?.getChildAt(0) as NavigationMenuView
        navigationMenuView.isVerticalScrollBarEnabled = false
    }

}

Uygulama Resimleri :

Projeyle ilgili tüm kodlara aşağıdaki adresten ulaşabilirsiniz.

//github.com/umiitkose/BottomAppBar

Okuduğunuz için teşekkür ederim, İyi Çalışmalar Herkese..

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir