How do I create this button with Gradient Effect in Xamarin Forms using Renderer ?
Now it is possible with Xamarin forms 4.8 with new features like gradient brushes and drag and drop features.
Check out this link => https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/brushes/
You can add a gradient background for any element such as button, frame, boxview etc..
Example code for Button:
<Button Text="Submit Order" CornerRadius="5" TextColor="White">
<Button.Background>
<LinearGradientBrush EndPoint="1,0">
<GradientStop Color="Yellow" Offset="0.1" />
<GradientStop Color="Green" Offset="1.0" />
</LinearGradientBrush>
</Button.Background>
</Button>
The output:
In xamarin you can't add gradient colors as a built in feature. You have to create a different rendering feature. This link will guide you.
In Xamarin Forms Craets
public class GradientColorStack:StackLayout
{
public Color StartColor { get; set; }
public Color EndColor { get; set; }
}
And then Renderer Android
public class GradientColorStackRenderer : VisualElementRenderer<StackLayout>
{
private Color StartColor { get; set; }
private Color EndColor { get; set; }
protected override void DispatchDraw(global::Android.Graphics.Canvas canvas)
{
#region for Horizontal Gradient
var gradient = new Android.Graphics.LinearGradient(0, 0, Width, 0,
#endregion
this.StartColor.ToAndroid(),
this.EndColor.ToAndroid(),
Android.Graphics.Shader.TileMode.Mirror);
var paint = new Android.Graphics.Paint()
{
Dither = true,
};
paint.SetShader(gradient);
canvas.DrawPaint(paint);
base.DispatchDraw(canvas);
}
protected override void OnElementChanged(ElementChangedEventArgs<Frame> e)
{
base.OnElementChanged(e);
if (e.OldElement != null || Element == null)
{
return;
}
try
{
var stack = e.NewElement as GradientColorStack;
this.StartColor = stack.StartColor;
this.EndColor = stack.EndColor;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(#"ERROR:", ex.Message);
}
}
}
And In Ios Project Rendering
public class GradientColorStackRenderer : VisualElementRenderer<Frame>
{
public override void Draw(CGRect rect)
{
base.Draw(rect);
GradientColorFrame stack = (GradientColorStack)this.Element;
CGColor startColor = stack.StartColor.ToCGColor();
CGColor endColor = stack.EndColor.ToCGColor();
#region for Vertical Gradient
var gradientLayer = new CAGradientLayer();
#endregion
gradientLayer.Frame = rect;
gradientLayer.Colors = new CGColor[] { startColor, endColor
};
NativeView.Layer.InsertSublayer(gradientLayer, 0);
}
}
Now you can Use in PCL Project Like this
<local:GradientColorStack StartColor="#DF596C" EndColor="#FFB239" >
</local:GradientColorStack>
Should you want to add it in a Styles file, the following worked for me:
Reference Post
<Style TargetType="Button">
<Setter Property="Background">
<Setter.Value>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
<GradientStop Color="White" Offset="0.6"/>
<GradientStop Color="Blue" Offset="1.0"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Style>
Related
I am trying to load a customized slider control in a listview (with accordeon behaviour). When the View loads all the listview elements are collapsed so the slider control visibility is false. I observed that the overriden Draw method within the ios renderer is not called while the control is not visible so I end up having the native control within my listview.
I have reproduced the issue in a separate project:
I have the IOS custom renderer:
public class CustomGradientSliderRenderer : SliderRenderer
{
public CGColor StartColor { get; set; }
public CGColor CenterColor { get; set; }
public CGColor EndColor { get; set; }
protected override void OnElementChanged(ElementChangedEventArgs<Slider> e)
{
if (Control == null)
{
var customSlider = e.NewElement as CustomGradientSlider;
StartColor = customSlider.StartColor.ToCGColor();
CenterColor = customSlider.CenterColor.ToCGColor();
EndColor = customSlider.EndColor.ToCGColor();
var slider = new SlideriOS
{
Continuous = true,
Height = (nfloat)customSlider.HeightRequest
};
SetNativeControl(slider);
}
base.OnElementChanged(e);
}
public override void Draw(CGRect rect)
{
base.Draw(rect);
if (Control != null)
{
Control.SetMinTrackImage(CreateGradientImage(rect.Size), UIControlState.Normal);
}
}
void OnControlValueChanged(object sender, EventArgs eventArgs)
{
((IElementController)Element).SetValueFromRenderer(Slider.ValueProperty, Control.Value);
}
public UIImage CreateGradientImage(CGSize rect)
{
var gradientLayer = new CAGradientLayer()
{
StartPoint = new CGPoint(0, 0.5),
EndPoint = new CGPoint(1, 0.5),
Colors = new CGColor[] { StartColor, CenterColor, EndColor },
Frame = new CGRect(0, 0, rect.Width, rect.Height),
CornerRadius = 5.0f
};
UIGraphics.BeginImageContext(gradientLayer.Frame.Size);
gradientLayer.RenderInContext(UIGraphics.GetCurrentContext());
var image = UIGraphics.GetImageFromCurrentImageContext();
UIGraphics.EndImageContext();
return image.CreateResizableImage(UIEdgeInsets.Zero);
}
}
public class SlideriOS : UISlider
{
public nfloat Height { get; set; }
public override CGRect TrackRectForBounds(CGRect forBounds)
{
var rect = base.TrackRectForBounds(forBounds);
return new CGRect(rect.X, rect.Y, rect.Width, Height);
}
}
The View with codebehind:
Main.xaml:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
x:Class="GradientSlider.MainPage"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:GradientSlider">
<ContentPage.Content>
<Grid>
<StackLayout x:Name="SliderContainer">
<local:CustomGradientSlider
x:Name="mySlider"
CenterColor="#feeb2f"
CornerRadius="16"
EndColor="#ba0f00"
HeightRequest="20"
HorizontalOptions="FillAndExpand"
Maximum="10"
Minimum="0"
StartColor="#6bab29"
VerticalOptions="CenterAndExpand"
MaximumTrackColor="Transparent"
ThumbColor="green"
/>
<Label x:Name="lblText" Text="txt"
VerticalOptions="Center" HorizontalOptions="Center"/>
</StackLayout>
<Button Text="Magic" Clicked="Button_Tapped" WidthRequest="100" HeightRequest="50" VerticalOptions="Center" HorizontalOptions="Center"/>
</Grid>
</ContentPage.Content>
</ContentPage>
Main.xaml.cs:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace GradientSlider
{
public partial class MainPage : ContentPage, INotifyPropertyChanged
{
public MainPage()
{
InitializeComponent();
SliderContainer.IsVisible = false;
}
void Button_Tapped(object sender,ClickedEventArgs a)
{
SliderContainer.IsVisible = !SliderContainer.IsVisible;
}
}
}
So in the scenario above you can see that when I load the main.xaml the control is invisible (SliderContainer.IsVisible = false;) in this case I get a native slider control and not my custom one. If I change in the constructor SliderContainer.IsVisible = true; then I get my custom control.
After an investigation I realised that if the control is not visible when the view loads the public override void Draw(CGRect rect) is not called. I could not find any solution to trigger the Draw method while the control is invisible.
Anybody has an idea how to load a custom renderer correctly while the control is not visible ?
Thank you!
Assuming the renderer is overriding OnElementPropertyChanged:
protected override void OnElementChanged(ElementChangedEventArgs<MyFormsSlider> e)
{
if (e.NewElement != null)
{
if (Control == null)
{
// Instantiate the native control and assign it to the Control property with
// the SetNativeControl method
SetNativeControl(new MyNativeControl(...
...
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
//assuming MyFormsSlider derives from View / VisualElement; the latter has IsVisibleProperty
if (e.PropertyName == MyFormsSlider.IsVisibleProperty.PropertyName)
{
//Control is the control set with SetNativeControl
Control. ...
}
...
}
I am trying to add a WebView control inside a ItemTemplate and set the height of the row. I know that I can't have the webview control scroll so I need to setting the height to the correct size to display the full html content. I have created an IValueConverter class that I was thinking can return the correct height needed but what height value to return depending on how long the content is?
Anyway I can load the webview and get the height needed to display the full content I get -1 for height in my writeline?
XAML Code
<telerikListView:ListViewTemplateCell>
<Grid BackgroundColor="{StaticResource LightBlueColor}"
Padding="10">
<telerikPrimitives:RadBorder Padding="10"
HorizontalOptions="Fill"
BorderThickness="2"
BorderColor="{StaticResource DarkBlueColor}"
BackgroundColor="White">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="50" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<!--<RowDefinition Height="*"/>-->
<RowDefinition Height="{Binding AssetItem.Description, Converter={StaticResource DescriptionToHeightConverter}}" />
</Grid.RowDefinitions>
<!--<Grid Grid.Row="0" Grid.Column="0">
<HtmlLabelControl:HtmlLabel
Text="{Binding AssetItem.Description}"
HeightRequest="100"/>-->
<WebView HeightRequest="800" MinimumHeightRequest="300" HorizontalOptions="FillAndExpand">
<WebView.Source>
<HtmlWebViewSource Html="{Binding AssetItem.Description}"/>
</WebView.Source>
</WebView>
<!--</Grid>-->
<!--<WebView Grid.Column="0" Grid.Row="0" HeightRequest="200" HorizontalOptions="FillAndExpand">
<WebView.Source>
<HtmlWebViewSource Html="{Binding AssetItem.Description}"/>
</WebView.Source>
</WebView>-->
<!--<Label Text="{Binding AssetItem.Description}"
TextColor="{StaticResource GrayTextColor}"
Grid.Row="0"
Grid.Column="0"/>-->
<!--Star-->
<telerikPrimitives:RadPath
x:Name="path"
Grid.Row="0"
Grid.Column="1"
WidthRequest="40"
HeightRequest="35"
StrokeThickness="2"
VerticalOptions="Start"
Fill="{Binding AssetItem.IsBookmark, Converter={StaticResource FavFillColorConverter}}"
Stroke="#3e7dc5"
Geometry="{x:Static telerikInput:Geometries.Star}">
<telerikPrimitives:RadPath.GestureRecognizers>
<TapGestureRecognizer NumberOfTapsRequired="1" Tapped="BookmarkCommand" CommandParameter="{Binding AssetItem.AssetId}" />
</telerikPrimitives:RadPath.GestureRecognizers>
</telerikPrimitives:RadPath>
</Grid>
<!--</Grid>-->
</telerikPrimitives:RadBorder>
</Grid>
</telerikListView:ListViewTemplateCell>
CS Converter Logic
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var description = value as string;
//WebView wv = new WebView();
//wv.Source = description;
HtmlWebViewSource HtmlSource = new HtmlWebViewSource();
HtmlSource.Html = description;
WebView webView = new WebView()
{
Source = HtmlSource
};
Debug.WriteLine($"Web View Height: {webView.Height}");
if (!string.IsNullOrEmpty(description))
{
if (description.Length == 300)
{
return 50;
}
}
return 300;
}
Test code
HtmlWebViewSource HtmlSource = new HtmlWebViewSource();
HtmlSource.Html = "<html><body><div><h1>MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM</h1></div></body></html>";
WebView webView = new WebView()
{
Source = HtmlSource
};
string htmlheight = "";
Task.Run(async () => {
try
{
htmlheight = await webView.EvaluateJavaScriptAsync("document.body.scrollHeight");
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
});
//WebView_NavigatedAsync(webView);
Debug.WriteLine($"Web View Height: {htmlheight}");
If you want to get the height of the html .You can implement by using Custom Renderer
in Forms
public MainPage()
{
InitializeComponent();
HtmlWebViewSource HtmlSource = new HtmlWebViewSource();
HtmlSource.Html = #"<html><body>
<h1>Xamarin.Forms</h1>
<p>Welcome to WebView.</p>
</body></html>";
Webview webView = new Webview()
{
WidthRequest = 100,
HeightRequest = 20,
Source =HtmlSource
};
MessagingCenter.Subscribe<Object, float>(this,"webview_loaded",(sender,value)=>{
Console.WriteLine(value); //value is the height of html
});
Content = new StackLayout
{
Children =
{
webView,
},
VerticalOptions = LayoutOptions.FillAndExpand,
HorizontalOptions=LayoutOptions.FillAndExpand
};
}
in iOS project
using Foundation;
using UIKit;
using CoreGraphics;
using xxx;
using xxx.iOS;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
[assembly:ExportRenderer(typeof(WebView),typeof(MyWebViewRenderer))]
namespace App7.iOS
{
public class MyWebViewRenderer:WebViewRenderer,IUIWebViewDelegate
{
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
if(NativeView!=null)
{
// WeakDelegate = this;
}
}
[Export("webViewDidFinishLoad:")]
public void LoadingFinished(UIWebView webView)
{
string htmlHeight = webView.EvaluateJavascript("document.body.scrollHeight");
float height = float.Parse(htmlHeight);
MessagingCenter.Send<System.Object, float>(this, "webview_loaded", height);
}
}
}
in Android
using Android.Content;
using Android.Webkit;
using Android.Widget;
using xxx;
using xxx.Droid;
using Java.Lang;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(Xamarin.Forms.WebView), typeof(MyWebViewRenderer))]
namespace xxx.Droid
{
public class MyWebViewRenderer:WebViewRenderer
{
public MyWebViewRenderer(Context context):base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)
{
base.OnElementChanged(e);
if(Control!=null)
{
Android.Webkit.WebView webview =(Android.Webkit.WebView) Control;
WebSettings settings = webview.Settings;
settings.JavaScriptEnabled = true;
webview.SetWebViewClient(new JavascriptWebViewClient());
}
}
}
public class JavascriptWebViewClient : WebViewClient
{
public override void OnPageFinished(Android.Webkit.WebView view, string url)
{
base.OnPageFinished(view, url);
view.EvaluateJavascript("javascript:document.body.scrollHeight;", new EvaluateBack() );
}
}
class EvaluateBack : Java.Lang.Object, IValueCallback
{
public void OnReceiveValue(Java.Lang.Object value)
{
string htmlHeight = value.ToString();
float height = float.Parse(htmlHeight);
MessagingCenter.Send<System.Object, float>(this,"webview_loaded",height);
}
}
}
Notes: in your test code ,you get call the method when the html didn't finish loading ,so the result is -1.
I need to create a triangle at the corner of a label/frame like the pic below with a number/small text in it.But just a way to draw the corner would be a great start.
How Can you do you do that ?
Any sample anywhere. Many thanks
Instead Using Plugin for just Triangle you can just use BoxView and rotate it with 135 and give negative margin so half portion will only get visible.
I achieved this using NControl https://github.com/chrfalch/NControl
public class DiagonalControl : NControlView
{
public static readonly BindableProperty CornerRadiusBindableProperty =
BindableProperty.Create(nameof(CornerRadius), typeof(int), typeof(DiagonalControl), 8);
private Xamarin.Forms.Color _backgroundColor;
public DiagonalControl()
{
base.BackgroundColor = Xamarin.Forms.Color.Transparent;
}
public new Xamarin.Forms.Color BackgroundColor
{
get
{
return _backgroundColor;
}
set
{
_backgroundColor = value;
Invalidate();
}
}
public int CornerRadius
{
get
{
return (int)GetValue(CornerRadiusBindableProperty);
}
set
{
SetValue(CornerRadiusBindableProperty, value);
}
}
public override void Draw(ICanvas canvas, Rect rect)
{
base.Draw(canvas, rect);
canvas.FillPath(new PathOp[] {
new MoveTo (0,0),
new LineTo (rect.Width, rect.Height),
new LineTo (rect.Width, 0),
new ClosePath ()
}, new NGraphics.Color((Xamarin.Forms.Color.White).R, (Xamarin.Forms.Color.White).G, (Xamarin.Forms.Color.White).B));
}
}
Then in the XAML use it like
<customviews:DiagonalControl
x:FieldModifier="Public"
HeightRequest="50"
HorizontalOptions="End"
VerticalOptions="Start"
WidthRequest="50" />
Draw path directly in xaml from Xamarin.Forms 4.7.0
(bump into the same request, and have an update for others)
<Path
HorizontalOptions="End"
VerticalOptions="Start"
Data="M 0,0 L 36,0 36,36Z"
Fill="#70a33e"
Stroke="Gray" />
And more details:
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/shapes/
https://devblogs.microsoft.com/xamarin/xamarin-forms-shapes-and-paths/
UPDATED:
So, I'm unable to create IOS custom height ProgressBar.
I use the latest version of Xamarin.Forms.
.cs file:
public class SplashScreenProgressBar : ProgressBar
{
public static readonly BindableProperty TintColorProperty =
BindableProperty.Create<CustomProgressBar, Color>( p => p.TintColor, Color.Green);
public Color TintColor
{
get { return (Color) GetValue(TintColorProperty); }
set { SetValue(TintColorProperty, value); }
}
public static readonly BindableProperty HeightExtendedProperty =
BindableProperty.Create("HeightExtended", typeof(double), typeof(SplashScreenProgressBar), 10.0);
public double HeightExtended
{
get { return (double) GetValue(HeightExtendedProperty); }
set { SetValue(HeightExtendedProperty, value); }
}
public static readonly BindableProperty BackgroundColorExtendedProperty =
BindableProperty.Create("BackgroundColorExtended", typeof(Color), typeof(SplashScreenProgressBar),
Color.White);
public Color BackgroundColorExtended
{
get { return (Color) GetValue(BackgroundColorExtendedProperty); }
set { SetValue(BackgroundColorExtendedProperty, value); }
}
}
Here is iOS renderer:
public class SplashScreenProgressBarRenderer : ProgressBarRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<ProgressBar> e)
{
base.OnElementChanged(e);
var element = (SplashScreenProgressBar)Element;
this.Control.ProgressTintColor = element.TintColor.ToUIColor();
this.Control.TrackTintColor = element.BackgroundColorExtended.ToUIColor();
}
public override void LayoutSubviews()
{
base.LayoutSubviews();
var element = (SplashScreenProgressBar)Element;
var X = 1.0f;
var Y = (System.nfloat)element.HeightExtended;
CGAffineTransform transform = CGAffineTransform.MakeScale(X, Y);
this.Control.Transform = transform;
this.Control.ClipsToBounds = true;
this.Control.Layer.MasksToBounds = true;
this.Control.CornerRadius = 5;
}
}
xaml file:
<StackLayout HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" BackgroundColor="White" >
<StackLayout HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" Margin="50" BackgroundColor="White" >
<views:SplashScreenProgressBar x:Name="Progress"
TintColor="#5FA5F9"
HorizontalOptions="FillAndExpand"
VerticalOptions="Center"
BackgroundColorExtended="#FFF" />
</StackLayout>
</StackLayout>
But this way doesn't work.
I googled and tried almost all samples which I've found, but nothing happened.
Screenshot:
As you see on the screenshot corner radius is applied to ProgressBar, but height(scale) isn't applied.
In PCL
StackLayout is overlapped with status bar.
Add Margin on it.
<StackLayout Margin="50" xxxxx
In Renderer
ClipsToBounds ,Layer.MasksToBounds ,Layer.CornerRadius should be set on the Control not the Renderer
this.Control.Transform = transform;
this.Control.ClipsToBounds = true;
this.Control.Layer.MasksToBounds = true;
this.Control.Layer.CornerRadius = 5;
When use the custom renderer in ios, it always occupy the whole area of parent element. So, u need to update the progress bar frame once again in layoutsubview.
bool is rendered;
public override void LayoutSubviews()
{
if(!rendered)
{
Frame = new CGRect(x,y,width,height);
setNeedsdisplay
}
rendered=true;
}
So, I spent a lot of hours to researching and investigation.
And seems there xamarin.forms iOS bug for progress bar rounded corners.
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.
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>
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
}
}
}
}