iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 8
1

Bottom Navigation
準備實現 iOS 上 UITabBarController + UINavigationController 的功能,這中搭配經常出現在各種類型的 App 上。

  • 三個 Tab 可以切換到不同的 Activity
  • HomeActivity 提供一個按鈕可以跳轉到 Home2Activity
  • Home2Activity 提供一個按鈕可以跳轉到 Home3Activity
  • Home3Activity 提供一個按鈕可以跳回 MainActivity
  • Toolbar 上有返回鍵,提供 Home3 -> Home2 -> Main 的返回功能。

Menu

在 res 資料夾下建立一個 menu  資料夾,然後在裡面放一個 navigation.xml,定義幾個可以點選的 Item。

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

    <item
        android:id="@+id/navigation_home"
        android:icon="@drawable/ic_home_black_24dp"
        android:title="@string/title_home" />

    <item
        android:id="@+id/navigation_dashboard"
        android:icon="@drawable/ic_dashboard_black_24dp"
        android:title="@string/title_dashboard" />

    <item
        android:id="@+id/navigation_notifications"
        android:icon="@drawable/ic_notifications_black_24dp"
        android:title="@string/title_notifications" />

</menu>

實現 navigation 的點擊監控

    private val onNavigationItemSelectedListener = BottomNavigationView.OnNavigationItemSelectedListener { item ->

        when (item.itemId) {
            R.id.navigation_home -> {
                changeFragmentTo(FragmentType.home)
                return@OnNavigationItemSelectedListener true
            }

            R.id.navigation_dashboard -> {
                title = "Dashboard"
                changeFragmentTo(FragmentType.dashboard)
                return@OnNavigationItemSelectedListener true
            }

            R.id.navigation_notifications -> {
                title = "Notification"
                changeFragmentTo(FragmentType.notification)
                return@OnNavigationItemSelectedListener true
            }
        }

        false
    }

Fragment

通過 supportFragmentManager 來管理 Fragment

val manager = supportFragmentManager

要切換 Fragment 需要幾個步驟(來自官方文件  in Java)

// Create new fragment and transaction
Fragment newFragment = new ExampleFragment();
FragmentTransaction transaction = getFragmentManager().beginTransaction();

// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);

// Commit the transaction
transaction.commit();

Kotlin 的例子

    private fun changeFragmentTo(type: FragmentType) {
        val transaction = manager.beginTransaction()
        when(type) {
            FragmentType.home -> {
                title = "Home"
                val homeFragment = HomeFragment()
                transaction.replace(R.id.baseFragment, homeFragment)
            }

            FragmentType.dashboard -> {
                val dashboardFragment = DashboardFragment()
                transaction.replace(R.id.baseFragment, dashboardFragment)
            }

            FragmentType.notification -> {
                val notificationFragment = NotificationDashboard()
                transaction.replace(R.id.baseFragment, notificationFragment)
            }

        }
        transaction.addToBackStack(null)
        transaction.commit()
    }

activity_main.xml

我們在 main 的 layout 中引入 BottomNavigationView

    <android.support.design.widget.BottomNavigationView
        android:id="@+id/navigation"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginEnd="0dp"
        android:layout_marginStart="0dp"
        android:background="?android:attr/windowBackground"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:menu="@menu/navigation" />

其中我們通過下面的方法引入剛才定義好的 menu(我們在 menu 下,有建立一個 navigation 的文件,並且定義好了幾個 item)

app:menu+@menu/navigaion"

幾個需要注意的地方

  • 默認高度是 54dp
  • icon 選中的顏色默認是 @color/colorPrimary
  • 文字默認顏色也是 @color/colorPrimary
  • 背景顏色默認是當前的樣式

顏色的部分可以直接在 <android.support.design.widget.BottomNavigationView /> 下修改

  • app:itemBackground="@android:color/red"
  • app:itemIconTint="@android:color/yellow"
  • app:itemTextColor="@android:color/green"

Navigation 返回鍵

通過在 Activity 中加入

supportActionBar?.setDisplayHomeAsUpEnabled(true)

然後通過 override 方法來接收點擊情況

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        when (item.getItemId()) {
        // Respond to the action bar's Up/Home button
            android.R.id.home -> {
                onBackPressed()
                return true
            }
        }
        return super.onOptionsItemSelected(item)
    }

回到最初的 Activity

這裡和 iOS 的 UINavigationController 不太一樣。
通過給 Intent 加 Flag 的方式可以清除其他 Activity 跳到下一個 Activity 上。

        val intentHomeActivity = Intent(this, MainActivity::class.java)
        intentHomeActivity.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or IntentCompat.FLAG_ACTIVITY_CLEAR_TASK)
        startActivity(intentHomeActivity)

Build.gradle

iOS 通過 CocoaPods 等工具進行依賴包管理而 Android 是通過 Gradle 而 Android 世界裡看起來連官方提供的一些 UI 控件 都會通過 Gradle 加載。

如果不是通過 IDE 來建立 BottomNavigationView,需要手動在 Build.gradle 中的 dependencies 增加依賴

<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:viewportHeight="24.0"
    android:viewportWidth="24.0">
    <path
        android:fillColor="#FF000000"
        android:pathData="M3,13h8L11,3L3,3v10zM3,21h8v-6L3,15v6zM13,21h8L21,11h-8v10zM13,3v6h8L21,3h-8z" />
</vector>

筆記

  • 問題:為什麼一定要在 res 下建立 menu 資料夾,而不能取其他名字,感覺是 Android 規定好的名稱?
  • TODO:TabLayout + Fragment / FragmentTabHost + Fragment / RadioGroup + RadioButton + Fragment / CustomTabView + Fragment
  • 問題:當我的 Activity 取名為 HomeDetailActivity 而 Layout 為 Activity_home_deail.xml 的時候,發現版面不見了...

https://ithelp.ithome.com.tw/upload/images/20171211/2010732901tIiANfYE.png

參考


上一篇
Kotlin 開發第 7 天 MyLocation (GoogleMap)
下一篇
Kotlin 開發第 9 天 ImageSlider (ViewPager)
系列文
Kotlin 30 天,通過每天一個小 demo 學習 Android 開發30

1 則留言

1
oliver
iT邦新手 5 級 ‧ 2017-12-11 09:05:51

好文推薦

我要留言

立即登入留言