maui-linux/Xamarin.Forms.Platform.Android/Renderers/LabelRenderer.cs

268 строки
7.8 KiB
C#

using Android.Content;
using Android.Content.Res;
using Android.Graphics;
using Android.Text;
using Android.Util;
using Android.Views;
using Android.Widget;
using System;
using System.ComponentModel;
using Xamarin.Forms.PlatformConfiguration.TizenSpecific;
namespace Xamarin.Forms.Platform.Android
{
public class LabelRenderer : ViewRenderer<Label, TextView>
{
ColorStateList _labelTextColorDefault;
float _lineSpacingExtraDefault;
float _lineSpacingMultiplierDefault;
int _lastConstraintHeight;
int _lastConstraintWidth;
SizeRequest? _lastSizeRequest;
float _lastTextSize = -1f;
Typeface _lastTypeface;
Color _lastUpdateColor = Color.Default;
FormsTextView _view;
bool _wasFormatted;
readonly MotionEventHelper _motionEventHelper = new MotionEventHelper();
SpannableString _spannableString;
public LabelRenderer(Context context) : base(context)
{
AutoPackage = false;
}
[Obsolete("This constructor is obsolete as of version 2.5. Please use LabelRenderer(Context) instead.")]
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 OnLayout(bool changed, int l, int t, int r, int b)
{
base.OnLayout(changed, l, t, r, b);
Control.RecalculateSpanPositions(Element, _spannableString, new SizeRequest(new Size(r - l, b - t)));
}
protected override TextView CreateNativeControl()
{
return new FormsTextView(Context);
}
protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
{
base.OnElementChanged(e);
if (_view == null)
{
_view = (FormsTextView)CreateNativeControl();
_labelTextColorDefault = _view.TextColors;
_lineSpacingMultiplierDefault = _view.LineSpacingMultiplier;
_lineSpacingExtraDefault = _view.LineSpacingExtra;
SetNativeControl(_view);
}
if (e.OldElement == null)
{
UpdateText();
UpdateLineBreakMode();
UpdateLineHeight();
UpdateGravity();
UpdateMaxLines();
}
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();
if (e.OldElement.MaxLines != e.NewElement.MaxLines)
UpdateMaxLines();
}
UpdateTextDecorations();
_motionEventHelper.UpdateElement(e.NewElement);
}
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.TextDecorationsProperty.PropertyName)
UpdateTextDecorations();
else if (e.PropertyName == Label.TextProperty.PropertyName || e.PropertyName == Label.FormattedTextProperty.PropertyName)
UpdateText();
else if (e.PropertyName == Label.LineHeightProperty.PropertyName)
UpdateLineHeight();
else if (e.PropertyName == Label.MaxLinesProperty.PropertyName)
UpdateMaxLines();
}
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()
{
#pragma warning disable 618 // We will need to update this when .Font goes away
Font f = Element.Font;
#pragma warning restore 618
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 UpdateTextDecorations()
{
if (!Element.IsSet(Label.TextDecorationsProperty))
return;
var textDecorations = Element.TextDecorations;
if ((textDecorations & TextDecorations.Strikethrough) == 0)
_view.PaintFlags &= ~PaintFlags.StrikeThruText;
else
_view.PaintFlags |= PaintFlags.StrikeThruText;
if ((textDecorations & TextDecorations.Underline) == 0)
_view.PaintFlags &= ~PaintFlags.UnderlineText;
else
_view.PaintFlags |= PaintFlags.UnderlineText;
}
void UpdateGravity()
{
Label label = Element;
_view.Gravity = label.HorizontalTextAlignment.ToHorizontalGravityFlags() | label.VerticalTextAlignment.ToVerticalGravityFlags();
_lastSizeRequest = null;
}
void UpdateLineBreakMode()
{
_view.SetLineBreakMode(Element);
_lastSizeRequest = null;
}
void UpdateLineHeight()
{
_lastSizeRequest = null;
if (Element.LineHeight == -1)
_view.SetLineSpacing(_lineSpacingExtraDefault, _lineSpacingMultiplierDefault);
else if (Element.LineHeight >= 0)
_view.SetLineSpacing(0, (float)Element.LineHeight);
}
void UpdateMaxLines()
{
Control.SetMaxLines(Element);
}
void UpdateText()
{
if (Element.FormattedText != null)
{
FormattedString formattedText = Element.FormattedText ?? Element.Text;
#pragma warning disable 618 // We will need to update this when .Font goes away
_view.TextFormatted = _spannableString = formattedText.ToAttributed(Element.Font, Element.TextColor, _view);
#pragma warning restore 618
_wasFormatted = true;
}
else
{
if (_wasFormatted)
{
_view.SetTextColor(_labelTextColorDefault);
_lastUpdateColor = Color.Default;
}
_view.Text = Element.Text;
UpdateColor();
UpdateFont();
_wasFormatted = false;
}
_lastSizeRequest = null;
}
public override bool OnTouchEvent(MotionEvent e)
{
if (base.OnTouchEvent(e))
return true;
return _motionEventHelper.HandleMotionEvent(Parent, e);
}
}
}