Как мне найти NavController, если я использую привязку просмотра? - PullRequest
0 голосов
/ 12 июля 2020

Обычно я использую val navController: NavController = findNavController(R.id.nav_host_fragment) в коде A, чтобы найти NavController, он основан на R.id.nav_host_fragment.

Теперь я использую привязку представления в приложении точно так же, как код B, как я могу использовать NavController, если я использую представление привязка?

Кстати, на мой взгляд, R.id.nav_host_fragment не будет доступен в привязке просмотра, верно?

Код A

class TasksActivity : AppCompatActivity() { 

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.tasks_act)

        val navController: NavController = findNavController(R.id.nav_host_fragment)
     }
 
}

Код B

class TasksActivity : AppCompatActivity() {
    
    private lateinit var binding: TasksActBinding
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        binding = TasksActBinding.inflate(layoutInflater)
        val view = binding.root
        setContentView(view)       
      
        //val navController: NavController = findNavController(R.id.nav_host_fragment)       
    }

}

tasks_act. xml

<androidx.drawerlayout.widget.DrawerLayout
    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/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".tasks.TasksActivity"
    tools:openDrawer="start">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <com.google.android.material.appbar.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <androidx.appcompat.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:minHeight="?attr/actionBarSize"
                android:theme="@style/Toolbar"
                app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
        </com.google.android.material.appbar.AppBarLayout>

        <fragment
            android:id="@+id/nav_host_fragment"
            android:name="androidx.navigation.fragment.NavHostFragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent"

            app:defaultNavHost="true"
            app:navGraph="@navigation/nav_graph" />

    </LinearLayout>

    ..

</androidx.drawerlayout.widget.DrawerLayout>

Ответы [ 2 ]

1 голос
/ 25 июля 2020

Код B все еще должен работать нормально.

Я просмотрел findNavController(). Это функция расширения для упрощения кода, код функции расширения:

fun Activity.findNavController(@IdRes viewId: Int): NavController =
    Navigation.findNavController(this, viewId)

Теперь, глядя на код findNavController() внутри Navigation, мы видим ниже

 @NonNull
    public static NavController findNavController(@NonNull Activity activity, @IdRes int viewId) {
        View view = ActivityCompat.requireViewById(activity, viewId);
        NavController navController = findViewNavController(view);
        if (navController == null) {
            throw new IllegalStateException("Activity " + activity
                    + " does not have a NavController set on " + viewId);
        }
        return navController;
    }

ViewId, который мы передаем в аргументе, используется в первой строке

View view = ActivityCompat.requireViewById(activity, viewId);

теперь глядя на requireViewById() внутри ActivityCompat мы видим

  @NonNull
    public static <T extends View> T requireViewById(@NonNull Activity activity, @IdRes int id) {
        if (Build.VERSION.SDK_INT >= 28) {
            return activity.requireViewById(id);
        }

        T view = activity.findViewById(id);
        if (view == null) {
            throw new IllegalArgumentException("ID does not reference a View inside this Activity");
        }
        return view;
    }

для api 28 и плюс вызывается метод

@NonNull
    public final <T extends View> T requireViewById(@IdRes int id) {
        T view = findViewById(id);
        if (view == null) {
            throw new IllegalArgumentException("ID does not reference a View inside this Activity");
        }
        return view;
    }

. Так что, пока представление (внутри которого присутствует nav_host_fragment) прикреплено к активности, код, который вы написали для поиска контроллера навигации, должен работать полностью нормально.

class TasksActivity : AppCompatActivity() {
    
    private lateinit var binding: TasksActBinding
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        binding = TasksActBinding.inflate(layoutInflater)
        val view = binding.root
        setContentView(view)       //you are attaching view to activity here , make sure you always call this before the next line , else you will get IllegalStateException 
      
        val navController: NavController = findNavController(R.id.nav_host_fragment)       
    }

}

Я не тестировал код лично, но, насколько я понимаю, он должен работать отлично.

1 голос
/ 12 июля 2020

Мы используем ViewBinding, чтобы получить ссылку на само представление. Если вы используете привязку просмотра в TextView, вы получите ссылку на представление.

В случае NavCotroller, если вы используете привязку просмотра, вы получите ссылку на фрагмент, а findNavController ожидайте ViewId целочисленного типа.

findNavController(@IdRes viewId: int)
...