Навигация с привязкой к представлению

Я пытаюсь заменить все findViewById с помощью View Binding. Но я не могу изменить строку кода NavController с помощью привязки просмотра.

val navController = findNavController(this, R.id.mainHostFragment)

to

var binding : ActivityMainBinding
val navController = findNavController(this, binding.mainHostFragment)

Как я могу это сделать?


person Thaw De Zin    schedule 18.03.2020    source источник


Ответы (4)


Вы не можете заменить его привязкой просмотра. findNavController делает больше, чем просто находит представление в макете.

Взгляните на исходный код здесь

 /**
 * Find a {@link NavController} given a local {@link Fragment}.
 *
 * <p>This method will locate the {@link NavController} associated with this Fragment,
 * looking first for a {@link NavHostFragment} along the given Fragment's parent chain.
 * If a {@link NavController} is not found, this method will look for one along this
 * Fragment's {@link Fragment#getView() view hierarchy} as specified by
 * {@link Navigation#findNavController(View)}.</p>
 *
 * @param fragment the locally scoped Fragment for navigation
 * @return the locally scoped {@link NavController} for navigating from this {@link Fragment}
 * @throws IllegalStateException if the given Fragment does not correspond with a
 * {@link NavHost} or is not within a NavHost.
 */
@NonNull
public static NavController findNavController(@NonNull Fragment fragment) {
    Fragment findFragment = fragment;
    while (findFragment != null) {
        if (findFragment instanceof NavHostFragment) {
            return ((NavHostFragment) findFragment).getNavController();
        }
        Fragment primaryNavFragment = findFragment.getParentFragmentManager()
                .getPrimaryNavigationFragment();
        if (primaryNavFragment instanceof NavHostFragment) {
            return ((NavHostFragment) primaryNavFragment).getNavController();
        }
        findFragment = findFragment.getParentFragment();
    }
    // Try looking for one associated with the view instead, if applicable
    View view = fragment.getView();
    if (view != null) {
        return Navigation.findNavController(view);
    }
    throw new IllegalStateException("Fragment " + fragment
            + " does not have a NavController set");
}

Это больше, чем просто поиск контроллера. Он проходит, создает фрагмент, создает представления и генерирует исключение.

Привязка представления просто создает класс привязки со всеми представлениями вашего макета в нем. Он не предназначен для поиска контроллера навигации приложения.

person Somesh Kumar    schedule 18.03.2020

С помощью этого ответа я нахожу простую реализацию

binding?.apply {
        setContentView(root)
        setSupportActionBar(toolbar)
        navController = (supportFragmentManager
            .findFragmentById(fragmentHost.id) as NavHostFragment)
            .navController
        setupActionBarWithNavController(navController, appBarConfiguration)
        bottom.setupWithNavController(navController)
    }
person luisenricke    schedule 30.06.2020
comment
блестящий, но меньше кода nav = ... will может измениться на nav = this.findNavController (R.id.myNavHostFragment) - person Fortran; 05.01.2021
comment
Есть ли у этого решения накладные расходы на создание двойных деревьев? - person Fortran; 05.01.2021
comment
@Fortran Да, это сложный ответ, потому что вы применяете привязку, но снова вызываете ссылку на все виджеты с помощью R.id ... - person luisenricke; 06.01.2021

findNavController(R.id.nav_host_fragment) должен появиться после присоединения представления к действию, подобному этому:

setContentView(binding.root)
val navController: NavController = findNavController(R.id.nav_host_fragment) 

Подробнее здесь

person francis    schedule 27.02.2021

Вот мой пример кода с использованием привязки представления и навигации.

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.setupActionBarWithNavController
import androidx.navigation.ui.setupWithNavController
import com.zeddigital.zigmaster.databinding.ActivityMainBinding


class MainActivity : AppCompatActivity() {

    private lateinit var appBarConfiguration: AppBarConfiguration
    private lateinit var binding : ActivityMainBinding

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

        /*
        Use view binding in activities
        
        Call the static inflate() method included in the generated binding class. 
        This creates an instance of the binding class for the activity to use.
        Get a reference to the root view by either calling the getRoot() method or using Kotlin property syntax.
        Pass the root view to setContentView() to make it the active view on the screen.*/
        binding = ActivityMainBinding.inflate(layoutInflater)

        val view = binding.root
        setContentView(view)

        setSupportActionBar(binding.appBarMain.toolbar)

        //val navController = findNavController(R.id.nav_host_fragment)
        val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
        val navController = navHostFragment.navController

        // Passing each menu ID as a set of Ids because each
        // menu should be considered as top level destinations.
        appBarConfiguration = AppBarConfiguration(setOf(
                R.id.nav_home, R.id.nav_gallery, R.id.nav_slideshow), binding.drawerLayout)
        setupActionBarWithNavController(navController, appBarConfiguration)
        binding.navView.setupWithNavController(navController)

    }
}
person Hari Shankar S    schedule 06.03.2021