0
votes

I want to have an Android.Widget.RelativeLayout added in a ContentPage. For this I've followed multiple online examples:

Xamarin Forms Custom Renderer for Android not displaying

Adding an "Android.Views.ViewGroup" to a Xamarin XAML page

and others.

But I cannot get it working.

In my shared project I have:

namespace SharedProject
{
  public partial class App : Application
    {

        public App ()
        {
            InitializeComponent();

            MainPage = new NavigationPage(new MainPage());
        }
     ....
    }

space

namespace SharedProject
{
    public class MyCustomViewControl : View
    {
        public MyCustomViewControl()
        {

        }
    }
}

and the MainPage.xaml which is being rendered:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:SharedProject="clr-namespace:SharedProject;assembly=SharedProject"
             x:Class="SharedProject.MainPage">
    <ContentPage.Content>
        <StackLayout>
            <SharedProject:MyCustomViewControl
                                 HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" />
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

and in the MonoAndroid project:

[assembly: ExportRenderer(typeof(MyCustomViewControl), typeof(MyCustomViewRenderer))]
namespace SharedProject.Mobile.Droid
{
    public class MyCustomViewRenderer : ViewRenderer<MyCustomViewControl, RelativeLayout>
    {
        public MyCustomViewRenderer(Context context) : base(context)
        {

        }

        private Android.Widget.RelativeLayout rlMainContainer;

        protected override void OnElementChanged(ElementChangedEventArgs<MyCustomViewControl> e)
        {
            base.OnElementChanged(e);

            if (e.OldElement != null || Element == null)
            {
                return;
            }

            rlMainContainer = new RelativeLayout(Context);
            rlMainContainer.SetMinimumHeight(50);
            rlMainContainer.SetMinimumWidth(100);
            rlMainContainer.LayoutParameters = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MatchParent, RelativeLayout.LayoutParams.MatchParent);

            if (Control == null)
                SetNativeControl(rlMainContainer);

            MainActivity.instance.setActiveReader(Control);
        }
    }
}

And in my MainActivity.OnCreate I have:

protected override void OnCreate(Bundle savedInstanceState)
        {
            TabLayoutResource = Resource.Layout.Tabbar;
            ToolbarResource = Resource.Layout.Toolbar;

            base.OnCreate(savedInstanceState);
            global::Xamarin.Forms.Forms.Init(this, savedInstanceState);


            instance = this;

            LoadApplication(new App());

I was expecting that when the MainPage is being rendered, the rlMainContainer would be also added to it as per the MainPage.xaml and OnElementChanged, but nothing inside MyCustomViewRenderer is being requested(no breakpoint hits).

What am I doing wrong?

3

3 Answers

1
votes

I just plugged your code into a new project and it worked fine as long as I was explicit about which RelativeLayout I wanted to use. There are 2 possible, Xamarin.Forms.RelativeLayout and Android.Widget.Relative layout. I assume you want the latter, but I don't see it being fully qualified, and since I assume you have using statements for both Xamarin.Forms (needed for the ExportRenderer attribute) and Android.Widget (needed for the RelativeLayout) it is not clear that you are using the correct RelativeLayout in all places.

There is also the question of whether you are using the Xamarin.Forms.Platform.Android.AppCompat.ViewRenderer or the Xamarin.Forms.Platform.Android.ViewRenderer. Most use AppCompat as the default Xam.Forms template uses the FormsAppCompatActivity. So assuming you are using AppCompat, the following full source code (with full type qualifications as necessary) for the custom renderer is working on my end:

using System;
using Android.Content;
using TestRelLayout;
using TestRelLayout.Droid;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;

[assembly: ExportRenderer(typeof(MyCustomViewControl), typeof(MyCustomViewRenderer))]
namespace TestRelLayout.Droid
{
    public class MyCustomViewRenderer : Xamarin.Forms.Platform.Android.AppCompat.ViewRenderer<MyCustomViewControl, Android.Widget.RelativeLayout>
    {
        public MyCustomViewRenderer(Context context) : base(context)
        {
        }

        private Android.Widget.RelativeLayout rlMainContainer;


        protected override void OnElementChanged(ElementChangedEventArgs<MyCustomViewControl> e)
        {
            base.OnElementChanged(e);

            if (e.OldElement != null || Element == null)
            {
                return;
            }

            rlMainContainer = new Android.Widget.RelativeLayout(Context);
            rlMainContainer.SetMinimumHeight(50);
            rlMainContainer.SetMinimumWidth(100);
            rlMainContainer.LayoutParameters = new Android.Widget.RelativeLayout.LayoutParams(Android.Widget.RelativeLayout.LayoutParams.MatchParent, Android.Widget.RelativeLayout.LayoutParams.MatchParent);
            // set the background color to make it easy to see if renderer is working               
            rlMainContainer.SetBackgroundColor(
                        Android.Graphics.Color.Aquamarine);

            if (Control == null)
                SetNativeControl(rlMainContainer);

            // did not bother to set this up in my MainActivity
            //MainActivity.instance.setActiveReader(Control);
        }
    }
}
0
votes

Why are you trying to render a native Android RelativeLayout? There are build in options in Xamarin.Forms. Look at this documentation

0
votes

After a lot of file comparison(my project and the Microsoft sample one), I found the issue to be related to the

MainPage = new NavigationPage(new MainPage());.

To solve it I just removed NavigationPage wrapper.

MainPage = new MainPage();.

Do not know yet why this happened, but if anyone knows please edit my answer with an explanation as well.

Edit: The Renderer works with NavigationPage as well, but only after the OnCreate method finishes executing.