单Activity多Fragment,Navigation实现Fragment跳转,Fragment之间通过ViewModel共享数据
1、MainActivity
1、activity_main.xml
<?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=".MainActivity">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/fragmentContainerView"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="@navigation/nav_graph" />
</androidx.constraintlayout.widget.ConstraintLayout>
2、MainActivity
/**
* kotlin_jetpack_navigation
* 使用navigation + dataBinding + viewModel
* 三个fragment共享一个viewModel中的数据,在NavigationView中显示
*/
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}
2、HomeFragment, DetailFragment
- FragmentA:包括SeekBar和一个按钮,点击button跳转到FragmentB
- FragmentB:SeekBar加一和减一操作的按钮,一个返回FragmentA的按钮,即经过加减操作以后,在FragmentA上显示加减的结果。
nav_graph.xml
<navigation 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/nav_graph"
app:startDestination="@id/homeFragment">
<fragment
android:id="@+id/detailFragment"
android:name="cn.hk.navigation3.DetailFragment"
android:label="fragment_detail"
tools:layout="@layout/fragment_detail" >
<action
android:id="@+id/action_detailFragment_to_homeFragment"
app:destination="@id/homeFragment" />
</fragment>
<fragment
android:id="@+id/homeFragment"
android:name="cn.hk.navigation3.HomeFragment"
android:label="fragment_home"
tools:layout="@layout/fragment_home" >
<action
android:id="@+id/action_homeFragment_to_detailFragment"
app:destination="@id/detailFragment" />
</fragment>
</navigation>
2.1、HomeFragment
1、fragment_home.xml
<?xml version="1.0" encoding="utf-8"?>
<layout 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">
<data>
<variable
name="data"
type="cn.hk.navigation3.MyViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".HomeFragment">
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_begin="320dp"
app:layout_constraintGuide_percent="0.5" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{String.valueOf(data.number)}"
android:textSize="20sp"
app:layout_constraintBottom_toTopOf="@+id/guideline"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/guideline" />
<SeekBar
android:id="@+id/seekBar"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintBottom_toTopOf="@+id/textView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
2、HomeFragment
class HomeFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
// val myViewModel = ViewModelProviders.of(this).get(MyViewModel::class.java)
val myViewModel by activityViewModels<MyViewModel>()
val binding = DataBindingUtil.inflate<FragmentHomeBinding>(
inflater, R.layout.fragment_home, container, false
)
binding.also {
it.data = myViewModel
it.lifecycleOwner = activity
it.button.setOnClickListener { v ->
val controller = Navigation.findNavController(v)
controller.navigate(R.id.action_homeFragment_to_detailFragment)
}
myViewModel.get().value?.also { numberValue ->
it.seekBar.progress = numberValue
}
it.seekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(p0: SeekBar?, p1: Int, p2: Boolean) {
myViewModel.set(p1)
}
override fun onStartTrackingTouch(p0: SeekBar?) {
}
override fun onStopTrackingTouch(p0: SeekBar?) {
}
})
}
return binding.root
}
2.2、DetailFragment
1、fragment_detail.xml
<?xml version="1.0" encoding="utf-8"?>
<layout 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">
<data>
<variable
name="data"
type="cn.hk.navigation3.MyViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".DetailFragment">
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_begin="320dp"
app:layout_constraintGuide_percent="0.5" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{String.valueOf(data.number)}"
android:textSize="20sp"
app:layout_constraintBottom_toTopOf="@+id/guideline"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/add"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="add"
android:onClick="@{()->data.count(1)}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/jian"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/guideline" />
<Button
android:id="@+id/jian"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="cut"
android:onClick="@{()->data.count(-1)}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/add"
app:layout_constraintTop_toTopOf="@+id/guideline" />
<Button
android:id="@+id/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="返回"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/add" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
2、DetailFragment
class DetailFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
// val myViewModel = ViewModelProviders.of(this).get(MyViewModel::class.java)
val myViewModel by activityViewModels<MyViewModel>()
val binding = DataBindingUtil.inflate<FragmentDetailBinding>(
inflater,
R.layout.fragment_detail,
container,
false
)
binding.also {
it.data = myViewModel
it.lifecycleOwner = activity
it.button3.setOnClickListener { v ->
val controller = Navigation.findNavController(v)
controller.navigate(R.id.action_detailFragment_to_homeFragment)
}
}
return binding.root
}
}
3、MyViewModel
class MyViewModel : ViewModel() {
var number: MutableLiveData<Int> = MutableLiveData(0)
fun get() = number
fun set(result: Int) {
number.value = result
}
fun count(x: Int) {
number.value = number.value?.plus(x)
if (number.value!! < 0)
number.value = 0
}
}