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.