Проблемы при изменении поведения кнопки «Назад» с помощью окна навигации (Android / Kotlin) - PullRequest
1 голос
/ 02 марта 2020

Создавая свое первое пользовательское приложение, я хотел бы реализовать то, что поначалу казалось простым, но, конечно, это не так. У меня есть действие с некоторыми фрагментами, к которому я могу перейти с помощью Навигатора:
res / menu / navdrawer_menu. xml

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">

    <item
        android:id="@+id/matchFragmentUI"
        android:icon="@drawable/ic_match"
        android:title="@string/matches_string" />
    <item
        android:id="@+id/statFragmentUI"
        android:icon="@drawable/ic_stat"
        android:title="@string/stats_string" />
    <item
        android:id="@+id/clubFragmentUI"
        android:icon="@drawable/ic_club"
        android:title="@string/club_string" />
    <item
        android:id="@+id/agendaFragmentUI"
        android:icon="@drawable/ic_agenda"
        android:title="@string/agenda_string" />
    <item
        android:id="@+id/settingFragmentUI"
        android:icon="@drawable/ic_settings"
        android:title="@string/settings_string" />
    <item
        android:id="@+id/profileFragmentUI"
        android:icon="@drawable/ic_person_black_24dp"
        android:title="@string/profile_text" />
</menu>

res / layout / activity_content. 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">

        <androidx.drawerlayout.widget.DrawerLayout
            android:id="@+id/drawerLayout"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <androidx.constraintlayout.widget.ConstraintLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                tools:context=".content.ContentActivity">

                <fragment
                    android:id="@+id/contentNavHostFragment"
                    android:name="androidx.navigation.fragment.NavHostFragment"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    app:defaultNavHost="true"
                    app:navGraph="@navigation/navigation_content" />

            </androidx.constraintlayout.widget.ConstraintLayout>

            <com.google.android.material.navigation.NavigationView
                android:id="@+id/navView"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_gravity="start"
                app:menu="@menu/navdrawer_menu"
                app:headerLayout="@layout/nav_header"/>

        </androidx.drawerlayout.widget.DrawerLayout>
    </layout>

Я хотел бы изменить поведение кнопки "Назад", чтобы пользователи не могли случайно покинуть приложение, например:

/* Override behavior of back button */
override fun onBackPressed() {

    /* Case we are not on the home screen */
    if(/* not on home screen */) /* go to home screen */

    else {

        /* Otherwise we return to the access activity */

        /* Dialog window to prevent accidental leaving */
        val backAlertDialog = android.app.AlertDialog.Builder(this)

        backAlertDialog.setTitle("Log out")
        backAlertDialog.setMessage("Are you sure you want to leave?")

        /* buttons YES/NO actions */
        backAlertDialog.setPositiveButton("No") { dialog, which -> dialog.cancel() }

        backAlertDialog.setNegativeButton("Yes") { dialog, which ->
            val accessIntent = Intent(this, AccessActivity::class.java)
            accessIntent.flags = FLAG_ACTIVITY_CLEAR_TOP // Clear activity backstack
            startActivity(accessIntent) // Go back to access activity
            finish() // Finish this activity
        }

        backAlertDialog.show()
    }
}

Моя проблема проверяет, отображаем ли мы HomeFragment. Сначала я попробовал с этим:

if (supportFragmentManager.backstackEntryCount > 0)

Но проблема здесь в том, что навигация с помощью навигационного ящика ничего не добавляет в backstack (backstackEntryCount остается на 0 ), поэтому он не будет работать.

Вот почему я сейчас пытаюсь использовать интерфейс NavigationView.OnNavigationItemSelectedListener, чтобы добавить что-то в backstack, когда элемент выбран, а также отслеживать текущий отображаемый фрагмент например:

/* Keep track of what the current fragment is like */
private var fragment : Fragment? = null

override fun onNavigationItemSelected(item: MenuItem): Boolean {

    val itemId = item.itemId

    val fm = this.supportFragmentManager

    /* Clear stack */
    fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE)

    /* Add a case for each item in the drawer */
    /* For each case, always add (push) a HomeFragment and then the fragment we navigate to */
    /* Then, going back will always return to Home because we cleared backstack before */
    when(itemId) {
        R.id.profileFragmentUI -> {
            fragment = ProfileFragmentUI()
        }
        R.id.agendaFragmentUI -> {
            fragment = AgendaFragmentUI()
        }
        R.id.clubFragmentUI -> {
            fragment = ClubFragmentUI()
        }
        R.id.statFragmentUI -> {
            fragment = StatFragmentUI()
        }
        R.id.matchFragmentUI -> {
            fragment = MatchFragmentUI()
        }
        R.id.settingFragmentUI -> {
            fragment = SettingFragmentUI()
        }
    }

    /* Replace current fragment by the selected fragment in backstack and add home for back support */
    if (fragment != null) {
        fm.beginTransaction()
            .add(HomeFragmentUI(), "HomeFragmentUI")
            .addToBackStack("HomeFragmentUI")
            .replace(R.id.contentNavHostFragment, fragment!!)
            .commit()
    }

    return true
}

Кроме того, вот мои методы onCreate() и onSupportNavigateUp() в коде активности:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    /* Bind layout elements at compile time to be faster at runtime */
    val binding = DataBindingUtil.setContentView<ActivityContentBinding>(this, R.layout.activity_content)

    val contentDrawerLayout = binding.drawerLayout
    val player = intent.getParcelableExtra("player")
    val navigationView = binding.navView

    navigationView.setNavigationItemSelectedListener { item -> onNavigationItemSelected(item) }

    /* Setup the navigation for fragments */
    val navController = this.findNavController(R.id.contentNavHostFragment)
    val fragmentManager = this.supportFragmentManager

    /* Setup navigation bar, with drawer menu */
    NavigationUI.setupActionBarWithNavController(this, navController, drawerLayout)
    NavigationUI.setupWithNavController(binding.navView, navController)

    fragment = HomeFragmentUI() /* To make back button work at start of navigation */
}

override fun onSupportNavigateUp(): Boolean {
    val navController = this.findNavController(R.id.contentNavHostFragment)
    /* Replace up button by drawer button on title screen */
    return NavigationUI.navigateUp(navController, drawerLayout)
}

Теперь я хочу выполнить свою проверку следующим образом:

if (fragment is HomeFragmentUI) 
    /* display dialog */ 
else 
    /* navigate back to home */

Проблема теперь в том, что когда я выбираю предмет в своем ящике, я перехожу к хорошему фрагменту, НО атрибут fragment все еще является экземпляром HomeFragmentUI. Я пытался поместить некоторые журналы в методе onNavigationItemSelected, но они никогда не обнаруживаются. Я понятия не имею, почему метод никогда не вызывается, так как я определил слушателя в onCreate.

Вот некоторые ссылки, которые я использовал до сих пор:
https://www.youtube.com/watch?v=I47Zy6JtNIU

https://www.youtube.com/watch?v=y9KYKYJJ4GY

https://guides.codepath.com/android/Fragment-Navigation-Drawer

Заранее спасибо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...