2
votes

I'm building an Android and iOS app using Xamarin Forms.

What I'm simply trying to do is set a background drawable on my Android app for my ListView items. The root view of my ListView items are StackLayout's:

var listView = new ListView
{
    ItemsSource = items,
    ItemTemplate = new DataTemplate(() =>
    {
        return new ViewCell
        {
            View = new StackLayout(...)
        };
    }
};

I know I can access the native element by using a custom renderer:

public class MyEntryRenderer : EntryRenderer
{
    protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
    {
        base.OnElementChanged(e);

        if (e.OldElement == null) {
            var nativeEditText = (EditText)Control;
            ...
        }
    }
}

But I'm not sure how this would work for a StackLayout (or any other layout for that matter).

I first extended StackLayout:

public class ListViewItem : StackLayout
{
}

And I read somewhere that layouts use the VisualElementRenderer, so I tried the following:

public class ListViewItemRenderer : VisualElementRenderer<StackLayout>
{
    protected override void OnElementChanged(ElementChangedEventArgs<StackLayout> e)
    {
        base.OnElementChanged(e);

        // any way to access the native element?
    }
}

But VisualElementRenderer does not seem to give me access to the native element.

So is there any way I can access the native elements of Layout elements? Or maybe there is a different way to simply set a background drawable on layouts within my Android app?

2

2 Answers

3
votes

Even though I still don't know how to access the native element of a layout, the VisualElementRenderer has a method for setting the background drawable on Android (which was exactly what I needed). So I ended up with the following:

protected override void OnElementChanged(ElementChangedEventArgs<StackLayout> e)
{
    base.OnElementChanged(e);
    SetBackgroundDrawable(Resources.GetDrawable(Resource.Drawable.listViewItem));
}
0
votes

I understand you want to hook into an existing Layout renderer and extending it to access the native element with extra capabilities like background image.

Eventually the support for background-image will be supported just like background-colour is, I imagine, across the Layout controls. It may be worth while waiting for this as I can't see why they wouldn't implement these in a later release.

In the mean time you would need something that would work and is quite easy to implement?

Creating the background drawable via inheriting the renderer from a Layout may not be the simplest of solutions therefore, although does have its advantages as you can then re-use easily with the extra functionality across all Layouts for an application.

In your code for ListViewItemRenderer, however, it is inheriting from a Xamarin.Forms control (you specified StackLayout) and have not specified a native, platform dependent, control to be the base for the layout control that would have to match the Xamarin.Forms platform dependent control used.

Each Renderer is tied to a native element. Layout controls will be no different than other custom native control renderers.

For a custom control, you will write a renderer something like the following (note I haven't specified a layout renderer as I haven't had a need to do this yet and am just going from past experience - but similar rules should apply to implementing a renderer for a layout as opposed to a custom control):-

// System.Windows.Controls.Grid in this case is the root native control for a WindowsPhone renderer of MyControl
public class MyControlRenderer : ViewRenderer<MyControlView, System.Windows.Controls.Grid>

There is a simpler approach, however to achieve what you want to do:-

The simpler approach would be instead of inheriting from the Stack Layout control, it would be better to inherit from Grid as the root of the control.

Then you can add an Image control to the Grid and also a Stack Layout for the same Grid Row and Column.

By doing the above you will be able to achieve a background-image across the entire listview item row.