7
votes

I am using a renderer to allow me to set a custom footer in my TableView. The renderer works but I would like to have the capability to set up different footers for the different table sections. For example one footer for table section 0 and another for table section 1, all the way up to table section 5.

Here's the XAML that I am using:

           <!-- <local:ExtFooterTableView x:Name="tableView" Intent="Settings" HasUnevenRows="True">-->
                <TableView x:Name="tableView" Intent="Settings" HasUnevenRows="True">
                <TableSection Title="Cards1">
                    <ViewCell Height="50">
                        <Label Text="Hello1" />
                    </ViewCell>
                    <ViewCell Height="50">
                        <Label Text="Hello2" />
                    </ViewCell>
                </TableSection>
                <TableSection Title="Cards2">
                    <TextCell Height="50" Text="Hello"></TextCell>
                </TableSection>

                </TableSection>
        <!--    </local:ExtFooterTableView>-->
            </TableView>

and here is the C# class and renderer:

public class ExtFooterTableView : TableView
{
    public ExtFooterTableView()
    {
    }
}

and:

   using System;
using Japanese;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;

[assembly: ExportRenderer(typeof(ExtFooterTableView), typeof(Japanese.iOS.ExtFooterTableViewRenderer))]
namespace Japanese.iOS
{
    public class ExtFooterTableViewRenderer : TableViewRenderer
    {
        protected override void OnElementChanged(ElementChangedEventArgs<TableView> e)
        {
            base.OnElementChanged(e);
            if (Control == null)
                return;

            var tableView = Control as UITableView;
            var formsTableView = Element as TableView;
            tableView.WeakDelegate = new CustomFooterTableViewModelRenderer(formsTableView);
        }


        private class CustomFooterTableViewModelRenderer : TableViewModelRenderer
        {
            public CustomFooterTableViewModelRenderer(TableView model) : base(model)
            {
            }

            public override UIView GetViewForFooter(UITableView tableView, nint section)
            {
                Debug.WriteLine("xx");
                if (section == 0)
                {
                    return new UILabel()
                    {
                        // Text = TitleForFooter(tableView, section), // or use some other text here
                        Text = "abc",
                        TextAlignment = UITextAlignment.Left
                        // TextAlignment = NSTextAlignment.NSTextAlignmentJustified
                    };
                }
                else
                {
                    return new UILabel()
                    {
                        // Text = TitleForFooter(tableView, section), // or use some other text here
                        Text = "def",
                        TextAlignment = UITextAlignment.Left
                        // TextAlignment = NSTextAlignment.NSTextAlignmentJustified
                    };
                }
            }

        }
    }
}

The code works but I would like to find out how I can set up a different footer text for different sections in the XAML. Something like this:

From what I see it looks like the code is partly there TitleForFooter(tableView, section) but I am not sure how to use it and how I could set it up. Note that I am not really looking for a view model solution. I would be happy to be simply able to specify the section footer text as part of the TableView XAML.

I'd appreciate if anyone could give me some advice on this.

2

2 Answers

1
votes

First of all, in order to be able to specify the section footer text in XAML - simplest option would be to create a bindable property in TableSection. But as TableSection is sealed, we can't derive it to define our custom bindable properties.

So, the next option is to create a attached bindable property.

public class Ex
{
    public static readonly BindableProperty FooterTextProperty =
        BindableProperty.CreateAttached("FooterText", typeof(string), typeof(Ex), defaultValue: default(string));

    public static string GetFooterText(BindableObject view)
    {
        return (string)view.GetValue(FooterTextProperty);
    }

    public static void SetFooterText(BindableObject view, string value)
    {
        view.SetValue(FooterTextProperty, value);
    }
}

Next step would be to update renderer to retrieve this value for every section:

private class CustomFooterTableViewModelRenderer : TableViewModelRenderer
{
    public CustomFooterTableViewModelRenderer(TableView model) : base(model)
    {
    }

    public override UIView GetViewForFooter(UITableView tableView, nint section)
    {
        return new UILabel()
        {
            Text = TitleForFooter(tableView, section), // or use some other text here
            Font = UIFont.SystemFontOfSize(14),
            ShadowColor = Color.White.ToUIColor(),
            ShadowOffset = new CoreGraphics.CGSize(0, 1),
            TextColor = Color.DarkGray.ToUIColor(),
            BackgroundColor = Color.Transparent.ToUIColor(),
            Opaque = false,
            TextAlignment = UITextAlignment.Center
        };
    }

    //Retrieves the footer text for corresponding section through the attached property
    public override string TitleForFooter(UITableView tableView, nint section)
    {
        var tblSection = View.Root[(int)section];
        return Ex.GetFooterText(tblSection);
    }
}

Sample Usage

<local:ExtFooterTableView x:Name="tableView" Intent="Settings" HasUnevenRows="True">
    <TableSection Title="Cards1" local:Ex.FooterText="Sample description">
        <ViewCell Height="50">
            <Label Margin="20,0,20,0" Text="Hello1" />
        </ViewCell>
        <ViewCell Height="50">
            <Label Margin="20,0,20,0" Text="Hello2" />
        </ViewCell>
    </TableSection>
    <TableSection  Title="Cards2" local:Ex.FooterText="Disclaimer note">
        <TextCell Height="50" Text="Hello"></TextCell>
    </TableSection>
</local:ExtFooterTableView>

enter image description here

1
votes

It is very simple. you need to add the bindable property for pass value from XAML to CustomRenderer in CustomControl like this:

Customer TableView

public class ExtFooterTableView : TableView
{
    public ExtFooterTableView()
    {
    }
}

Xaml control code

<local:ExtFooterTableView x:Name="tableView" Intent="Settings" HasUnevenRows="True">

Renderer class

using System;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using yournamespace;
using System.ComponentModel;

[assembly: ExportRenderer(typeof(ExtFooterTableView), typeof(FooterTableViewRenderer))]
namespace yournamespace
{
    public class FooterTableViewRenderer : TableViewRenderer
    {
        protected override void OnElementChanged(ElementChangedEventArgs<TableView> e)
        {
            base.OnElementChanged(e);
        }


        protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            base.OnElementPropertyChanged(sender, e);

            var view = (ExtFooterTableView)Element;

            if (e.PropertyName == ExtFooterTableView.IntentProperty.PropertyName)
            {
                string intent = view.Intent;
                // Do your stuff for intent property
            }

            if (e.PropertyName == ExtFooterTableView.HasUnevenRowsProperty.PropertyName)
            {
                bool hasUnevenRows = view.HasUnevenRows;
                // Do yout stuff for HasUnevenRow
            }
        }

    }
}