diff options
Diffstat (limited to 'Xamarin.Forms.Platform.Android/Renderers/LabelRenderer.cs')
-rw-r--r-- | Xamarin.Forms.Platform.Android/Renderers/LabelRenderer.cs | 213 |
1 files changed, 213 insertions, 0 deletions
diff --git a/Xamarin.Forms.Platform.Android/Renderers/LabelRenderer.cs b/Xamarin.Forms.Platform.Android/Renderers/LabelRenderer.cs new file mode 100644 index 00000000..45068838 --- /dev/null +++ b/Xamarin.Forms.Platform.Android/Renderers/LabelRenderer.cs @@ -0,0 +1,213 @@ +using System; +using System.ComponentModel; +using Android.Content.Res; +using Android.Graphics; +using Android.Text; +using Android.Util; +using Android.Widget; +using AColor = Android.Graphics.Color; + +namespace Xamarin.Forms.Platform.Android +{ + public class LabelRenderer : ViewRenderer<Label, TextView> + { + ColorStateList _labelTextColorDefault; + int _lastConstraintHeight; + int _lastConstraintWidth; + + SizeRequest? _lastSizeRequest; + float _lastTextSize = -1f; + Typeface _lastTypeface; + + Color _lastUpdateColor = Color.Default; + FormsTextView _view; + bool _wasFormatted; + + public LabelRenderer() + { + AutoPackage = false; + } + + public override SizeRequest GetDesiredSize(int widthConstraint, int heightConstraint) + { + if (_lastSizeRequest.HasValue) + { + // if we are measuring the same thing, no need to waste the time + bool canRecycleLast = widthConstraint == _lastConstraintWidth && heightConstraint == _lastConstraintHeight; + + if (!canRecycleLast) + { + // if the last time we measured the returned size was all around smaller than the passed constraint + // and the constraint is bigger than the last size request, we can assume the newly measured size request + // will not change either. + int lastConstraintWidthSize = MeasureSpecFactory.GetSize(_lastConstraintWidth); + int lastConstraintHeightSize = MeasureSpecFactory.GetSize(_lastConstraintHeight); + + int currentConstraintWidthSize = MeasureSpecFactory.GetSize(widthConstraint); + int currentConstraintHeightSize = MeasureSpecFactory.GetSize(heightConstraint); + + bool lastWasSmallerThanConstraints = _lastSizeRequest.Value.Request.Width < lastConstraintWidthSize && _lastSizeRequest.Value.Request.Height < lastConstraintHeightSize; + + bool currentConstraintsBiggerThanLastRequest = currentConstraintWidthSize >= _lastSizeRequest.Value.Request.Width && currentConstraintHeightSize >= _lastSizeRequest.Value.Request.Height; + + canRecycleLast = lastWasSmallerThanConstraints && currentConstraintsBiggerThanLastRequest; + } + + if (canRecycleLast) + return _lastSizeRequest.Value; + } + + SizeRequest result = base.GetDesiredSize(widthConstraint, heightConstraint); + result.Minimum = new Size(Math.Min(Context.ToPixels(10), result.Request.Width), result.Request.Height); + + _lastConstraintWidth = widthConstraint; + _lastConstraintHeight = heightConstraint; + _lastSizeRequest = result; + + return result; + } + + protected override void OnElementChanged(ElementChangedEventArgs<Label> e) + { + base.OnElementChanged(e); + if (_view == null) + { + _view = new FormsTextView(Context); + _labelTextColorDefault = _view.TextColors; + SetNativeControl(_view); + } + + if (e.OldElement == null) + { + UpdateText(); + UpdateLineBreakMode(); + UpdateGravity(); + } + else + { + _view.SkipNextInvalidate(); + UpdateText(); + if (e.OldElement.LineBreakMode != e.NewElement.LineBreakMode) + UpdateLineBreakMode(); + if (e.OldElement.HorizontalTextAlignment != e.NewElement.HorizontalTextAlignment || e.OldElement.VerticalTextAlignment != e.NewElement.VerticalTextAlignment) + UpdateGravity(); + } + } + + protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) + { + base.OnElementPropertyChanged(sender, e); + + if (e.PropertyName == Label.HorizontalTextAlignmentProperty.PropertyName || e.PropertyName == Label.VerticalTextAlignmentProperty.PropertyName) + UpdateGravity(); + else if (e.PropertyName == Label.TextColorProperty.PropertyName) + UpdateText(); + else if (e.PropertyName == Label.FontProperty.PropertyName) + UpdateText(); + else if (e.PropertyName == Label.LineBreakModeProperty.PropertyName) + UpdateLineBreakMode(); + else if (e.PropertyName == Label.TextProperty.PropertyName || e.PropertyName == Label.FormattedTextProperty.PropertyName) + UpdateText(); + } + + void UpdateColor() + { + Color c = Element.TextColor; + if (c == _lastUpdateColor) + return; + _lastUpdateColor = c; + + if (c.IsDefault) + _view.SetTextColor(_labelTextColorDefault); + else + _view.SetTextColor(c.ToAndroid()); + } + + void UpdateFont() + { + Font f = Element.Font; + + Typeface newTypeface = f.ToTypeface(); + if (newTypeface != _lastTypeface) + { + _view.Typeface = newTypeface; + _lastTypeface = newTypeface; + } + + float newTextSize = f.ToScaledPixel(); + if (newTextSize != _lastTextSize) + { + _view.SetTextSize(ComplexUnitType.Sp, newTextSize); + _lastTextSize = newTextSize; + } + } + + void UpdateGravity() + { + Label label = Element; + + _view.Gravity = label.HorizontalTextAlignment.ToHorizontalGravityFlags() | label.VerticalTextAlignment.ToVerticalGravityFlags(); + + _lastSizeRequest = null; + } + + void UpdateLineBreakMode() + { + switch (Element.LineBreakMode) + { + case LineBreakMode.NoWrap: + _view.SetSingleLine(true); + _view.Ellipsize = null; + break; + case LineBreakMode.WordWrap: + _view.SetSingleLine(false); + _view.Ellipsize = null; + _view.SetMaxLines(100); + break; + case LineBreakMode.CharacterWrap: + _view.SetSingleLine(false); + _view.Ellipsize = null; + _view.SetMaxLines(100); + break; + case LineBreakMode.HeadTruncation: + _view.SetSingleLine(true); + _view.Ellipsize = TextUtils.TruncateAt.Start; + break; + case LineBreakMode.TailTruncation: + _view.SetSingleLine(true); + _view.Ellipsize = TextUtils.TruncateAt.End; + break; + case LineBreakMode.MiddleTruncation: + _view.SetSingleLine(true); + _view.Ellipsize = TextUtils.TruncateAt.Middle; + break; + } + _lastSizeRequest = null; + } + + void UpdateText() + { + if (Element.FormattedText != null) + { + FormattedString formattedText = Element.FormattedText ?? Element.Text; + _view.TextFormatted = formattedText.ToAttributed(Element.Font, Element.TextColor, _view); + _wasFormatted = true; + } + else + { + if (_wasFormatted) + { + _view.SetTextColor(_labelTextColorDefault); + _lastUpdateColor = Color.Default; + } + _view.Text = Element.Text; + UpdateColor(); + UpdateFont(); + + _wasFormatted = false; + } + + _lastSizeRequest = null; + } + } +}
\ No newline at end of file |