From fc55e242909e090770b0bbc487bf2bcf730e1e57 Mon Sep 17 00:00:00 2001 From: Daria Boytsova Date: Wed, 9 Jul 2025 22:16:41 +0200 Subject: [PATCH] Fragments howework --- app/build.gradle | 3 + app/src/main/AndroidManifest.xml | 8 ++ .../otus/gpb/homework/fragments/ActivityA.kt | 18 +++ .../otus/gpb/homework/fragments/ActivityB.kt | 37 ++++++ .../gpb/homework/fragments/ChildFragmentAA.kt | 66 +++++++++++ .../gpb/homework/fragments/ChildFragmentAB.kt | 43 +++++++ .../otus/gpb/homework/fragments/FragmentA.kt | 105 ++++++++++++++++++ .../otus/gpb/homework/fragments/FragmentBA.kt | 87 +++++++++++++++ .../otus/gpb/homework/fragments/FragmentBB.kt | 55 +++++++++ .../gpb/homework/fragments/MainActivity.kt | 17 ++- .../fragments/ParentFragmentListener.kt | 5 + .../res/layout-land/activity_fragment_b.xml | 21 ++++ .../main/res/layout/activity_fragment_a.xml | 8 ++ .../main/res/layout/activity_fragment_b.xml | 10 ++ app/src/main/res/layout/activity_main.xml | 20 +++- app/src/main/res/layout/child_fragment_aa.xml | 18 +++ app/src/main/res/layout/child_fragment_ab.xml | 6 + app/src/main/res/layout/fragment_ba.xml | 18 +++ app/src/main/res/layout/fragment_bb.xml | 18 +++ app/src/main/res/layout/fragment_parent_a.xml | 25 +++++ app/src/main/res/values/strings.xml | 8 ++ 21 files changed, 592 insertions(+), 4 deletions(-) create mode 100644 app/src/main/java/otus/gpb/homework/fragments/ActivityA.kt create mode 100644 app/src/main/java/otus/gpb/homework/fragments/ActivityB.kt create mode 100644 app/src/main/java/otus/gpb/homework/fragments/ChildFragmentAA.kt create mode 100644 app/src/main/java/otus/gpb/homework/fragments/ChildFragmentAB.kt create mode 100644 app/src/main/java/otus/gpb/homework/fragments/FragmentA.kt create mode 100644 app/src/main/java/otus/gpb/homework/fragments/FragmentBA.kt create mode 100644 app/src/main/java/otus/gpb/homework/fragments/FragmentBB.kt create mode 100644 app/src/main/java/otus/gpb/homework/fragments/ParentFragmentListener.kt create mode 100644 app/src/main/res/layout-land/activity_fragment_b.xml create mode 100644 app/src/main/res/layout/activity_fragment_a.xml create mode 100644 app/src/main/res/layout/activity_fragment_b.xml create mode 100644 app/src/main/res/layout/child_fragment_aa.xml create mode 100644 app/src/main/res/layout/child_fragment_ab.xml create mode 100644 app/src/main/res/layout/fragment_ba.xml create mode 100644 app/src/main/res/layout/fragment_bb.xml create mode 100644 app/src/main/res/layout/fragment_parent_a.xml diff --git a/app/build.gradle b/app/build.gradle index c5cf1b8..427be29 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -42,6 +42,9 @@ dependencies { implementation 'androidx.appcompat:appcompat:1.5.1' implementation 'com.google.android.material:material:1.6.1' implementation 'androidx.constraintlayout:constraintlayout:2.1.4' + implementation 'androidx.fragment:fragment-ktx:1.8.8' + implementation 'com.google.android.material:material:1.5.0' + implementation 'androidx.fragment:fragment:1.8.8' testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.3' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 9604b34..b716662 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -15,12 +15,20 @@ + + + + \ No newline at end of file diff --git a/app/src/main/java/otus/gpb/homework/fragments/ActivityA.kt b/app/src/main/java/otus/gpb/homework/fragments/ActivityA.kt new file mode 100644 index 0000000..bcc4768 --- /dev/null +++ b/app/src/main/java/otus/gpb/homework/fragments/ActivityA.kt @@ -0,0 +1,18 @@ +package otus.gpb.homework.fragments + +import android.os.Bundle +import androidx.appcompat.app.AppCompatActivity + +class ActivityA : AppCompatActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_fragment_a) + + if (savedInstanceState == null) { + supportFragmentManager.beginTransaction() + .replace(R.id.fragment_activity_container, FragmentA()) + .commit() + } + } +} diff --git a/app/src/main/java/otus/gpb/homework/fragments/ActivityB.kt b/app/src/main/java/otus/gpb/homework/fragments/ActivityB.kt new file mode 100644 index 0000000..7660e08 --- /dev/null +++ b/app/src/main/java/otus/gpb/homework/fragments/ActivityB.kt @@ -0,0 +1,37 @@ +package otus.gpb.homework.fragments + +import android.content.res.Configuration +import android.graphics.Color +import android.os.Bundle +import androidx.appcompat.app.AppCompatActivity + +class ActivityB : AppCompatActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_fragment_b) + + if (savedInstanceState == null) { + val currentOrientation = resources.configuration.orientation + val fragmentBA = FragmentBA.newInstance(Color.WHITE) + + if (currentOrientation == Configuration.ORIENTATION_PORTRAIT) { + supportFragmentManager.beginTransaction() + .replace(R.id.fragment_b_activity_container, fragmentBA) + .commit() + } else { + val fragmentBB = FragmentBB.newInstance(Color.YELLOW) + + supportFragmentManager.beginTransaction() + .replace(R.id.fragment_container_ba_land, fragmentBA) + .replace(R.id.fragment_container_bb_land, fragmentBB) + .commit() + } + } + } + + companion object { + const val REQUEST_KEY_COLOR = "request_key_color" + const val BUNDLE_KEY_COLOR = "bundle_key_color" + } +} diff --git a/app/src/main/java/otus/gpb/homework/fragments/ChildFragmentAA.kt b/app/src/main/java/otus/gpb/homework/fragments/ChildFragmentAA.kt new file mode 100644 index 0000000..51fe163 --- /dev/null +++ b/app/src/main/java/otus/gpb/homework/fragments/ChildFragmentAA.kt @@ -0,0 +1,66 @@ +package otus.gpb.homework.fragments + +import android.content.Context +import android.graphics.Color +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Button +import androidx.fragment.app.Fragment + +class ChildFragmentAA : Fragment() { + + private var listener: ParentFragmentListener? = null + private var backgroundColor: Int = Color.WHITE + + + override fun onAttach(context: Context) { + super.onAttach(context) + if (parentFragment is ParentFragmentListener) { + listener = parentFragment as ParentFragmentListener + } else { + throw RuntimeException("${parentFragment} must implement ParentFragmentListener") + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + arguments?.let { + backgroundColor = it.getInt(ARG_BACKGROUND_COLOR) + } + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + val view = inflater.inflate(R.layout.child_fragment_aa, container, false) + view.setBackgroundColor(backgroundColor) + val openChildFragmentABButton: Button = + view.findViewById(R.id.button_open_child_fragment_ab) + openChildFragmentABButton.setOnClickListener { + listener?.onOpenChildFragmentABClicked() + } + return view + } + + override fun onDetach() { + super.onDetach() + listener = null + } + + companion object { + private const val ARG_BACKGROUND_COLOR = "background_color" + + fun newInstance(color: Int): ChildFragmentAA { + val fragment = ChildFragmentAA() + val args = Bundle().apply { + putInt(ARG_BACKGROUND_COLOR, color) + } + fragment.arguments = args + return fragment + } + } +} diff --git a/app/src/main/java/otus/gpb/homework/fragments/ChildFragmentAB.kt b/app/src/main/java/otus/gpb/homework/fragments/ChildFragmentAB.kt new file mode 100644 index 0000000..099c1a1 --- /dev/null +++ b/app/src/main/java/otus/gpb/homework/fragments/ChildFragmentAB.kt @@ -0,0 +1,43 @@ +package otus.gpb.homework.fragments + +import android.graphics.Color +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment + +class ChildFragmentAB : Fragment() { + + private var backgroundColor: Int = Color.WHITE + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + arguments?.let { + backgroundColor = it.getInt(ARG_BACKGROUND_COLOR, Color.WHITE) + } + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + val view = inflater.inflate(R.layout.child_fragment_ab, container, false) + view?.setBackgroundColor(backgroundColor) + return view + } + + companion object { + private const val ARG_BACKGROUND_COLOR = "background_color_ab" + + fun newInstance(color: Int): ChildFragmentAB { + val fragment = ChildFragmentAB() + val args = Bundle().apply { + putInt(ARG_BACKGROUND_COLOR, color) + } + fragment.arguments = args + return fragment + } + } +} diff --git a/app/src/main/java/otus/gpb/homework/fragments/FragmentA.kt b/app/src/main/java/otus/gpb/homework/fragments/FragmentA.kt new file mode 100644 index 0000000..d070f3e --- /dev/null +++ b/app/src/main/java/otus/gpb/homework/fragments/FragmentA.kt @@ -0,0 +1,105 @@ +package otus.gpb.homework.fragments + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Button +import androidx.activity.OnBackPressedCallback +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentManager + + +class FragmentA : Fragment(), ParentFragmentListener { + + private lateinit var openChildFragmentAAButton: Button + private lateinit var onBackPressedCallback: OnBackPressedCallback + + private val childBackStackListener = FragmentManager.OnBackStackChangedListener { + updateOpenChildButtonVisibility() + } + + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + val view = inflater.inflate(R.layout.fragment_parent_a, container, false) + + openChildFragmentAAButton = view.findViewById(R.id.button_open_fragment_aa) + + openChildFragmentAAButton.setOnClickListener { + openChildFragmentAA() + } + + onBackPressedCallback = object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + if (childFragmentManager.backStackEntryCount > 0) { + childFragmentManager.popBackStack() + } else { + isEnabled = false + requireActivity().onBackPressedDispatcher.onBackPressed() + isEnabled = true + } + } + } + requireActivity().onBackPressedDispatcher.addCallback( + viewLifecycleOwner, + onBackPressedCallback + ) + + childFragmentManager.addOnBackStackChangedListener(childBackStackListener) + updateOpenChildButtonVisibility() + return view + } + + override fun onDestroyView() { + super.onDestroyView() + childFragmentManager.removeOnBackStackChangedListener(childBackStackListener) + } + + private fun updateOpenChildButtonVisibility() { + val hasChildFragment = + childFragmentManager.findFragmentById(R.id.parent_fragment_a_child_container) != null + val isChildBackStackEmpty = childFragmentManager.backStackEntryCount == 0 + + if (hasChildFragment && isChildBackStackEmpty) { + } else if (!hasChildFragment && isChildBackStackEmpty) { + openChildFragmentAAButton.visibility = View.VISIBLE + } else { + openChildFragmentAAButton.visibility = View.GONE + } + + openChildFragmentAAButton.visibility = + if (childFragmentManager.backStackEntryCount == 0 && childFragmentManager.findFragmentById( + R.id.parent_fragment_a_child_container + ) == null + ) View.VISIBLE else View.GONE + openChildFragmentAAButton.visibility = + if (childFragmentManager.backStackEntryCount == 0) View.VISIBLE else View.GONE + } + + private fun openChildFragmentAA() { + val randomColor = ColorGenerator.generateColor() + val childFragmentAA = ChildFragmentAA.newInstance(randomColor) + childFragmentManager.beginTransaction() + .replace(R.id.parent_fragment_a_child_container, childFragmentAA) + .addToBackStack("ChildFragmentAA") + .commit() + openChildFragmentAAButton.visibility = View.GONE + } + + private fun openChildFragmentAB() { + val randomColor = ColorGenerator.generateColor() + val childFragmentAB = ChildFragmentAB.newInstance(randomColor) + childFragmentManager.beginTransaction() + .replace(R.id.parent_fragment_a_child_container, childFragmentAB) + .addToBackStack("ChildFragmentAB") + .commit() + } + + override fun onOpenChildFragmentABClicked() { + openChildFragmentAB() + } +} diff --git a/app/src/main/java/otus/gpb/homework/fragments/FragmentBA.kt b/app/src/main/java/otus/gpb/homework/fragments/FragmentBA.kt new file mode 100644 index 0000000..be886f9 --- /dev/null +++ b/app/src/main/java/otus/gpb/homework/fragments/FragmentBA.kt @@ -0,0 +1,87 @@ +package otus.gpb.homework.fragments + +import android.content.res.Configuration +import android.graphics.Color +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Button +import androidx.fragment.app.Fragment + +class FragmentBA : Fragment() { + + private var backgroundColor: Int = Color.WHITE + private lateinit var openFragmentBBButton: Button + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + arguments?.let { + backgroundColor = it.getInt(ARG_BACKGROUND_COLOR, Color.WHITE) + } + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + val view = inflater.inflate( + R.layout.fragment_ba, + container, + false + ) + view.setBackgroundColor(backgroundColor) + return view + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + parentFragmentManager.setFragmentResultListener( + ActivityB.REQUEST_KEY_COLOR, + viewLifecycleOwner + ) { requestKey, bundle -> + if (requestKey == ActivityB.REQUEST_KEY_COLOR) { + val newColor = bundle.getInt(ActivityB.BUNDLE_KEY_COLOR, Color.WHITE) + view.setBackgroundColor(newColor) + this.backgroundColor = newColor + } + } + + openFragmentBBButton = view.findViewById(R.id.button_open_fragment_bb) + + val currentOrientation = resources.configuration.orientation + if (currentOrientation == Configuration.ORIENTATION_PORTRAIT) { + openFragmentBBButton.visibility = View.VISIBLE + openFragmentBBButton.setOnClickListener { + openFragmentBBInPortrait() + } + } else { + openFragmentBBButton.visibility = View.GONE + } + } + + private fun openFragmentBBInPortrait() { + val randomColor = ColorGenerator.generateColor() + val fragmentBB = FragmentBB.newInstance(randomColor) + + parentFragmentManager.beginTransaction() + .replace(R.id.fragment_b_activity_container, fragmentBB) + .addToBackStack("FragmentBBFromBA") + .commit() + } + + companion object { + private const val ARG_BACKGROUND_COLOR = "background_color_ba" + + fun newInstance(color: Int): FragmentBA { + val fragment = FragmentBA() + val args = Bundle().apply { + putInt(ARG_BACKGROUND_COLOR, color) + } + fragment.arguments = args + return fragment + } + } +} diff --git a/app/src/main/java/otus/gpb/homework/fragments/FragmentBB.kt b/app/src/main/java/otus/gpb/homework/fragments/FragmentBB.kt new file mode 100644 index 0000000..b2dba91 --- /dev/null +++ b/app/src/main/java/otus/gpb/homework/fragments/FragmentBB.kt @@ -0,0 +1,55 @@ +package otus.gpb.homework.fragments + +import android.content.res.Configuration +import android.graphics.Color +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Button +import androidx.fragment.app.Fragment + +class FragmentBB : Fragment() { + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + val view = inflater.inflate(R.layout.fragment_bb, container, false) + view.setBackgroundColor(Color.YELLOW) + return view + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + val changeColorButton: Button = view.findViewById(R.id.button_send_color) + changeColorButton.setOnClickListener { + val newColor = ColorGenerator.generateColor() + val result = Bundle().apply { + putInt(ActivityB.BUNDLE_KEY_COLOR, newColor) + } + parentFragmentManager.setFragmentResult(ActivityB.REQUEST_KEY_COLOR, result) + + val currentOrientation = resources.configuration.orientation + if (currentOrientation == Configuration.ORIENTATION_PORTRAIT) { + parentFragmentManager.popBackStack() + + } + } + } + + companion object { + private const val ARG_BACKGROUND_COLOR = "background_color_bb" + + fun newInstance(color: Int): FragmentBB { + val fragment = FragmentBB() + val args = Bundle().apply { + putInt(ARG_BACKGROUND_COLOR, color) + } + fragment.arguments = args + return fragment + } + } +} diff --git a/app/src/main/java/otus/gpb/homework/fragments/MainActivity.kt b/app/src/main/java/otus/gpb/homework/fragments/MainActivity.kt index 5e89c44..75597d2 100644 --- a/app/src/main/java/otus/gpb/homework/fragments/MainActivity.kt +++ b/app/src/main/java/otus/gpb/homework/fragments/MainActivity.kt @@ -1,12 +1,27 @@ package otus.gpb.homework.fragments +import android.content.Intent import android.os.Bundle +import android.widget.Button import androidx.appcompat.app.AppCompatActivity + class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) + + val openFragmentAButton = findViewById