diff --git a/Ooui.Forms/Controls/LinkLabel.cs b/Ooui.Forms/Controls/LinkLabel.cs
new file mode 100644
index 0000000..5371101
--- /dev/null
+++ b/Ooui.Forms/Controls/LinkLabel.cs
@@ -0,0 +1,20 @@
+using System;
+using Xamarin.Forms;
+
+namespace Ooui.Forms
+{
+ public class LinkLabel : Xamarin.Forms.Label
+ {
+ public static readonly BindableProperty HRefProperty = BindableProperty.Create ("HRef", typeof (string),
+ typeof (LinkView), string.Empty, BindingMode.OneWay, null, null, null, null);
+
+ public string HRef {
+ get { return (string)base.GetValue (HRefProperty); }
+ set { base.SetValue (HRefProperty, value); }
+ }
+
+ public LinkLabel ()
+ {
+ }
+ }
+}
diff --git a/Ooui.Forms/Controls/LinkView.cs b/Ooui.Forms/Controls/LinkView.cs
new file mode 100644
index 0000000..fd51d53
--- /dev/null
+++ b/Ooui.Forms/Controls/LinkView.cs
@@ -0,0 +1,20 @@
+using System;
+using Xamarin.Forms;
+
+namespace Ooui.Forms
+{
+ public class LinkView : ContentView
+ {
+ public static readonly BindableProperty HRefProperty = BindableProperty.Create ("HRef", typeof (string),
+ typeof (LinkView), string.Empty, BindingMode.OneWay, null, null, null, null);
+
+ public string HRef {
+ get { return (string)base.GetValue (HRefProperty); }
+ set { base.SetValue (HRefProperty, value); }
+ }
+
+ public LinkView ()
+ {
+ }
+ }
+}
diff --git a/Ooui.Forms/Exports.cs b/Ooui.Forms/Exports.cs
index 04c82e6..1904bdd 100644
--- a/Ooui.Forms/Exports.cs
+++ b/Ooui.Forms/Exports.cs
@@ -3,23 +3,25 @@ using Ooui.Forms;
using Ooui.Forms.Renderers;
using Xamarin.Forms;
-[assembly: Dependency(typeof(ResourcesProvider))]
-[assembly: ExportRenderer(typeof(ActivityIndicator), typeof(ActivityIndicatorRenderer))]
-[assembly: ExportRenderer(typeof(BoxView), typeof(BoxRenderer))]
-[assembly: ExportRenderer(typeof(Button), typeof(ButtonRenderer))]
-[assembly: ExportRenderer(typeof(DatePicker), typeof(DatePickerRenderer))]
-[assembly: ExportRenderer(typeof(Editor), typeof(EditorRenderer))]
-[assembly: ExportRenderer(typeof(Entry), typeof(EntryRenderer))]
-[assembly: ExportRenderer(typeof(Frame), typeof(FrameRenderer))]
-[assembly: ExportRenderer(typeof(Image), typeof(ImageRenderer))]
-[assembly: ExportRenderer(typeof(Label), typeof(LabelRenderer))]
-[assembly: ExportRenderer(typeof(ProgressBar), typeof(ProgressBarRenderer))]
-[assembly: ExportRenderer(typeof(SearchBar), typeof(SearchBarRenderer))]
-[assembly: ExportRenderer(typeof(Switch), typeof(SwitchRenderer))]
-[assembly: ExportRenderer(typeof(TimePicker), typeof(TimePickerRenderer))]
-[assembly: ExportImageSourceHandler(typeof(FileImageSource), typeof(FileImageSourceHandler))]
-[assembly: ExportImageSourceHandler(typeof(StreamImageSource), typeof(StreamImagesourceHandler))]
-[assembly: ExportImageSourceHandler(typeof(UriImageSource), typeof(ImageLoaderSourceHandler))]
+[assembly: Dependency (typeof (ResourcesProvider))]
+[assembly: ExportRenderer (typeof (ActivityIndicator), typeof (ActivityIndicatorRenderer))]
+[assembly: ExportRenderer (typeof (BoxView), typeof (BoxRenderer))]
+[assembly: ExportRenderer (typeof (Button), typeof (ButtonRenderer))]
+[assembly: ExportRenderer (typeof (DatePicker), typeof (DatePickerRenderer))]
+[assembly: ExportRenderer (typeof (Editor), typeof (EditorRenderer))]
+[assembly: ExportRenderer (typeof (Entry), typeof (EntryRenderer))]
+[assembly: ExportRenderer (typeof (Frame), typeof (FrameRenderer))]
+[assembly: ExportRenderer (typeof (Image), typeof (ImageRenderer))]
+[assembly: ExportRenderer (typeof (Label), typeof (LabelRenderer))]
+[assembly: ExportRenderer (typeof (LinkLabel), typeof (LinkLabelRenderer))]
+[assembly: ExportRenderer (typeof (LinkView), typeof (LinkViewRenderer))]
+[assembly: ExportRenderer (typeof (ProgressBar), typeof (ProgressBarRenderer))]
+[assembly: ExportRenderer (typeof (SearchBar), typeof (SearchBarRenderer))]
+[assembly: ExportRenderer (typeof (Switch), typeof (SwitchRenderer))]
+[assembly: ExportRenderer (typeof (TimePicker), typeof (TimePickerRenderer))]
+[assembly: ExportImageSourceHandler (typeof (FileImageSource), typeof (FileImageSourceHandler))]
+[assembly: ExportImageSourceHandler (typeof (StreamImageSource), typeof (StreamImagesourceHandler))]
+[assembly: ExportImageSourceHandler (typeof (UriImageSource), typeof (ImageLoaderSourceHandler))]
namespace Ooui.Forms
{
diff --git a/Ooui.Forms/Ooui.Forms.csproj b/Ooui.Forms/Ooui.Forms.csproj
index 8bcdc99..cacc1d4 100644
--- a/Ooui.Forms/Ooui.Forms.csproj
+++ b/Ooui.Forms/Ooui.Forms.csproj
@@ -24,6 +24,7 @@
+
diff --git a/Ooui.Forms/Renderers/LinkLabelRenderer.cs b/Ooui.Forms/Renderers/LinkLabelRenderer.cs
new file mode 100644
index 0000000..3d7fe61
--- /dev/null
+++ b/Ooui.Forms/Renderers/LinkLabelRenderer.cs
@@ -0,0 +1,165 @@
+using System;
+using System.ComponentModel;
+using Ooui.Forms.Extensions;
+using Xamarin.Forms;
+
+namespace Ooui.Forms.Renderers
+{
+ public class LinkLabelRenderer : ViewRenderer
+ {
+ SizeRequest _perfectSize;
+
+ bool _perfectSizeValid;
+
+ public override SizeRequest GetDesiredSize (double widthConstraint, double heightConstraint)
+ {
+ if (!_perfectSizeValid) {
+ var size = Element.Text.MeasureSize (Element.FontFamily, Element.FontSize, Element.FontAttributes);
+ size.Width = Math.Ceiling (size.Width);
+ size.Height = Math.Ceiling (size.Height * 1.4);
+ _perfectSize = new SizeRequest (size, size);
+ _perfectSizeValid = true;
+ }
+
+ var widthFits = widthConstraint >= _perfectSize.Request.Width;
+ var heightFits = heightConstraint >= _perfectSize.Request.Height;
+
+ if (widthFits && heightFits)
+ return _perfectSize;
+
+ var result = base.GetDesiredSize (widthConstraint, heightConstraint);
+ var tinyWidth = Math.Min (10, result.Request.Width);
+ result.Minimum = new Size (tinyWidth, result.Request.Height);
+
+ if (widthFits || Element.LineBreakMode == LineBreakMode.NoWrap)
+ return result;
+
+ bool containerIsNotInfinitelyWide = !double.IsInfinity (widthConstraint);
+
+ if (containerIsNotInfinitelyWide) {
+ bool textCouldHaveWrapped = Element.LineBreakMode == LineBreakMode.WordWrap || Element.LineBreakMode == LineBreakMode.CharacterWrap;
+ bool textExceedsContainer = result.Request.Width > widthConstraint;
+
+ if (textExceedsContainer || textCouldHaveWrapped) {
+ var expandedWidth = Math.Max (tinyWidth, widthConstraint);
+ result.Request = new Size (expandedWidth, result.Request.Height);
+ }
+ }
+
+ return result;
+ }
+
+ protected override void OnElementChanged (ElementChangedEventArgs e)
+ {
+ if (e.NewElement != null) {
+ if (Control == null) {
+ SetNativeControl (new Anchor ());
+ }
+
+ UpdateHRef ();
+
+ UpdateText ();
+ UpdateTextColor ();
+ UpdateFont ();
+
+ UpdateLineBreakMode ();
+ UpdateAlignment ();
+ }
+
+ base.OnElementChanged (e);
+ }
+
+ protected override void OnElementPropertyChanged (object sender, PropertyChangedEventArgs e)
+ {
+ base.OnElementPropertyChanged (sender, e);
+
+ if (Control == null)
+ return;
+
+ if (e.PropertyName == Ooui.Forms.LinkLabel.HRefProperty.PropertyName)
+ UpdateHRef ();
+ else if (e.PropertyName == Xamarin.Forms.Label.HorizontalTextAlignmentProperty.PropertyName)
+ UpdateAlignment ();
+ else if (e.PropertyName == Xamarin.Forms.Label.VerticalTextAlignmentProperty.PropertyName)
+ UpdateAlignment ();
+ else if (e.PropertyName == Xamarin.Forms.Label.TextColorProperty.PropertyName)
+ UpdateTextColor ();
+ else if (e.PropertyName == Xamarin.Forms.Label.FontProperty.PropertyName)
+ UpdateFont ();
+ else if (e.PropertyName == Xamarin.Forms.Label.TextProperty.PropertyName)
+ UpdateText ();
+ else if (e.PropertyName == Xamarin.Forms.Label.FormattedTextProperty.PropertyName)
+ UpdateText ();
+ else if (e.PropertyName == Xamarin.Forms.Label.LineBreakModeProperty.PropertyName)
+ UpdateLineBreakMode ();
+ }
+
+ protected override void SetBackgroundColor (Xamarin.Forms.Color color)
+ {
+ if (color == Xamarin.Forms.Color.Default)
+ Style.BackgroundColor = Colors.Clear;
+ else
+ Style.BackgroundColor = color.ToOouiColor ();
+ }
+
+ void UpdateHRef ()
+ {
+ Control.HRef = Element.HRef;
+ }
+
+ void UpdateAlignment ()
+ {
+ this.Style.Display = "table";
+ Control.Style.Display = "table-cell";
+ this.Style.TextAlign = Element.HorizontalTextAlignment.ToOouiTextAlign ();
+ Control.Style.VerticalAlign = Element.VerticalTextAlignment.ToOouiVerticalAlign ();
+ }
+
+ void UpdateLineBreakMode ()
+ {
+ _perfectSizeValid = false;
+ }
+
+ bool isTextFormatted;
+ void UpdateText ()
+ {
+ _perfectSizeValid = false;
+
+ var values = Element.GetValues (Xamarin.Forms.Label.FormattedTextProperty, Xamarin.Forms.Label.TextProperty, Xamarin.Forms.Label.TextColorProperty);
+ var formatted = values[0] as FormattedString;
+ if (formatted != null) {
+ Control.Text = (string)values[1];
+ isTextFormatted = true;
+ }
+ else {
+ Control.Text = (string)values[1];
+ isTextFormatted = false;
+ }
+ }
+
+ void UpdateFont ()
+ {
+ if (isTextFormatted)
+ return;
+ _perfectSizeValid = false;
+
+ Element.SetStyleFont (Element.FontFamily, Element.FontSize, Element.FontAttributes, Control.Style);
+ }
+
+ void UpdateTextColor ()
+ {
+ if (isTextFormatted)
+ return;
+
+ _perfectSizeValid = false;
+
+ var textColor = Element.TextColor;
+ if (textColor.IsDefault) {
+ Control.Style.Color = null;
+ }
+ else {
+ Control.Style.Color = textColor.ToOouiColor (Xamarin.Forms.Color.Black);
+ }
+ }
+ }
+}
diff --git a/Ooui.Forms/Renderers/LinkViewRenderer.cs b/Ooui.Forms/Renderers/LinkViewRenderer.cs
new file mode 100644
index 0000000..4ee222b
--- /dev/null
+++ b/Ooui.Forms/Renderers/LinkViewRenderer.cs
@@ -0,0 +1,36 @@
+using System;
+using System.ComponentModel;
+
+namespace Ooui.Forms.Renderers
+{
+ public class LinkViewRenderer : ViewRenderer
+ {
+ public LinkViewRenderer ()
+ : base ("a")
+ {
+ }
+
+ protected override void OnElementChanged (ElementChangedEventArgs e)
+ {
+ base.OnElementChanged (e);
+
+ UpdateHRef ();
+ }
+
+ protected override void OnElementPropertyChanged (object sender, PropertyChangedEventArgs e)
+ {
+ base.OnElementPropertyChanged (sender, e);
+
+ if (Control == null)
+ return;
+
+ if (e.PropertyName == Ooui.Forms.LinkLabel.HRefProperty.PropertyName)
+ UpdateHRef ();
+ }
+
+ void UpdateHRef ()
+ {
+ this.SetAttribute ("href", Element.HRef);
+ }
+ }
+}
diff --git a/Ooui.Forms/Renderers/ViewRenderer.cs b/Ooui.Forms/Renderers/ViewRenderer.cs
index edbe129..b425349 100644
--- a/Ooui.Forms/Renderers/ViewRenderer.cs
+++ b/Ooui.Forms/Renderers/ViewRenderer.cs
@@ -15,11 +15,16 @@ namespace Ooui.Forms.Renderers
public TNativeElement Control { get; private set; }
- ///
- /// Determines whether the native control is disposed of when this renderer is disposed
- /// Can be overridden in deriving classes
- ///
- protected virtual bool ManageNativeControlLifetime => true;
+ ///
+ /// Determines whether the native control is disposed of when this renderer is disposed
+ /// Can be overridden in deriving classes
+ ///
+ protected virtual bool ManageNativeControlLifetime => true;
+
+ public ViewRenderer (string tagName = "div")
+ : base (tagName)
+ {
+ }
protected override void Dispose (bool disposing)
{
diff --git a/Ooui.Forms/VisualElementRenderer.cs b/Ooui.Forms/VisualElementRenderer.cs
index f6f4548..628d863 100644
--- a/Ooui.Forms/VisualElementRenderer.cs
+++ b/Ooui.Forms/VisualElementRenderer.cs
@@ -62,7 +62,7 @@ namespace Ooui.Forms
}
}
- public VisualElementRenderer () : base ("div")
+ public VisualElementRenderer (string tagName = "div") : base (tagName)
{
_propertyChangedHandler = OnElementPropertyChanged;
}
diff --git a/Ooui/Anchor.cs b/Ooui/Anchor.cs
new file mode 100644
index 0000000..864011b
--- /dev/null
+++ b/Ooui/Anchor.cs
@@ -0,0 +1,18 @@
+using System;
+
+namespace Ooui
+{
+ public class Anchor : Element
+ {
+ string href = "";
+ public string HRef {
+ get => href;
+ set => SetProperty (ref href, value ?? "", "href");
+ }
+
+ public Anchor ()
+ : base ("a")
+ {
+ }
+ }
+}
diff --git a/Samples/DisplayAlertPage.xaml b/Samples/DisplayAlertPage.xaml
index 63fee3a..e610926 100644
--- a/Samples/DisplayAlertPage.xaml
+++ b/Samples/DisplayAlertPage.xaml
@@ -1,11 +1,18 @@
+ HorizontalOptions="Center" />
+
+
+
+