Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom renderer for Android CardView not showing Forms component content

I've created a custom component which extends ContentView and renderer which renders to a CardView on Android.

The problem I am facing is that the Forms content is rendered below the CardView. On KitKat this does not occur, but I think the CardView implementation is not the same as on Lollipop or newer.

Setting the background color of the CardView to transparent (0x00000000) reveals the content below the CardView.

The forms component:

using Xamarin.Forms;

namespace CodeFest
{
    public class NativeClientProfile : ContentView
    {
        public NativeClientProfile()
        {
            var grid = new Grid
            {
                RowDefinitions = new RowDefinitionCollection {new RowDefinition()},
                ColumnDefinitions = new ColumnDefinitionCollection {new ColumnDefinition(), new ColumnDefinition()}
            };
            grid.Children.Add(new Label {Text = "FSP No"}, 0, 0);
            grid.Children.Add(new Label {Text = "12345", HorizontalTextAlignment = TextAlignment.Center}, 1, 0);
            grid.Children.Add(new Label {Text = "Risk"}, 0, 1);
            grid.Children.Add(
                new Label {Text = "Low", TextColor = Color.Green, HorizontalTextAlignment = TextAlignment.Center}, 1, 1);
            var item = new Label
            {
                Text = "Foo bar",
                HorizontalTextAlignment = TextAlignment.Center,
                FontSize = 30,
                FontAttributes = FontAttributes.Bold
            }; 
            Content = new StackLayout
            {
                Children =
                {
                    item,
                    new Label
                    {
                        Text = "Financial Services Provider",
                        HorizontalTextAlignment = TextAlignment.Center
                    },
                    grid
                }
            };
        }
    }
}

The custom renderer:

using Android.Support.V7.Widget;
using Android.Text;
using Android.Views;
using CodeFest;
using CodeFest.Droid.ComponentRenderers;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;

[assembly: ExportRenderer(typeof(NativeClientProfile), typeof(NativeClientProfileRenderer))]
namespace CodeFest.Droid.ComponentRenderers
{
    class NativeClientProfileRenderer : ViewRenderer<NativeClientProfile, CardView>
    {
        protected override void OnElementChanged(ElementChangedEventArgs<NativeClientProfile> elementChangedEventArgs)
        {
            var view = new CardView(Context);
            //view.SetCardBackgroundColor(0x00000000);
            SetNativeControl(view);
        }
    }
}

I am looking for an example of how to correctly render forms components within a CardView custom renderer.

like image 665
Justin Avatar asked Oct 06 '16 08:10

Justin


1 Answers

You can use a Frame as base class instead of ContentView. This has the advantage, that you can use the existing FrameRenderer of Xamarin.Forms.Platform.Android.AppCompat which is already using a CardView. (see: FrameRenderer.cs).

FrameRenderer declaration

public class FrameRenderer : CardView, IVisualElementRenderer, AView.IOnClickListener, AView.IOnTouchListener

Renderer

class NativeClientProfileRenderer : Xamarin.Forms.Platform.Android.AppCompat.FrameRenderer
{
    protected override void OnElementChanged(ElementChangedEventArgs<Frame> e)
    {
        base.OnElementChanged(e);
    }
}

NativeClientProfile

public class NativeClientProfile : Frame
{
    public NativeClientProfile()
    {
        // your stuff...
        Content = new StackLayout
        {
            Children =
            {
                item,
                new Label
                {
                    Text = "Financial Services Provider",
                    HorizontalTextAlignment = TextAlignment.Center
                },
                grid
            }
        };
    }
}

Discussion

The renderer shows you what it needs if you really want to do it manually. Using the FrameRenderer makes your code dependent on the implementation of Xamarin. If they ever change the type of view that is rendered for a Frame it will break your App. But if you have a look at the implementation of the FrameRenderer, I'd try to avoid creating it completely from scratch (simple risk vs. effort evaluation).

like image 170
Sven-Michael Stübe Avatar answered Dec 05 '22 14:12

Sven-Michael Stübe