Igor
Igor

Reputation: 609

SetSupportActionBar on Fragment does not set SupportActionBar

Following sample Android-Support/Fragments for MvvmCross and trying to refactor my own app to move AppBar and Toolbar resource definition to fragments. I am having having problems with the call to SetSupportActionbar on the fragment while the call used to work fine on the Activity. Here is the refactored code:

activity_main.axml

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/main_coordinator_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true">

    <!-- Actual content of the screen -->
    <FrameLayout
        android:id="@+id/main_content_frame"
        android:layout_width="match_parent"
        android:layout_height="fill_parent"
        android:layout_centerInParent="true"
        android:layout_below="@+id/toolbar"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />

</android.support.design.widget.CoordinatorLayout>

MainActivity.cs

using Android.App;
using Android.OS;
using Android.Content.PM;
using MvvmCross.Droid.Support.V7.AppCompat;
using Mobile.Core.ViewModels;

namespace Mobile.Droid.Activities
{
    [Activity(
        Label = "@string/applicationName",
        Icon = "@drawable/ic_icon", 
        Theme = "@style/AppTheme.Default",
        LaunchMode = LaunchMode.SingleTop,
        ScreenOrientation = ScreenOrientation.Portrait,
        Name = "droid.mobile.activities.MainActivity")]
    public class MainActivity : MvxAppCompatActivity<MainViewModel>
    {
        ...    
        protected override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);

            SetContentView(Resource.Layout.activity_main);

            ViewModel.ShowLists();
        }
        ....
    }
}

fragment_lists.axml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/list_frame"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/main_app_bar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.ActionBar">

        <android.support.v7.widget.Toolbar
            android:id="@+id/main_tool_bar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:popupTheme="@style/AppTheme.ToolBar"
            app:layout_scrollFlags="scroll|enterAlways" />

    </android.support.design.widget.AppBarLayout>

    <MvvmCross.Droid.Support.V4.MvxSwipeRefreshLayout
        android:id="@+id/listsRefresher"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"
        app:MvxBind="Refreshing IsLoading; RefreshCommand ReloadCommand">

        <MvvmCross.Droid.Support.V7.RecyclerView.MvxRecyclerView
            android:id="@+id/listsRecyclerView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_behavior="@string/appbar_scrolling_view_behavior"
            app:MvxItemTemplate="@layout/item_list"
            app:MvxBind="ItemsSource Lists; ItemClick ShowListItemsCommand" />

    </MvvmCross.Droid.Support.V4.MvxSwipeRefreshLayout>

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|right"
        android:layout_margin="@dimen/margin_medium"
        android:src="@drawable/ic_add_white_24dp"
        android:visibility="invisible"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"
        app:layout_anchor="@id/main_content_frame"
        app:layout_anchorGravity="bottom|right|end" />

</RelativeLayout>

ListsFragment.cs

using Android.OS;
using Android.Views;
using MvvmCross.Droid.Support.V4;
using MvvmCross.Binding.Droid.BindingContext;
using Android.Runtime;
using List.Mobile.Droid.Common;
using MvvmCross.Binding.BindingContext;
using Android.Support.V4.View;
using Android.Widget;
using List.Mobile.Core.ViewModels;
using MvvmCross.Droid.Support.V7.RecyclerView;
using Android.Support.V7.Widget;
using MvvmCross.Droid.Views.Attributes;

namespace List.Mobile.Droid.Views
{
    [MvxFragmentPresentation(typeof(MainViewModel), Resource.Id.main_content_frame, true)]
    [Register("list.mobile.droid.views.ListsFragment")]
    public class ListsFragment : BaseFragment<ListsViewModel>, ActionMode.ICallback
    {
        ...    
        public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
        {
            base.OnCreateView(inflater, container, savedInstanceState);
            ...
        }
   }
}

BaseFragment.cs

using MvvmCross.Droid.Support.V4;
using List.Mobile.Droid.Common;
using MvvmCross.Core.ViewModels;
using Android.OS;
using Android.Views;
using Android.Support.Design.Widget;
using Android.Support.V7.Widget;
using Android.Support.V7.App;

namespace List.Mobile.Droid.Views
{
    public abstract class BaseFragment<T> : MvxFragment<T> where T : MvxViewModel
    {    
        protected AppBarLayout AppBar { get; set; }
        protected FloatingActionButton FAB { get; set; }
        protected Toolbar Toolbar { get; set; }

        public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
        {
            var view = base.OnCreateView(inflater, container, savedInstanceState);

            AppBar = Activity.FindViewById<AppBarLayout>(Resource.Id.main_app_bar);
            FAB = Activity.FindViewById<FloatingActionButton>(Resource.Id.fab);
            Toolbar = Activity.FindViewById<Toolbar>(Resource.Id.main_tool_bar);
            AppCompatActivity parentActivity = ((AppCompatActivity)Activity);
            parentActivity.SetSupportActionBar(Toolbar);
            parentActivity.SupportActionBar.SetDisplayHomeAsUpEnabled(false);
            parentActivity.SupportActionBar.SetHomeButtonEnabled(false);

           return view;
       }
     }
}

Problem is with line:

parentActivity.SetSupportActionBar(Toolbar);

As it does not seem to set the action bar and subsequent calls to parentActivity.SupportActionBar fail with NullReferenceException. Any ideas? Do please not that this worked when the Appbar and Toolbar were defined on the Activity rather than the Fragment.

Upvotes: 1

Views: 665

Answers (1)

Igor
Igor

Reputation: 609

If you cannot see the answer, take a break, have a coffee and it will come to you. Since the AppBar and the Toolbar is defined in the fragment XML, I cannot call Activity.FindViewById() to inflate it. The same applies in the above code to AppBar and FAB. Once I refactored the code closer to the above mentioned example I was following (sub-class Fragment provides ResourceId of the fragment layout and base class inflates it), I was able to change the calls:

AppBar = Activity.FindViewById<AppBarLayout>(Resource.Id.main_app_bar);
Fab = Activity.FindViewById<FloatingActionButton>(Resource.Id.fab);
Toolbar = Activity.FindViewById<Toolbar>(Resource.Id.main_tool_bar);

to:

AppBar = FragmentView.FindViewById<AppBarLayout>(Resource.Id.main_app_bar);
Fab = FragmentView.FindViewById<FloatingActionButton>(Resource.Id.fab);
Toolbar = FragmentView.FindViewById<Toolbar>(Resource.Id.main_tool_bar);

where:

FragmentView = this.BindingInflate(FragmentResourceId, null);

everything started to work just fine.

Upvotes: 1

Related Questions