比較 Kotlin & Flutter 返回上個頁面時,如何改成返回上上頁
討論 Kotlin 原本返回上個頁面的功能,如何改成返回上上頁
頁面流程與 Flutter 相同,Flutter 的部份參考上一篇說明
簡要架構:
示意圖
Activity
和 3 個 Fragment
navigation
)Activity
和 3個 Fragment
的 layout xml 檔案 。Activity
和 3個 Fragment
檔案。nav_graph.xml
。以下為 activity_main.xml
檔案內容:
MainActivity
layout :加入 FragmentContainerView
控制 Fragment
,並加入導覽功能(app:navGraph="@navigation/nav_graph"
)<?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:id="@+id/mainConstraintlayout"
tools:context=".MainActivity">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_graph" />
<Button
android:id="@+id/mainBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:backgroundTint="@color/lightGreen"
android:text="Go to Second Page"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_graph"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
以下為 fragment_first.xml
檔案內容:第三頁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:id="@+id/frameLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background = "@color/yellow"
tools:context=".fragment.FirstFragment">
<TextView
android:id="@+id/firstPageTV"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/first_fragment"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/firstPageBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:text = "@string/first_fragment_btn"
android:textColor = "@color/white"
android:backgroundTint="@color/lightGreen"
app:layout_constraintTop_toBottomOf="@+id/firstPageTV" />
</androidx.constraintlayout.widget.ConstraintLayout>
以下為 fragment_second.xml
檔案內容:第二頁layout(頂端bar + 櫻花圖片 + 進入第三頁的按鈕 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"
tools:context=".SecondActivity">
<include layout="@layout/app_bar"
android:id="@+id/appbar"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/appbar"
android:src="@drawable/sakura"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
以下為 fragment_third.xml
檔案內容:第三頁layout(頂端bar + 中間放星星圖片)
<?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:id="@+id/frameLayout3"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".fragment.ThirdFragment">
<include
android:id="@+id/appbar"
layout="@layout/app_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/starImage"
android:layout_width="200dp"
android:layout_height="200dp"
android:background="@drawable/star_selected"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/appbar" />
<TextView
android:id="@+id/thirdPageTV"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Back to First Page"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/appbar" />
</androidx.constraintlayout.widget.ConstraintLayout>
以下為 app_bar.xml
檔案內容:第二頁和第三頁頂端 bar 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"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/white"
android:elevation="6dp"
>
<ImageView
android:id="@+id/backBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:src="@drawable/arrow_back"
/>
<TextView
android:id="@+id/barTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="20dp"
android:textSize = "30sp"
app:layout_constraintStart_toEndOf="@id/backBtn"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
以下為 values/strings.xml
檔案內容:
<resources>
<string name="app_name">kotlin_demo</string>
<string name="first_fragment">Hi~ This is First fragment</string>
<string name="first_fragment_btn">GO TO SECOND PAGE</string>
<string name="second_fragment">Second Fragment</string>
<string name="second_fragment_btn">Go to Third Page</string>
<string name="third_fragment">Third Fragment</string>
</resources>
以下為 MainActivity.kt
檔案內容:控制 Fragment
package com.example.kotlin_demo
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import androidx.core.view.isVisible
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val mainBtn:Button = findViewById<Button>(R.id.mainBtn)
mainBtn.isVisible = false
}
}
以下為 FirstFragment.kt
檔案內容:主要為第一頁頁面相關功能
findNavController().navigate(R.id.from_firstFragment_into_secondFragment)
切換到第二頁。package com.example.kotlin_demo.fragment
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import androidx.navigation.fragment.findNavController
import com.example.kotlin_demo.R
class FirstFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_first, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val btn = view.findViewById<Button>(R.id.firstPageBtn)
btn.setOnClickListener(object:View.OnClickListener{
override fun onClick(p0: View?) {
findNavController().navigate(R.id.from_firstFragment_into_secondFragment)
}
})
}
}
以下為 SecondFragment.kt
檔案內容:主要為第二頁頁面相關功能
findNavController().popBackStack()
返回第一頁。findNavController().navigate(R.id.from_secondFragment_into_thirdFragment)
切換到第三頁。package com.example.kotlin_demo.fragment
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.navigation.fragment.findNavController
import com.example.kotlin_demo.R
class SecondFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_second, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val btn = view.findViewById<TextView>(R.id.secondBtn)
btn.setOnClickListener(object:View.OnClickListener{
override fun onClick(p0: View?) {
findNavController().navigate(R.id.from_secondFragment_into_thirdFragment)
}
})
val title = view.findViewById<TextView>(R.id.barTitle)
title.setText("Second Page")
val returnBtn = view.findViewById<ImageView>(R.id.backBtn)
returnBtn.setOnClickListener(object:View.OnClickListener{
override fun onClick(p0: View?) {
findNavController().popBackStack()
}
})
}
}
以下為 ThirdFragment.kt
檔案內容:主要為第三頁頁面相關功能
findNavController().navigate(R.id.from_thirdFragment_into_firstFragment)
由第三頁切換到第一頁。package com.example.kotlin_demo.fragment
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.navigation.fragment.findNavController
import com.example.kotlin_demo.R
class ThirdFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_third, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val title = view.findViewById<TextView>(R.id.barTitle)
title.setText("Third Page")
val returnBtn = view.findViewById<ImageView>(R.id.backBtn)
returnBtn.setOnClickListener(object:View.OnClickListener{
override fun onClick(p0: View?) {
findNavController().navigate(R.id.from_thirdFragment_into_firstFragment)
}
})
}
}
以下為 nav_grah.xml
檔案內容:
<fragment
:宣告在導覽圖新增 Fragment
<action
:宣告在上層 Fragment
時,要切換到的頁面app:popUpTo="@id/first_fragment"
代表 會移除第一頁之上的頁面Stack,第一頁會在Stack最上方,而不能再返回之前的頁面
由以下例子說明:
- 在導覽圖新增
FirstFragment
存在,宣告可以由 idfirst_fragment
可以指向它- 於
FirstFragment
頁面時,可由 idfrom_firstFragment_into_secondFragment
執行切換到第二頁的動作(app:destination="@id/second_fragment"
)<fragment android:id="@+id/first_fragment" android:name="com.example.kotlin_demo.fragment.FirstFragment" android:label="FirstFragment" > <action android:id="@+id/from_firstFragment_into_secondFragment" app:destination="@id/second_fragment" /> </fragment>
以下為完整內容:
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/nav_graph"
app:startDestination="@id/first_fragment"
>
<fragment android:id="@+id/first_fragment"
android:name="com.example.kotlin_demo.fragment.FirstFragment"
android:label="FirstFragment"
>
<action android:id="@+id/from_firstFragment_into_secondFragment"
app:destination="@id/second_fragment"
/>
</fragment>
<fragment android:id="@+id/second_fragment"
android:name="com.example.kotlin_demo.fragment.SecondFragment"
android:label="SecondFragment"
>
<action android:id="@+id/from_secondFragment_into_thirdFragment"
app:destination="@id/third_fragment"
/>
</fragment>
<fragment android:id="@+id/third_fragment"
android:name="com.example.kotlin_demo.fragment.ThirdFragment"
android:label="ThirdFragment"
>
<action android:id="@+id/from_thirdFragment_into_firstFragment"
app:destination="@id/first_fragment"
app:popUpTo="@id/first_fragment"
app:popUpToInclusive="true"
/>
</fragment>
</navigation>