動態配置

延續上一節靜態配置

在上一節提到靜態配置雖然較簡潔, 但若想靈活更換Fragment就得依靠 動態添加.替換Fragment。

再建一個新的Fragment

要替換當然要有兩個才看得出效果。

那就建立一個Fragment,取名叫做EditFragment。

然後將fragment_edit.xml修改成一個文字匡和一個送出按鈕

<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.savesomthingdemo.EditFragment">

    <!-- TODO: Update blank fragment layout -->

    <Button
        android:id="@+id/btnSubmitMessage"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="送出"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/textInputMessage"
        app:layout_constraintTop_toTopOf="@+id/textInputMessage" />

    <EditText
        android:id="@+id/textInputMessage"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:ems="10"
        android:hint="請輸入訊息"
        android:inputType="textPersonName"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>

效果: editFragment的xml佈局可視圖

修改activity_main.xml

要將靜態配置的xml轉成動態,改起來其實很方便。

只要將fragment 替換成 FrameLayout, 並將原本的android:name那行刪除就Ok了。

另外我添加一個SeekBar用來切換我們顯示的Fragment。

完整activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.savesomthingdemo.MainActivity">

    <FrameLayout
        android:id="@+id/demoFragment"
        android:name="com.example.savesomthingdemo.TimeFragment"
        android:layout_width="388dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toTopOf="@+id/btnShowHide"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/btnShowHide"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="隱藏"
        android:textSize="24sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent" />

    <SeekBar
        android:id="@+id/seekbarChangeFragment"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginRight="32dp"
        android:max="2"
        android:progress="0"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintStart_toEndOf="@+id/btnShowHide"
        app:layout_constraintTop_toTopOf="@+id/btnShowHide" />

</android.support.constraint.ConstraintLayout>

效果:

更改MainActivy

這時MainActivity絕對是出現一堆紅字XD 因為原本的Fragment變成了FrameLayout,所以導致一些屬性找不到。

可以用底下這行取代原本的Fragemnt,雖然長了一點。

val demoFragment = supportFragmentManager.findFragmentById(R.id.demoFragment)

完整MainActivity.kt

package com.example.savesomthingdemo

import android.os.Bundle
import android.support.v4.app.Fragment
import android.support.v7.app.AppCompatActivity
import android.util.Log
import android.widget.SeekBar
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {
    private val pageFragemnts: Array<Fragment> = arrayOf(EditFragment(), TimeFragment())

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        seekbarChangeFragment.setOnSeekBarChangeListener(object: SeekBar.OnSeekBarChangeListener {
            override fun onProgressChanged(p0: SeekBar?, position: Int, p2: Boolean) {
                Log.d("onProgressChanged", "位置:$position")
                changeFragment(position)
            }

            override fun onStartTrackingTouch(p0: SeekBar?) {}

            override fun onStopTrackingTouch(p0: SeekBar?) {}
        })

        btnShowHide.setOnClickListener {
            val demoFragment = supportFragmentManager.findFragmentById(R.id.demoFragment) ?: return@setOnClickListener

            val fragmentTransaction = supportFragmentManager.beginTransaction()

            if (demoFragment.isHidden){
                fragmentTransaction.show(demoFragment)
                btnShowHide.text = "顯示"
            }else{
                fragmentTransaction.hide(demoFragment)
                btnShowHide.text = "隱藏"
            }
            fragmentTransaction.commit()
        }
    }

    fun changeFragment(position: Int) {
        val fragmentTransaction = supportFragmentManager.beginTransaction()
        val demoFragment = supportFragmentManager.findFragmentById(R.id.demoFragment)

        when(position) {
            2 -> {
                fragmentTransaction.remove(demoFragment)
            }
            else -> {
                fragmentTransaction.replace(R.id.demoFragment, pageFragemnts[position])
            }

        }
        fragmentTransaction.commit()

    }
}

MainActivty.kt 碎碎念補充說明

由上而下講,首先pageFragments是我們存放自訂Fragment的陣列, 方便後續替換Fragment。

seekbarChangeFragment.setOnSeekBarChangeListener 就是設定我們seekbar的監聽器。 裡面必須Override三個方法, onProgressChanged() 只要seekbar的拉條一拉動就會觸發。 onStartTrackingTouch() 從手指沒按突然按下seekbar的拉條時觸發。 onStopTrackingTouch() 從手指一直按著到突然放開seekbar的拉條時觸發。

此範例只使用到onProgressChanged(), 並利用此方法的第二個參數:position(位置)來決定我要更動哪個Fragment, 而切換哪個Fragment則定義在changeFragment()這個函數中。

changeFragment(position: Int)

新出現的就是replace和remove, replace就是把第一個參數id對映的的fragmentLayout的內容物替換成第二參數的fragment。 remove則是移除你填入的fragment。

有趣的是依據我參考的文件說明,remove會破壞該Fragment的實例,而replace則是remove() + add()的綜合體。

有趣的點在於說 我的程式明明就一直重複使用那些Fragment,但在替換(replace)時應該會摧毀才對, 但我的App依舊正常運作.沒有崩潰。 =W= Why?

成果

參考資料

Android 拖动条SeekBar的简单使用

Kotlin 開發第 8 天 BottomNavigation ( Fragment + Intent)

Android 底部导航栏 (底部 Tab) 最佳实践|掘金技术征文

results matching ""

    No results matching ""