<Label Text="Time Picker" Margin="0,0,0,-10" />
<TimePicker></TimePicker>
<Label Text="Picker" Margin="0,0,0,-10" />
- <Picker Title="Select a monkey">
+ <Picker Title="Select a monkey">
<Picker.ItemsSource>
<x:Array Type="{x:Type x:String}">
<x:String>Baboon</x:String>
<Label Text="Red background" Margin="0,0,0,-10" />
<Stepper BackgroundColor="Red"></Stepper>
+ <Label Text="Editors" FontSize="Large"></Label>
+ <Label Text="Normal" Margin="0,0,0,-10" />
+ <Editor HeightRequest="200"></Editor>
+ <Label Text="Place Holder" Margin="0,0,0,-10" />
+ <Editor Placeholder="Place Holder" HeightRequest="200"></Editor>
</StackLayout>
</ScrollView>
--- /dev/null
+using UIKit;
+using MaterialComponents;
+using System;
+
+namespace Xamarin.Forms.Platform.iOS.Material
+{
+ public class MaterialEditorRenderer : EditorRendererBase<MaterialMultilineTextField>, IMaterialEntryRenderer
+ {
+ bool _hackHasRan = false;
+
+ protected override MaterialMultilineTextField CreateNativeControl()
+ {
+ return new MaterialMultilineTextField(this, Element);
+ }
+
+ protected override void SetBackgroundColor(Color color)
+ {
+ ApplyTheme();
+ }
+
+
+ protected internal override void UpdateTextColor()
+ {
+ Control?.UpdateTextColor(this);
+ }
+
+
+ protected virtual void ApplyTheme()
+ {
+ Control?.ApplyTheme(this);
+ }
+
+ protected internal override void UpdateFont()
+ {
+ base.UpdateFont();
+ Control?.ApplyTypographyScheme(Element);
+ }
+
+ protected internal override void UpdatePlaceholderText()
+ {
+ if (Control == null || !_hackHasRan)
+ return;
+
+ Control.UpdatePlaceholder(this);
+ }
+
+ protected internal override void UpdatePlaceholderColor()
+ {
+ if (Control == null || !_hackHasRan)
+ return;
+
+ Control.UpdatePlaceholder(this);
+ }
+
+ protected internal override void UpdateText()
+ {
+ if (!_hackHasRan)
+ return;
+
+ base.UpdateText();
+ }
+
+ protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
+ {
+ base.OnElementChanged(e);
+ InitialPlaceholderSetupHack();
+ }
+
+ protected internal override void UpdateAutoSizeOption()
+ {
+ base.UpdateAutoSizeOption();
+ Control.AutoSizeWithChanges = Element.AutoSize == EditorAutoSizeOption.TextChanges;
+
+ if(!Control.ExpandsOnOverflow)
+ Control.ExpandsOnOverflow = Element.AutoSize == EditorAutoSizeOption.TextChanges;
+ }
+
+ // this is required to force the placeholder to size correctly if it starts out prefilled
+ void InitialPlaceholderSetupHack()
+ {
+ if (Element == null)
+ return;
+
+ if(String.IsNullOrWhiteSpace(Element.Text) || String.IsNullOrWhiteSpace(Element.Placeholder))
+ {
+ _hackHasRan = true;
+ UpdateText();
+ UpdatePlaceholderText();
+ return;
+ }
+
+ TextView.BecomeFirstResponder();
+ Control.UpdatePlaceholder(this);
+ Device.BeginInvokeOnMainThread(() =>
+ {
+ _hackHasRan = true;
+ UpdateText();
+ TextView.ResignFirstResponder();
+ });
+ }
+
+
+ // Placeholder is currently broken upstream and doesn't animate to the correct scale
+ string IMaterialEntryRenderer.Placeholder => Element?.Placeholder;
+ // string IMaterialEntryRenderer.Placeholder => String.Empty;
+
+ Color IMaterialEntryRenderer.TextColor => Element?.TextColor ?? Color.Default;
+ Color IMaterialEntryRenderer.PlaceholderColor => Element?.PlaceholderColor ?? Color.Default;
+ Color IMaterialEntryRenderer.BackgroundColor => Element?.BackgroundColor ?? Color.Default;
+
+ protected IntrinsicHeightTextView IntrinsicHeightTextView => (IntrinsicHeightTextView)TextView;
+ protected override UITextView TextView => Control?.TextView;
+
+ }
+}
\ No newline at end of file
-using UIKit;
+using CoreGraphics;
+using UIKit;
namespace Xamarin.Forms.Platform.iOS.Material
{
}
-
Color IMaterialEntryRenderer.TextColor => Element?.TextColor ?? Color.Default;
Color IMaterialEntryRenderer.PlaceholderColor => Element?.PlaceholderColor ?? Color.Default;
Color IMaterialEntryRenderer.BackgroundColor => Element?.BackgroundColor ?? Color.Default;
--- /dev/null
+using System;
+using CoreGraphics;
+using MaterialComponents;
+using UIKit;
+using MMultilineTextField = MaterialComponents.MultilineTextField;
+using MTextInputControllerBase = MaterialComponents.TextInputControllerBase;
+using Xamarin.Forms.Internals;
+
+namespace Xamarin.Forms.Platform.iOS.Material
+{
+ public class MaterialMultilineTextField : MMultilineTextField, IMaterialTextField
+ {
+ public SemanticColorScheme ColorScheme { get; set; }
+ public TypographyScheme TypographyScheme { get; set; }
+ public MTextInputControllerBase ActiveTextInputController { get; set; }
+ public ITextInput TextInput => this;
+ internal bool AutoSizeWithChanges { get; set; } = false;
+ CGSize _contentSize;
+
+
+ public MaterialMultilineTextField(IMaterialEntryRenderer element, IFontElement fontElement)
+ {
+ VisualElement.VerifyVisualFlagEnabled();
+ MaterialTextManager.Init(element, this, fontElement);
+ }
+
+ public override CGSize SizeThatFits(CGSize size)
+ {
+ bool expandTurnedBackOn = UpdateIfTextViewShouldCollapse();
+ var result = base.SizeThatFits(size);
+
+ if (nfloat.IsInfinity(result.Width))
+ result = SystemLayoutSizeFittingSize(result, (float)UILayoutPriority.FittingSizeLevel, (float)UILayoutPriority.DefaultHigh);
+
+ if (ExpandsOnOverflow)
+ _contentSize = result;
+ else
+ _contentSize = TextView.ContentSize;
+
+ if (!expandTurnedBackOn)
+ UpdateIfTextViewShouldStopExpanding();
+
+ return result;
+ }
+
+ bool UpdateIfTextViewShouldCollapse()
+ {
+ if (!ExpandsOnOverflow &&
+ !AutoSizeWithChanges &&
+ !ShouldRestrainSize())
+ {
+ ExpandsOnOverflow = true;
+ return true;
+ }
+
+ return false;
+ }
+
+ bool ShouldRestrainSize()
+ {
+ if (TextView?.Font == null)
+ return false;
+
+ return (((NumberOfLines + 1) * TextView.Font.LineHeight) > Frame.Height);
+ }
+
+ void UpdateIfTextViewShouldStopExpanding()
+ {
+ if (!UpdateIfTextViewShouldCollapse() &&
+ !AutoSizeWithChanges &&
+ ExpandsOnOverflow &&
+ ShouldRestrainSize())
+ {
+ ExpandsOnOverflow = false;
+ }
+ }
+
+ public override CGRect Frame
+ {
+ get => base.Frame;
+ set
+ {
+ base.Frame = value;
+ UpdateIfTextViewShouldStopExpanding();
+ }
+ }
+
+ int NumberOfLines
+ {
+ get
+ {
+ if (TextView?.ContentSize == null || TextView.Font == null || TextView.Font.LineHeight == 0)
+ return 0;
+
+ return (int)(_contentSize.Height / TextView.Font.LineHeight);
+ }
+ }
+
+ internal void ApplyTypographyScheme(IFontElement fontElement) => MaterialTextManager.ApplyTypographyScheme(this, fontElement);
+
+ internal void ApplyTheme(IMaterialEntryRenderer element) => MaterialTextManager.ApplyTheme(this, element);
+
+ internal void UpdatePlaceholder(IMaterialEntryRenderer element) => MaterialTextManager.UpdatePlaceholder(this, element);
+
+ internal void UpdateTextColor(IMaterialEntryRenderer element) => MaterialTextManager.UpdateTextColor(this, element);
+
+
+ }
+}
namespace Xamarin.Forms.Platform.iOS.Material
{
- public class MaterialTextField : MTextField
+ internal interface IMaterialTextField
{
- SemanticColorScheme _colorScheme;
- TypographyScheme _typographyScheme;
- MTextInputControllerBase _activeTextinputController;
+ SemanticColorScheme ColorScheme { get; set; }
+ TypographyScheme TypographyScheme { get; set; }
+ MTextInputControllerBase ActiveTextInputController { get; set; }
+
+ ITextInput TextInput { get; }
+ }
+
+ public class MaterialTextField : MTextField, IMaterialTextField
+ {
+ public SemanticColorScheme ColorScheme { get; set; }
+ public TypographyScheme TypographyScheme { get; set; }
+ public MTextInputControllerBase ActiveTextInputController { get; set; }
+
+ public ITextInput TextInput => this;
public MaterialTextField(IMaterialEntryRenderer element, IFontElement fontElement)
{
VisualElement.VerifyVisualFlagEnabled();
- ClearButtonMode = UITextFieldViewMode.Never;
- _activeTextinputController = new MTextInputControllerFilled(this);
- TextInsetsMode = TextInputTextInsetsMode.IfContent;
- _typographyScheme = CreateTypographyScheme();
- _colorScheme = (SemanticColorScheme)CreateColorScheme();
- ApplyTypographyScheme(fontElement);
- ApplyTheme(element);
-
+ MaterialTextManager.Init(element, this, fontElement);
}
public override CGSize SizeThatFits(CGSize size)
return result;
}
- internal void ApplyTypographyScheme(IFontElement fontElement)
- {
- Font = fontElement?.ToUIFont();
- _typographyScheme.Subtitle1 = Font;
- TextFieldTypographyThemer.ApplyTypographyScheme(_typographyScheme, this);
- TextFieldTypographyThemer.ApplyTypographyScheme(_typographyScheme, _activeTextinputController);
- }
-
- internal void ApplyTheme(IMaterialEntryRenderer element)
- {
- if (element == null)
- return;
-
- if (_activeTextinputController == null)
- return;
-
- FilledTextFieldColorThemer.ApplySemanticColorScheme(_colorScheme, (MTextInputControllerFilled)_activeTextinputController);
-
- var textColor = MaterialColors.GetEntryTextColor(element.TextColor);
- var placeHolderColors = MaterialColors.GetPlaceHolderColor(element.PlaceholderColor, element.TextColor);
- var underlineColors = MaterialColors.GetUnderlineColor(element.TextColor);
-
- TextColor = textColor;
- _activeTextinputController.InlinePlaceholderColor = placeHolderColors.InlineColor;
- _activeTextinputController.FloatingPlaceholderNormalColor = placeHolderColors.InlineColor;
- _activeTextinputController.FloatingPlaceholderActiveColor = placeHolderColors.FloatingColor;
-
- // BackgroundColor
- _activeTextinputController.BorderFillColor = MaterialColors.CreateEntryFilledInputBackgroundColor(element.BackgroundColor, element.TextColor);
-
- _activeTextinputController.ActiveColor = underlineColors.FocusedColor;
- _activeTextinputController.NormalColor = underlineColors.UnFocusedColor;
- }
-
- internal void UpdatePlaceholder(IMaterialEntryRenderer element)
- {
- var placeholderText = element.Placeholder ?? String.Empty;
- _activeTextinputController.PlaceholderText = placeholderText;
- ApplyTheme(element);
-
- var previous = _activeTextinputController.FloatingPlaceholderScale;
- if (String.IsNullOrWhiteSpace(placeholderText))
- _activeTextinputController.FloatingPlaceholderScale = 0;
- else
- _activeTextinputController.FloatingPlaceholderScale = (float)TextInputControllerBase.FloatingPlaceholderScaleDefault;
-
- if (previous != _activeTextinputController.FloatingPlaceholderScale && element is IVisualElementRenderer controller)
- controller.Element?.InvalidateMeasureInternal(InvalidationTrigger.VerticalOptionsChanged);
- }
+ internal void ApplyTypographyScheme(IFontElement fontElement) =>
+ MaterialTextManager.ApplyTypographyScheme(this, fontElement);
+ internal void ApplyTheme(IMaterialEntryRenderer element) => MaterialTextManager.ApplyTheme(this, element);
- internal void UpdateTextColor(IMaterialEntryRenderer element)
- {
- var uIColor = MaterialColors.GetEntryTextColor(element.TextColor);
- _colorScheme.OnSurfaceColor = uIColor;
- _colorScheme.PrimaryColor = uIColor;
- }
+ internal void UpdatePlaceholder(IMaterialEntryRenderer element) => MaterialTextManager.UpdatePlaceholder(this, element);
- protected virtual IColorScheming CreateColorScheme()
- {
- var returnValue = MaterialColors.Light.CreateColorScheme();
- return returnValue;
- }
- protected virtual TypographyScheme CreateTypographyScheme()
- {
- return new TypographyScheme();
- }
+ internal void UpdateTextColor(IMaterialEntryRenderer element) => MaterialTextManager.UpdateTextColor(this, element);
}
--- /dev/null
+using System;
+using CoreGraphics;
+using MaterialComponents;
+using UIKit;
+using MTextField = MaterialComponents.TextField;
+using MTextInputControllerFilled = MaterialComponents.TextInputControllerFilled;
+using MTextInputControllerBase = MaterialComponents.TextInputControllerBase;
+using System.Collections.Generic;
+using ObjCRuntime;
+using Foundation;
+using Xamarin.Forms.Internals;
+
+namespace Xamarin.Forms.Platform.iOS.Material
+{
+ internal static class MaterialTextManager
+ {
+ public static void Init(IMaterialEntryRenderer element, IMaterialTextField textField, IFontElement fontElement)
+ {
+ textField.TextInput.ClearButtonMode = UITextFieldViewMode.Never;
+ textField.ActiveTextInputController = new MTextInputControllerFilled(textField.TextInput);
+ textField.TextInput.TextInsetsMode = TextInputTextInsetsMode.IfContent;
+ textField.TypographyScheme = CreateTypographyScheme();
+ textField.ColorScheme = (SemanticColorScheme)CreateColorScheme();
+ ApplyTypographyScheme(textField, fontElement);
+ ApplyTheme(textField, element);
+ }
+ public static void ApplyTypographyScheme(IMaterialTextField textField, IFontElement fontElement)
+ {
+ textField.TextInput.Font = fontElement?.ToUIFont();
+ textField.TypographyScheme.Subtitle1 = textField.TextInput.Font;
+ TextFieldTypographyThemer.ApplyTypographyScheme(textField.TypographyScheme, textField.TextInput);
+ TextFieldTypographyThemer.ApplyTypographyScheme(textField.TypographyScheme, textField.ActiveTextInputController);
+ }
+
+ public static void ApplyTheme(IMaterialTextField textField, IMaterialEntryRenderer element)
+ {
+ if (element == null)
+ return;
+
+ if (textField.ActiveTextInputController == null)
+ return;
+
+ FilledTextFieldColorThemer.ApplySemanticColorScheme(textField.ColorScheme, (MTextInputControllerFilled)textField.ActiveTextInputController);
+
+ var textColor = MaterialColors.GetEntryTextColor(element.TextColor);
+ var placeHolderColors = MaterialColors.GetPlaceHolderColor(element.PlaceholderColor, element.TextColor);
+ var underlineColors = MaterialColors.GetUnderlineColor(element.TextColor);
+
+ textField.TextInput.TextColor = textColor;
+ textField.ActiveTextInputController.InlinePlaceholderColor = placeHolderColors.InlineColor;
+ textField.ActiveTextInputController.FloatingPlaceholderNormalColor = placeHolderColors.InlineColor;
+ textField.ActiveTextInputController.FloatingPlaceholderActiveColor = placeHolderColors.FloatingColor;
+
+ // BackgroundColor
+ textField.ActiveTextInputController.BorderFillColor = MaterialColors.CreateEntryFilledInputBackgroundColor(element.BackgroundColor, element.TextColor);
+
+ textField.ActiveTextInputController.ActiveColor = underlineColors.FocusedColor;
+ textField.ActiveTextInputController.NormalColor = underlineColors.UnFocusedColor;
+ }
+
+ public static void UpdatePlaceholder(IMaterialTextField textField, IMaterialEntryRenderer element)
+ {
+ var placeholderText = element.Placeholder ?? String.Empty;
+ textField.ActiveTextInputController.PlaceholderText = placeholderText;
+ ApplyTheme(textField, element);
+
+ var previous = textField.ActiveTextInputController.FloatingPlaceholderScale;
+ if (String.IsNullOrWhiteSpace(placeholderText))
+ textField.ActiveTextInputController.FloatingPlaceholderScale = 0;
+ else
+ textField.ActiveTextInputController.FloatingPlaceholderScale = (float)TextInputControllerBase.FloatingPlaceholderScaleDefault;
+
+ if (previous != textField.ActiveTextInputController.FloatingPlaceholderScale && element is IVisualElementRenderer controller)
+ controller.Element?.InvalidateMeasureInternal(InvalidationTrigger.VerticalOptionsChanged);
+ }
+
+ public static void UpdateTextColor(IMaterialTextField textField, IMaterialEntryRenderer element)
+ {
+ var uIColor = MaterialColors.GetEntryTextColor(element.TextColor);
+ textField.ColorScheme.OnSurfaceColor = uIColor;
+ textField.ColorScheme.PrimaryColor = uIColor;
+ }
+
+ static IColorScheming CreateColorScheme()
+ {
+ var returnValue = MaterialColors.Light.CreateColorScheme();
+ return returnValue;
+ }
+
+ static TypographyScheme CreateTypographyScheme()
+ {
+ return new TypographyScheme();
+ }
+ }
+}
\ No newline at end of file
[assembly: ExportRenderer(typeof(Xamarin.Forms.TimePicker), typeof(Xamarin.Forms.Platform.iOS.Material.MaterialTimePickerRenderer), new[] { typeof(VisualMarker.MaterialVisual) })]
[assembly: ExportRenderer(typeof(Xamarin.Forms.Picker), typeof(Xamarin.Forms.Platform.iOS.Material.MaterialPickerRenderer), new[] { typeof(VisualMarker.MaterialVisual) })]
[assembly: ExportRenderer(typeof(Xamarin.Forms.DatePicker), typeof(Xamarin.Forms.Platform.iOS.Material.MaterialDatePickerRenderer), new[] { typeof(VisualMarker.MaterialVisual) })]
-[assembly: ExportRenderer(typeof(Xamarin.Forms.Stepper), typeof(Xamarin.Forms.Platform.iOS.Material.MaterialStepperRenderer), new[] { typeof(VisualMarker.MaterialVisual) })]
\ No newline at end of file
+[assembly: ExportRenderer(typeof(Xamarin.Forms.Stepper), typeof(Xamarin.Forms.Platform.iOS.Material.MaterialStepperRenderer), new[] { typeof(VisualMarker.MaterialVisual) })]
+[assembly: ExportRenderer(typeof(Xamarin.Forms.Editor), typeof(Xamarin.Forms.Platform.iOS.Material.MaterialEditorRenderer), new[] { typeof(VisualMarker.MaterialVisual) })]
\ No newline at end of file
<Link>MaterialColors.cs</Link>
</Compile>
<Compile Include="IMaterialEntryRenderer.cs" />
+ <Compile Include="MaterialEditorRenderer.cs" />
<Compile Include="MaterialPickerRenderer.cs" />
<Compile Include="MaterialDatePickerRenderer.cs" />
+ <Compile Include="MaterialMultiLineTextField.cs" />
+ <Compile Include="MaterialTextManager.cs" />
<Compile Include="MaterialTimePickerRenderer.cs" />
<Compile Include="MaterialTextField.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
--- /dev/null
+#if __ANDROID_28__
+using Android.Content;
+using Android.Util;
+using Android.Views;
+using Android.Widget;
+using Xamarin.Forms;
+using Xamarin.Forms.Platform.Android.Material;
+
+[assembly: ExportRenderer(typeof(Xamarin.Forms.Editor), typeof(MaterialEditorRenderer), new[] { typeof(VisualMarker.MaterialVisual) })]
+namespace Xamarin.Forms.Platform.Android.Material
+{
+ public sealed class MaterialEditorRenderer : EditorRendererBase<MaterialFormsTextInputLayout>
+ {
+ bool _disposed;
+ MaterialFormsEditText _textInputEditText;
+ MaterialFormsTextInputLayout _textInputLayout;
+
+ public MaterialEditorRenderer(Context context) :
+ base(MaterialContextThemeWrapper.Create(context))
+ {
+ VisualElement.VerifyVisualFlagEnabled();
+ }
+
+ IElementController ElementController => Element as IElementController;
+
+ protected override EditText EditText => _textInputEditText;
+
+ protected override MaterialFormsTextInputLayout CreateNativeControl()
+ {
+ LayoutInflater inflater = LayoutInflater.FromContext(Context);
+ var view = inflater.Inflate(Resource.Layout.TextInputLayoutFilledBox, null);
+ _textInputLayout = (MaterialFormsTextInputLayout)view;
+ _textInputEditText = _textInputLayout.FindViewById<MaterialFormsEditText>(Resource.Id.materialformsedittext);
+ UpdatePlaceholderText();
+
+ return _textInputLayout;
+ }
+
+ protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
+ {
+ base.OnElementChanged(e);
+ UpdateBackgroundColor();
+ }
+
+ protected override void UpdateTextColor() => ApplyTheme();
+
+ protected override void UpdateBackgroundColor()
+ {
+ if (_disposed || _textInputLayout == null)
+ return;
+
+ _textInputLayout.BoxBackgroundColor = MaterialColors.CreateEntryFilledInputBackgroundColor(Element.BackgroundColor, Element.TextColor);
+ }
+
+ protected internal override void UpdatePlaceholderText()
+ {
+ if (_disposed || _textInputLayout == null)
+ return;
+
+ _textInputLayout?.SetHint(Element.Placeholder, Element);
+ }
+
+
+ protected override void UpdatePlaceholderColor() => ApplyTheme();
+ void ApplyTheme() => _textInputLayout?.ApplyTheme(Element.TextColor, Element.PlaceholderColor);
+
+ protected internal override void UpdateFont()
+ {
+ if (_disposed || _textInputLayout == null)
+ return;
+
+ base.UpdateFont();
+ _textInputLayout.Typeface = Element.ToTypeface();
+ _textInputEditText.SetTextSize(ComplexUnitType.Sp, (float)Element.FontSize);
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ _disposed = true;
+ base.Dispose(disposing);
+ }
+ }
+}
+#endif
\ No newline at end of file
{
public sealed class MaterialEntryRenderer : EntryRendererBase<MaterialFormsTextInputLayout>
{
- bool _disposed;
MaterialFormsEditText _textInputEditText;
MaterialFormsTextInputLayout _textInputLayout;
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
- var oldElement = e.OldElement;
-
- if (oldElement != null)
- {
- oldElement.PropertyChanged -= OnElementPropertyChanged;
- oldElement.FocusChangeRequested -= OnFocusChangeRequested;
- }
-
- if (e.NewElement != null)
- Element.FocusChangeRequested += OnFocusChangeRequested;
-
UpdateBackgroundColor();
}
-
- protected override void OnFocusChangeRequested(object sender, VisualElement.FocusRequestArgs e)
- {
- e.Result = true;
-
- if (e.Focus)
- {
- // use post being BeginInvokeOnMainThread will not delay on android
- Looper looper = Context.MainLooper;
- var handler = new Handler(looper);
- handler.Post(() =>
- {
- _textInputEditText.RequestFocus();
- });
- }
- else
- {
- _textInputEditText.ClearFocus();
- }
-
- if (e.Focus)
- this.ShowKeyboard();
- else
- this.HideKeyboard();
- }
-
-
- protected override void Dispose(bool disposing)
- {
- if (_disposed)
- return;
-
- _disposed = true;
-
- if (disposing && Element != null)
- Element.FocusChangeRequested -= OnFocusChangeRequested;
-
- base.Dispose(disposing);
- }
-
protected override void UpdateTextColor() => ApplyTheme();
protected override void UpdateBackgroundColor()
protected internal override void UpdatePlaceHolderText()
{
_textInputLayout.SetHint(Element.Placeholder, Element);
- Element.InvalidateMeasureNonVirtual(Internals.InvalidationTrigger.VerticalOptionsChanged);
}
}
Context Context = textInputEditText.Context;
- textInputEditText.SetPadding((int)Context.ToPixels(rect.Left), (int)Context.ToPixels(rect.Top), (int)Context.ToPixels(rect.Right), (int)Context.ToPixels(rect.Bottom));
+ var left = (int)Context.ToPixels(rect.Left);
+ var top = (int)Context.ToPixels(rect.Top);
+ var right = (int)Context.ToPixels(rect.Right);
+ var bottom = (int)Context.ToPixels(rect.Bottom);
+
+ if(textInputEditText.PaddingLeft != left ||
+ textInputEditText.PaddingTop != top ||
+ textInputEditText.PaddingRight != right ||
+ textInputEditText.PaddingBottom != bottom)
+ textInputEditText.SetPadding(left, top, right, bottom);
}
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
-using System.Linq;
using Android.Content;
using Android.Content.Res;
using Android.OS;
using Android.Util;
using Android.Views;
using Java.Lang;
-using Xamarin.Forms.Internals;
-using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
+using Android.Widget;
namespace Xamarin.Forms.Platform.Android
{
- public class EditorRenderer : ViewRenderer<Editor, FormsEditText>, ITextWatcher
+ public class EditorRenderer : EditorRendererBase<FormsEditText>
{
- bool _disposed;
+ TextColorSwitcher _hintColorSwitcher;
TextColorSwitcher _textColorSwitcher;
- ColorStateList defaultPlaceholdercolor;
public EditorRenderer(Context context) : base(context)
{
+ }
+
+ [Obsolete("This constructor is obsolete as of version 2.5. Please use EntryRenderer(Context) instead.")]
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public EditorRenderer()
+ {
+ AutoPackage = false;
+ }
+
+ protected override FormsEditText CreateNativeControl()
+ {
+ return new FormsEditText(Context);
+ }
+
+ protected override EditText EditText => Control;
+
+ protected override void UpdatePlaceholderColor()
+ {
+ _hintColorSwitcher = _hintColorSwitcher ?? new TextColorSwitcher(EditText.HintTextColors, Element.UseLegacyColorManagement());
+ _hintColorSwitcher.UpdateTextColor(EditText, Element.PlaceholderColor, EditText.SetHintTextColor);
+ }
+
+ protected override void UpdateTextColor()
+ {
+ _textColorSwitcher = _textColorSwitcher ?? new TextColorSwitcher(EditText.TextColors, Element.UseLegacyColorManagement());
+ _textColorSwitcher.UpdateTextColor(EditText, Element.TextColor);
+ }
+ }
+
+ public abstract class EditorRendererBase<TControl> : ViewRenderer<Editor, TControl>, ITextWatcher
+ where TControl : global::Android.Views.View
+ {
+ bool _disposed;
+ protected abstract EditText EditText { get; }
+
+ public EditorRendererBase(Context context) : base(context)
+ {
AutoPackage = false;
}
[Obsolete("This constructor is obsolete as of version 2.5. Please use EditorRenderer(Context) instead.")]
[EditorBrowsable(EditorBrowsableState.Never)]
- public EditorRenderer()
+ public EditorRendererBase()
{
AutoPackage = false;
}
((IElementController)Element).SetValueFromRenderer(Editor.TextProperty, s.ToString());
}
- protected override FormsEditText CreateNativeControl()
- {
- return new FormsEditText(Context);
- }
-
protected override void OnFocusChangeRequested(object sender, VisualElement.FocusRequestArgs e)
{
if (!e.Focus)
{
- Control.HideKeyboard();
+ EditText.HideKeyboard();
}
base.OnFocusChangeRequested(sender, e);
// Post this to the main looper queue so it doesn't happen until the other focus stuff has resolved
// Otherwise, ShowKeyboard will be called before this control is truly focused, and we will potentially
// be displaying the wrong keyboard
- Control?.PostShowKeyboard();
+ EditText?.PostShowKeyboard();
}
}
edit = CreateNativeControl();
SetNativeControl(edit);
- edit.AddTextChangedListener(this);
- if(edit is IFormsEditText formsEditText)
+ EditText.AddTextChangedListener(this);
+ if(EditText is IFormsEditText formsEditText)
formsEditText.OnKeyboardBackPressed += OnKeyboardBackPressed;
-
- var useLegacyColorManagement = e.NewElement.UseLegacyColorManagement();
- _textColorSwitcher = new TextColorSwitcher(edit.TextColors, useLegacyColorManagement);
-
- defaultPlaceholdercolor = Control.HintTextColors;
}
- edit.SetSingleLine(false);
- edit.Gravity = GravityFlags.Top;
+ EditText.SetSingleLine(false);
+ EditText.Gravity = GravityFlags.Top;
if ((int)Build.VERSION.SdkInt > 16)
- edit.TextAlignment = global::Android.Views.TextAlignment.ViewStart;
- edit.SetHorizontallyScrolling(false);
+ EditText.TextAlignment = global::Android.Views.TextAlignment.ViewStart;
+ EditText.SetHorizontallyScrolling(false);
UpdateText();
UpdateInputType();
if (disposing)
{
- if (Control != null && Control is IFormsEditText formsEditText)
+ if (EditText != null && EditText is IFormsEditText formsEditText)
{
formsEditText.OnKeyboardBackPressed -= OnKeyboardBackPressed;
}
ElementController.SendCompleted();
}
- void UpdateFont()
+ protected internal virtual void UpdateFont()
{
- Control.Typeface = Element.ToTypeface();
- Control.SetTextSize(ComplexUnitType.Sp, (float)Element.FontSize);
+ EditText.Typeface = Element.ToTypeface();
+ EditText.SetTextSize(ComplexUnitType.Sp, (float)Element.FontSize);
}
void UpdateInputType()
{
Editor model = Element;
- FormsEditText edit = Control;
+ var edit = EditText;
var keyboard = model.Keyboard;
edit.InputType = keyboard.ToInputType() | InputTypes.TextFlagMultiLine;
{
string newText = Element.Text ?? "";
- if (Control.Text == newText)
+ if (EditText.Text == newText)
return;
- Control.Text = newText;
- Control.SetSelection(newText.Length);
+ EditText.Text = newText;
+ EditText.SetSelection(newText.Length);
}
- void UpdateTextColor()
- {
- _textColorSwitcher?.UpdateTextColor(Control, Element.TextColor);
- }
+ abstract protected void UpdateTextColor();
- void UpdatePlaceholderText()
+ internal protected virtual void UpdatePlaceholderText()
{
- if (Control.Hint == Element.Placeholder)
+ if (EditText.Hint == Element.Placeholder)
return;
- Control.Hint = Element.Placeholder;
+ EditText.Hint = Element.Placeholder;
}
- void UpdatePlaceholderColor()
- {
- if (Element.PlaceholderColor == Color.Default)
- Control.SetHintTextColor(defaultPlaceholdercolor);
- else
- Control.SetHintTextColor(Element.PlaceholderColor.ToAndroid());
- }
+ abstract protected void UpdatePlaceholderColor();
void OnKeyboardBackPressed(object sender, EventArgs eventArgs)
{
ElementController?.SendCompleted();
- Control?.ClearFocus();
+ EditText?.ClearFocus();
}
void UpdateMaxLength()
{
- var currentFilters = new List<IInputFilter>(Control?.GetFilters() ?? new IInputFilter[0]);
+ var currentFilters = new List<IInputFilter>(EditText?.GetFilters() ?? new IInputFilter[0]);
for (var i = 0; i < currentFilters.Count; i++)
{
currentFilters.Add(new InputFilterLengthFilter(Element.MaxLength));
- Control?.SetFilters(currentFilters.ToArray());
+ EditText?.SetFilters(currentFilters.ToArray());
- var currentControlText = Control?.Text;
+ var currentControlText = EditText?.Text;
if (currentControlText.Length > Element.MaxLength)
- Control.Text = currentControlText.Substring(0, Element.MaxLength);
+ EditText.Text = currentControlText.Substring(0, Element.MaxLength);
}
void UpdateIsReadOnly()
{
bool isReadOnly = !Element.IsReadOnly;
- Control.FocusableInTouchMode = isReadOnly;
- Control.Focusable = isReadOnly;
- Control.SetCursorVisible(isReadOnly);
+ EditText.FocusableInTouchMode = isReadOnly;
+ EditText.Focusable = isReadOnly;
+ EditText.SetCursorVisible(isReadOnly);
}
}
}
\ No newline at end of file
{
base.UpdateIsReadOnly();
bool isReadOnly = !Element.IsReadOnly;
- Control.SetCursorVisible(isReadOnly);
+ EditText.SetCursorVisible(isReadOnly);
}
protected override void UpdatePlaceholderColor()
// Fire Completed and dismiss keyboard for hardware / physical keyboards
if (actionId == ImeAction.Done || actionId == _currentInputImeFlag || (actionId == ImeAction.ImeNull && e.KeyCode == Keycode.Enter && e.Action == KeyEventActions.Up))
{
- Control.ClearFocus();
+ EditText.ClearFocus();
v.HideKeyboard();
((IEntryController)Element).SendCompleted();
}
{
if (!e.Focus)
{
- Control.HideKeyboard();
+ EditText.HideKeyboard();
}
base.OnFocusChangeRequested(sender, e);
// Post this to the main looper queue so it doesn't happen until the other focus stuff has resolved
// Otherwise, ShowKeyboard will be called before this control is truly focused, and we will potentially
// be displaying the wrong keyboard
- Control?.PostShowKeyboard();
+ EditText?.PostShowKeyboard();
}
}
if (disposing)
{
- if (Control != null && Control is IFormsEditText formsEditContext)
+ if (EditText != null && EditText is IFormsEditText formsEditContext)
{
formsEditContext.OnKeyboardBackPressed -= OnKeyboardBackPressed;
formsEditContext.SelectionChanged -= SelectionChanged;
if (EditText.Text != Element.Text)
{
EditText.Text = Element.Text;
- if (Control.IsFocused)
+ if (EditText.IsFocused)
{
EditText.SetSelection(EditText.Text.Length);
- Control.ShowKeyboard();
+ EditText.ShowKeyboard();
}
}
}
void UpdateCursorSelection()
{
- if (_nativeSelectionIsUpdating || Control == null || Element == null)
+ if (_nativeSelectionIsUpdating || Control == null || Element == null || EditText == null)
return;
- if (!Element.IsReadOnly && Control.RequestFocus())
+ if (!Element.IsReadOnly && EditText.RequestFocus())
{
try
{
{
bool isReadOnly = !Element.IsReadOnly;
- Control.FocusableInTouchMode = isReadOnly;
- Control.Focusable = isReadOnly;
+ EditText.FocusableInTouchMode = isReadOnly;
+ EditText.Focusable = isReadOnly;
}
}
}
<Compile Include="IBorderVisualElementRenderer.cs" />
<Compile Include="IDeviceInfoProvider.cs" />
<Compile Include="ITabStop.cs" />
+ <Compile Include="Material\MaterialEditorRenderer.cs" />
<Compile Include="Material\MaterialFormsTextInputLayoutBase.cs" />
<Compile Include="Material\MaterialFormsEditTextBase.cs" />
<Compile Include="Material\MaterialFormsEditTextManager.cs" />
namespace Xamarin.Forms.Platform.iOS
{
- public class EditorRenderer : ViewRenderer<Editor, UITextView>
+ public class EditorRenderer : EditorRendererBase<UITextView>
+ {
+ UILabel _placeholderLabel;
+
+ public EditorRenderer()
+ {
+ Frame = new RectangleF(0, 20, 320, 40);
+ }
+
+ protected override UITextView CreateNativeControl()
+ {
+ return new FormsUITextView(RectangleF.Empty);
+ }
+
+ protected override UITextView TextView => Control;
+
+ protected internal override void UpdateText()
+ {
+ base.UpdateText();
+ _placeholderLabel.Hidden = !string.IsNullOrEmpty(TextView.Text);
+ }
+
+ protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
+ {
+ // create label so it can get updated during the initial setup loop
+ _placeholderLabel = new UILabel
+ {
+ BackgroundColor = UIColor.Clear
+ };
+
+ base.OnElementChanged(e);
+
+ CreatePlaceholderLabel();
+ }
+
+ protected internal override void UpdateFont()
+ {
+ base.UpdateFont();
+ _placeholderLabel.Font = Element.ToUIFont();
+ }
+
+ protected internal override void UpdatePlaceholderText()
+ {
+ _placeholderLabel.Text = Element.Placeholder;
+ }
+
+ protected internal override void UpdatePlaceholderColor()
+ {
+ if (Element.PlaceholderColor == Color.Default)
+ _placeholderLabel.TextColor = UIColor.DarkGray;
+ else
+ _placeholderLabel.TextColor = Element.PlaceholderColor.ToUIColor();
+ }
+
+ void CreatePlaceholderLabel()
+ {
+ Control.AddSubview(_placeholderLabel);
+
+ var edgeInsets = TextView.TextContainerInset;
+ var lineFragmentPadding = TextView.TextContainer.LineFragmentPadding;
+
+ var vConstraints = NSLayoutConstraint.FromVisualFormat(
+ "V:|-" + edgeInsets.Top + "-[_placeholderLabel]-" + edgeInsets.Bottom + "-|", 0, new NSDictionary(),
+ NSDictionary.FromObjectsAndKeys(
+ new NSObject[] { _placeholderLabel }, new NSObject[] { new NSString("_placeholderLabel") })
+ );
+
+ var hConstraints = NSLayoutConstraint.FromVisualFormat(
+ "H:|-" + lineFragmentPadding + "-[_placeholderLabel]-" + lineFragmentPadding + "-|",
+ 0, new NSDictionary(),
+ NSDictionary.FromObjectsAndKeys(
+ new NSObject[] { _placeholderLabel }, new NSObject[] { new NSString("_placeholderLabel") })
+ );
+
+ _placeholderLabel.TranslatesAutoresizingMaskIntoConstraints = false;
+
+ Control.AddConstraints(hConstraints);
+ Control.AddConstraints(vConstraints);
+ }
+
+ }
+
+ public abstract class EditorRendererBase<TControl> : ViewRenderer<Editor, TControl>
+ where TControl : UIView
{
bool _disposed;
IEditorController ElementController => Element;
- UILabel _placeholderLabel;
+ protected abstract UITextView TextView { get; }
protected override void Dispose(bool disposing)
{
{
if (Control != null)
{
- Control.Changed -= HandleChanged;
- Control.Started -= OnStarted;
- Control.Ended -= OnEnded;
- Control.ShouldChangeText -= ShouldChangeText;
- (Control as FormsUITextView).FrameChanged -= OnFrameChanged;
+ TextView.Changed -= HandleChanged;
+ TextView.Started -= OnStarted;
+ TextView.Ended -= OnEnded;
+ TextView.ShouldChangeText -= ShouldChangeText;
+ if(Control is IFormsUITextView formsUITextView)
+ formsUITextView.FrameChanged -= OnFrameChanged;
}
}
if (Control == null)
{
- SetNativeControl(new FormsUITextView(RectangleF.Empty));
+ SetNativeControl(CreateNativeControl());
if (Device.Idiom == TargetIdiom.Phone)
{
var spacer = new UIBarButtonItem(UIBarButtonSystemItem.FlexibleSpace);
var doneButton = new UIBarButtonItem(UIBarButtonSystemItem.Done, (o, a) =>
{
- Control.ResignFirstResponder();
+ TextView.ResignFirstResponder();
ElementController.SendCompleted();
});
accessoryView.SetItems(new[] { spacer, doneButton }, false);
- Control.InputAccessoryView = accessoryView;
+ TextView.InputAccessoryView = accessoryView;
}
- Control.Changed += HandleChanged;
- Control.Started += OnStarted;
- Control.Ended += OnEnded;
- Control.ShouldChangeText += ShouldChangeText;
+ TextView.Changed += HandleChanged;
+ TextView.Started += OnStarted;
+ TextView.Ended += OnEnded;
+ TextView.ShouldChangeText += ShouldChangeText;
}
- CreatePlaceholderLabel();
+ UpdateFont();
UpdatePlaceholderText();
UpdatePlaceholderColor();
UpdateTextColor();
UpdateText();
- UpdateFont();
UpdateKeyboard();
UpdateEditable();
UpdateTextAlignment();
UpdateUserInteraction();
}
- private void UpdateAutoSizeOption()
+ protected internal virtual void UpdateAutoSizeOption()
{
- if (Control is FormsUITextView textView)
+ if (Control is IFormsUITextView textView)
{
textView.FrameChanged -= OnFrameChanged;
if (Element.AutoSize == EditorAutoSizeOption.TextChanges)
}
}
- void CreatePlaceholderLabel()
- {
- _placeholderLabel = new UILabel
- {
- BackgroundColor = UIColor.Clear
- };
-
- Control.AddSubview(_placeholderLabel);
-
- var edgeInsets = Control.TextContainerInset;
- var lineFragmentPadding = Control.TextContainer.LineFragmentPadding;
-
- var vConstraints = NSLayoutConstraint.FromVisualFormat(
- "V:|-" + edgeInsets.Top + "-[_placeholderLabel]-" + edgeInsets.Bottom + "-|", 0, new NSDictionary(),
- NSDictionary.FromObjectsAndKeys(
- new NSObject[] { _placeholderLabel }, new NSObject[] { new NSString("_placeholderLabel") })
- );
-
- var hConstraints = NSLayoutConstraint.FromVisualFormat(
- "H:|-" + lineFragmentPadding + "-[_placeholderLabel]-" + lineFragmentPadding + "-|",
- 0, new NSDictionary(),
- NSDictionary.FromObjectsAndKeys(
- new NSObject[] { _placeholderLabel }, new NSObject[] { new NSString("_placeholderLabel") })
- );
-
- _placeholderLabel.TranslatesAutoresizingMaskIntoConstraints = false;
-
- Control.AddConstraints(hConstraints);
- Control.AddConstraints(vConstraints);
- }
-
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
void HandleChanged(object sender, EventArgs e)
{
- ElementController.SetValueFromRenderer(Editor.TextProperty, Control.Text);
+ ElementController.SetValueFromRenderer(Editor.TextProperty, TextView.Text);
}
private void OnFrameChanged(object sender, EventArgs e)
// will resize until it can't anymore and thus it should never be scrolled until the Frame can't increase in size
if (Element.AutoSize == EditorAutoSizeOption.TextChanges)
{
- Control.ScrollRangeToVisible(new NSRange(0, 0));
+ TextView.ScrollRangeToVisible(new NSRange(0, 0));
}
}
void OnEnded(object sender, EventArgs eventArgs)
{
- if (Control.Text != Element.Text)
- ElementController.SetValueFromRenderer(Editor.TextProperty, Control.Text);
+ if (TextView.Text != Element.Text)
+ ElementController.SetValueFromRenderer(Editor.TextProperty, TextView.Text);
Element.SetValue(VisualElement.IsFocusedPropertyKey, false);
ElementController.SendCompleted();
void UpdateEditable()
{
- Control.Editable = Element.IsEnabled;
- Control.UserInteractionEnabled = Element.IsEnabled;
+ TextView.Editable = Element.IsEnabled;
+ TextView.UserInteractionEnabled = Element.IsEnabled;
- if (Control.InputAccessoryView != null)
- Control.InputAccessoryView.Hidden = !Element.IsEnabled;
+ if (TextView.InputAccessoryView != null)
+ TextView.InputAccessoryView.Hidden = !Element.IsEnabled;
}
- void UpdateFont()
+ protected internal virtual void UpdateFont()
{
var font = Element.ToUIFont();
- Control.Font = font;
- _placeholderLabel.Font = font;
+ TextView.Font = font;
}
void UpdateKeyboard()
{
var keyboard = Element.Keyboard;
- Control.ApplyKeyboard(keyboard);
+ TextView.ApplyKeyboard(keyboard);
if (!(keyboard is Internals.CustomKeyboard))
{
if (Element.IsSet(Xamarin.Forms.InputView.IsSpellCheckEnabledProperty))
{
if (!Element.IsSpellCheckEnabled)
{
- Control.SpellCheckingType = UITextSpellCheckingType.No;
+ TextView.SpellCheckingType = UITextSpellCheckingType.No;
}
}
if (Element.IsSet(Editor.IsTextPredictionEnabledProperty))
{
if (!Element.IsTextPredictionEnabled)
{
- Control.AutocorrectionType = UITextAutocorrectionType.No;
+ TextView.AutocorrectionType = UITextAutocorrectionType.No;
}
}
}
- Control.ReloadInputViews();
+ TextView.ReloadInputViews();
}
- void UpdateText()
+ protected internal virtual void UpdateText()
{
- if (Control.Text != Element.Text)
+ if (TextView.Text != Element.Text)
{
- Control.Text = Element.Text;
+ TextView.Text = Element.Text;
}
- _placeholderLabel.Hidden = !string.IsNullOrEmpty(Control.Text);
}
- void UpdatePlaceholderText()
- {
- _placeholderLabel.Text = Element.Placeholder;
- }
+ protected internal abstract void UpdatePlaceholderText();
+ protected internal abstract void UpdatePlaceholderColor();
- void UpdatePlaceholderColor()
- {
- if (Element.PlaceholderColor == Color.Default)
- _placeholderLabel.TextColor = UIColor.DarkGray;
- else
- _placeholderLabel.TextColor = Element.PlaceholderColor.ToUIColor();
- }
void UpdateTextAlignment()
{
- Control.UpdateTextAlignment(Element);
+ TextView.UpdateTextAlignment(Element);
}
- void UpdateTextColor()
+ protected internal virtual void UpdateTextColor()
{
var textColor = Element.TextColor;
if (textColor.IsDefault)
- Control.TextColor = UIColor.Black;
+ TextView.TextColor = UIColor.Black;
else
- Control.TextColor = textColor.ToUIColor();
+ TextView.TextColor = textColor.ToUIColor();
}
void UpdateMaxLength()
{
- var currentControlText = Control.Text;
+ var currentControlText = TextView.Text;
if (currentControlText.Length > Element.MaxLength)
- Control.Text = currentControlText.Substring(0, Element.MaxLength);
+ TextView.Text = currentControlText.Substring(0, Element.MaxLength);
}
bool ShouldChangeText(UITextView textView, NSRange range, string text)
void UpdateReadOnly()
{
+ TextView.UserInteractionEnabled = !Element.IsReadOnly;
+
+ // Control and TextView might be different
Control.UserInteractionEnabled = !Element.IsReadOnly;
}
UpdateEditable();
}
- internal class FormsUITextView : UITextView
+ internal class FormsUITextView : UITextView, IFormsUITextView
{
- public event EventHandler ContentSizeChanged;
public event EventHandler FrameChanged;
public FormsUITextView(RectangleF frame) : base(frame)
FrameChanged?.Invoke(this, EventArgs.Empty);
}
}
-
- public override CGSize ContentSize
- {
- get
- {
- return base.ContentSize;
- }
- set
- {
- base.ContentSize = value;
- ContentSizeChanged?.Invoke(this, EventArgs.Empty);
- }
- }
}
}
-}
+
+ internal interface IFormsUITextView
+ {
+ event EventHandler FrameChanged;
+ }
+}
\ No newline at end of file