Home > Software engineering >  Using a DialogFragment as a Navgraph destination in Xamarin.Android
Using a DialogFragment as a Navgraph destination in Xamarin.Android

Time:09-16

I am trying to include a DialogFragment as a destination, following the examples here, adapting the code for Xamarin.

The code works fine as long as I use <fragment/> in the navgraph. However, when changed to <dialog/>, the app crashes when I try navigating to the DialogFragment, with an error saying: AndroidX.Fragment.App.Fragment InstantiationException: 'Unable to instantiate fragment fragmentname: make sure class name exists.

Is this functionality not available in xamarin.android, or are there any additional steps I need to take to make it work?

EDIT 1: Posting example code.

MainActivity.cs:

namespace exampleApp
{
    [Activity(Label = "@string/app_name", Theme = "@style/AppTheme.NoActionBar", MainLauncher = true)]
    public class MainActivity : AppCompatActivity
    {
        protected override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);
            Xamarin.Essentials.Platform.Init(this, savedInstanceState);
            SetContentView(Resource.Layout.activity_main);

        }

        public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
        {
            Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);

            base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
        }
    }
}

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout 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">

    <fragment
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:id="@ id/main_nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        app:navGraph="@navigation/nav_graph"
        app:defaultNavHost="true" />


</androidx.coordinatorlayout.widget.CoordinatorLayout>

fragment1.cs:

using Android.OS;
using Android.Views;
using Android.Widget;
using System;
using AndroidX.Fragment.App;
using AndroidX.Navigation;

namespace exampleApp
{
    public class Fragment1 : Fragment
    {
        public override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);
        }

        public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
        {
            //Inflating view pretty much creates it in memory, without showing it on screen.
            View view = inflater.Inflate(Resource.Layout.fragment1_layout, container, false);

            return view;
        }
        public override void OnViewCreated(View view, Bundle savedInstanceState)
        {
            base.OnViewCreated(view, savedInstanceState);
            Button dialogButton = view.FindViewById<Button>(Resource.Id.button_dialog);

            dialogButton.Click  = (object sender, EventArgs e) =>
            {
                Navigation.FindNavController(view).Navigate(Resource.Id.dest_dialog);
            };
        }
    }
}

fragment1_layout.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@ id/fragment1_layout">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Open Dialog"
        android:id="@ id/button_dialog"/>
</LinearLayout>

ExampleDialog.cs:

namespace exampleApp
{
    public class ExampleDialog : AndroidX.Fragment.App.DialogFragment
    {
        public override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);

            // Create your fragment here
        }

        public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
        {
            // Use this to return your custom view for this Fragment
            return inflater.Inflate(Resource.Layout.exampleDialog_layout, container, false);

            //return base.OnCreateView(inflater, container, savedInstanceState);
        }
    }
}

exampleDialog_layout.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@ id/exampleDialog_layout"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="EXAMPLE DIALOG"/>
    </LinearLayout>

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/dest_fragment1">

    <fragment
        android:id="@ id/dest_fragment1"
        android:name="exampleApp.Fragment1">
    </fragment>

    <dialog
        android:id="@ id/dest_dialog"
        android:name="exampleApp.ExampleDialog">
    </dialog>
</navigation>

CodePudding user response:

Great to see another Xamarin.Android developer using the NavigationComponent!!

That error is usually because you have a typo in your nav_graph.xml. You usually use the fully qualified name of the fragment or dialog - case is important. I always lowercase the namespace as in com.companyname.navigationgraph6.fragments.RaceResultFragment. The RaceResultFragment (fragment name) is exactly as it is declared in the class.

I have a number of tutorials on the NavigationComponent, NavigationGraph1 through NavigationGraph6 which increase in complexity as the project number increases. Each project has the same NavigationGraph.docx explaining each feature as I progress the tutorials.

You can find them at https://github.com/gmck. From memory, I think it is NavigationGraph3 where I introduce a dialog.

CodePudding user response:

@kfjpkcw

I tried to reproduce your problem and was successful. For some reason xamarin.android doesn't seem to be able to distinguish between a dialog and a fragment, hence the exception. I reckon you should report that at https://github.com/xamarin/AndroidX/issues. I'm sure I tried a dialog ages ago and it worked, (https://medium.com/androiddevelopers/navigation-component-dialog-destinations-bfeb8b022759 but maybe I only used it in Android Studio) but after working with nav_graphs for a while I found it tedious adding all the extra stuff like a destination to goto and animations (then stuck with one type of animation), so decided to only use nav_graph for fragment part only. If you read my docx file I sort of justify why I've gone my own route.

To get around your problem with dialogs, just handle it as I do in NavigationGraph series I referred to.

  • Related