Fragment 中文翻譯是「片段」,是 android 的一大特色之一,它的存在使得 android 有更靈活的空間。比如說:當手機轉向的時候,改變佈局位置。
在這篇文章中,我簡單做一個 Fragment 換頁的範例
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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=".FrgActivity">
<TextView
android:id="@+id/textFragment"
android:text="Hello world!"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:textSize="30sp"/>
<fragment
android:id="@+id/frgFragment"
android:name="com.example.simplewidgetshowcase.FragmentA"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textFragment" />
</androidx.constraintlayout.widget.ConstraintLayout>
利用 fragment 中 name 的屬性,讓他在靜態載入 xml 時就知道他要裝哪一個 fragment。
底下是 fragment 的 layout
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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"
android:background="@android:color/holo_green_light">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="A"
android:textSize="100sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
因為有用 name 的關係,所以直接執行的話,就可以有畫面了
可以看到 上面的「Hello world!」 text view 是在 activity 上的,所以它同時顯示了 activity 跟 fragment 的佈局。
除了直接加入以外,還需要以動態的方式改變 fragment。在這裡使用很常看到的 tab 方式,點選 tab item 已切換 fragment。
fragment 的除了名字其它地方都沒有改變
<androidx.constraintlayout.widget.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"
android:background="@android:color/holo_green_light">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="A"
android:textSize="100sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
activity 的地方則是增加了 tab layout 和被它包住的兩個 tab item
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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=".FrgActivity">
<com.google.android.material.tabs.TabLayout
android:id="@+id/tablayoutFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" >
<com.google.android.material.tabs.TabItem
android:id="@+id/tabA"
android:text="A"
android:layout_width="wrap_content"
android:layout_height="match_parent"/>
<com.google.android.material.tabs.TabItem
android:id="@+id/tabB"
android:text="B"
android:layout_width="wrap_content"
android:layout_height="match_parent"/>
</com.google.android.material.tabs.TabLayout>
<fragment
android:id="@+id/frgFragment"
android:name="com.example.simplewidgetshowcase.MyFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tablayoutFragment" />
</androidx.constraintlayout.widget.ConstraintLayout>
建立一個 fragment
在 fragment 裡面用 constructor 得知要放入什麼內容
class MyFragment(): Fragment(){
private var content: String?= null
constructor(content: String) : this() {
this.content= content
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val root = inflater.inflate(R.layout.fragment_my, container, false)
val textView: TextView= root.findViewById(R.id.textView)
textView.text= content
return root
}
}
跟 activity 一樣,fragment 也有屬於 fragment 的生命週期。如果是想要像 activity 一樣操控元件的地方,可以在 onCreateView 方法裡面。
不一樣的是,要多加一條 inflater.inflate(R.layout.fragment_my, container, false)
拿到 root,
用 object 做 onTabSelectedListener
裡面的 0 跟 1 代表位置,從零開始
而在 activity 中,簡單寫一個切換 fragment 的方法,
要換的時候再呼叫它就好了。
class FrgActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_fragment)
val fragmentA= MyFragment("A")
val fragmentB= MyFragment("B")
changeFragment(fragmentA)
val tabLayout: TabLayout= findViewById(R.id.tablayoutFragment)
tabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
override fun onTabSelected(tab: TabLayout.Tab?) {
when(tab?.position){
0 -> changeFragment(fragmentA)
1 -> changeFragment(fragmentB)
}
}
override fun onTabUnselected(tab: TabLayout.Tab?) {}
override fun onTabReselected(tab: TabLayout.Tab?) {}
})
}
fun changeFragment(frg: Fragment){
val transaction: FragmentTransaction = supportFragmentManager.beginTransaction()
transaction.replace(R.id.frgFragment, frg)
transaction.commit()
}
}
做完以後就像這樣
可以透過點擊上面的 tab 來切換畫面