<Label Text="Custom (Disabled)" Margin="0,0,0,-10" />
<Slider Minimum="-100" Maximum="100" IsEnabled="false"
ThumbColor="{StaticResource DarkRedColor}" MaximumTrackColor="{StaticResource SecondaryColor}" MinimumTrackColor="{StaticResource PrimaryColor}" />
+
+
+ <Label Text="Pickers" FontSize="Large"></Label>
+ <Label Text="Date Picker" Margin="0,0,0,-10" />
+ <DatePicker></DatePicker>
+ <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.ItemsSource>
+ <x:Array Type="{x:Type x:String}">
+ <x:String>Baboon</x:String>
+ <x:String>Capuchin Monkey</x:String>
+ <x:String>Blue Monkey</x:String>
+ <x:String>Squirrel Monkey</x:String>
+ <x:String>Golden Lion Tamarin</x:String>
+ <x:String>Howler Monkey</x:String>
+ <x:String>Japanese Macaque</x:String>
+ </x:Array>
+ </Picker.ItemsSource>
+ </Picker>
<Label Text="Steppers" FontSize="Large" />
<Label Text="Default" Margin="0,0,0,-10" />
</ItemGroup>
<Import Project="..\Xamarin.Flex\Xamarin.Flex.projitems" Label="Shared" Condition="Exists('..\Xamarin.Flex\Xamarin.Flex.projitems')" />
<UsingTask TaskName="XFCorePostProcessor.Tasks.FixXFCoreAssembly" AssemblyFile="..\XFCorePostProcessor.Tasks\bin\Debug\net461\XFCorePostProcessor.Tasks.dll" />
- <Target
- Condition="$(DesignTimeBuild) != true AND $(BuildingProject) == true"
- AfterTargets="AfterCompile"
- Name="XFCorePostProcessor"
- Inputs="$(IntermediateOutputPath)$(TargetFileName)"
- Outputs="$(IntermediateOutputPath)XFCorePostProcessor.stamp">
- <Touch
- Files="$(IntermediateOutputPath)XFCorePostProcessor.stamp"
- AlwaysCreate="True" />
- <FixXFCoreAssembly
- Assembly="$(IntermediateOutputPath)$(TargetFileName)"
- ReferencePath="@(ReferencePath)" />
+ <Target Condition="$(DesignTimeBuild) != true AND $(BuildingProject) == true" AfterTargets="AfterCompile" Name="XFCorePostProcessor" Inputs="$(IntermediateOutputPath)$(TargetFileName)" Outputs="$(IntermediateOutputPath)XFCorePostProcessor.stamp">
+ <Touch Files="$(IntermediateOutputPath)XFCorePostProcessor.stamp" AlwaysCreate="True" />
+ <FixXFCoreAssembly Assembly="$(IntermediateOutputPath)$(TargetFileName)" ReferencePath="@(ReferencePath)" />
</Target>
</Project>
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using Foundation;
+using UIKit;
+
+namespace Xamarin.Forms.Platform.iOS.Material
+{
+ public interface IMaterialEntryRenderer
+ {
+ Color TextColor { get; }
+ Color PlaceholderColor { get; }
+ Color BackgroundColor { get; }
+ string Placeholder { get; }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System.ComponentModel;
+using UIKit;
+
+namespace Xamarin.Forms.Platform.iOS.Material
+{
+ public class MaterialDatePickerRenderer : DatePickerRendererBase<MaterialTextField>, IMaterialEntryRenderer
+ {
+ public MaterialDatePickerRenderer()
+ {
+ VisualElement.VerifyVisualFlagEnabled();
+ }
+
+ protected override MaterialTextField CreateNativeControl()
+ {
+ var field = new NoCaretMaterialTextField(this, Element);
+ return field;
+ }
+
+ protected override void SetBackgroundColor(Color color)
+ {
+ ApplyTheme();
+ }
+
+ protected internal override void UpdateFont()
+ {
+ base.UpdateFont();
+ Control?.ApplyTypographyScheme(Element);
+ }
+
+
+ protected internal override void UpdateTextColor()
+ {
+ Control?.UpdateTextColor(this);
+ }
+
+
+ protected virtual void ApplyTheme()
+ {
+ Control?.ApplyTheme(this);
+ }
+
+ internal void UpdatePlaceholder()
+ {
+ Control?.UpdatePlaceholder(this);
+ }
+
+ protected override void OnElementChanged(ElementChangedEventArgs<DatePicker> e)
+ {
+ base.OnElementChanged(e);
+ UpdatePlaceholder();
+ }
+
+ string IMaterialEntryRenderer.Placeholder => string.Empty;
+ Color IMaterialEntryRenderer.PlaceholderColor => Color.Default;
+
+ Color IMaterialEntryRenderer.TextColor => Element?.TextColor ?? Color.Default;
+ Color IMaterialEntryRenderer.BackgroundColor => Element?.BackgroundColor ?? Color.Default;
+ }
+}
\ No newline at end of file
-using System;
-using System.ComponentModel;
-
-using System.Drawing;
-using CoreGraphics;
-using Foundation;
-using UIKit;
-using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
-using Specifics = Xamarin.Forms.PlatformConfiguration.iOSSpecific.Entry;
-using MTextField = MaterialComponents.TextField;
-using MTextInputControllerOutlined = MaterialComponents.TextInputControllerOutlined;
-using MTextInputControllerFilled = MaterialComponents.TextInputControllerFilled;
-using MTextInputControllerBase = MaterialComponents.TextInputControllerBase;
-using MTextInputControllerUnderline = MaterialComponents.TextInputControllerUnderline;
-
-using Xamarin.Forms;
-using MaterialComponents;
+using UIKit;
namespace Xamarin.Forms.Platform.iOS.Material
{
- public class MaterialEntryRenderer : EntryRenderer
+ public class MaterialEntryRenderer : EntryRendererBase<MaterialTextField>, IMaterialEntryRenderer
{
- SemanticColorScheme _colorScheme;
- TypographyScheme _typographyScheme;
-
public MaterialEntryRenderer()
{
VisualElement.VerifyVisualFlagEnabled();
- _colorScheme = (SemanticColorScheme)CreateColorScheme();
- _typographyScheme = CreateTypographyScheme();
}
- public override CGSize SizeThatFits(CGSize size)
- {
- var result = base.SizeThatFits(size);
- if (nfloat.IsInfinity(result.Width))
- result = Control.SystemLayoutSizeFittingSize(result, (float)UILayoutPriority.FittingSizeLevel, (float)UILayoutPriority.DefaultHigh);
-
- return result;
- }
-
- IElementController ElementController => Element as IElementController;
- MTextInputControllerBase _activeTextinputController;
-
- public new MTextField Control { get; private set; }
-
- protected override UITextField CreateNativeControl()
+ protected override MaterialTextField CreateNativeControl()
{
- var field = new MTextField();
- Control = field;
- field.ClearButtonMode = UITextFieldViewMode.Never;
- _activeTextinputController = new MTextInputControllerFilled(field);
- field.TextInsetsMode = TextInputTextInsetsMode.IfContent;
- ApplyTypographyScheme();
- ApplyTheme();
-
+ var field = new MaterialTextField(this, Element);
return field;
}
- protected virtual IColorScheming CreateColorScheme()
- {
- var returnValue = MaterialColors.Light.CreateColorScheme();
-
- return returnValue;
- }
-
- protected virtual TypographyScheme CreateTypographyScheme()
- {
- return new TypographyScheme();
- }
-
protected override void SetBackgroundColor(Color color)
{
ApplyTheme();
}
- void ApplyTypographyScheme()
- {
- if (Control == null)
- return;
-
- _typographyScheme.Subtitle1 = Control.Font;
- TextFieldTypographyThemer.ApplyTypographyScheme(_typographyScheme, Control);
- TextFieldTypographyThemer.ApplyTypographyScheme(_typographyScheme, _activeTextinputController);
- }
-
protected internal override void UpdateFont()
{
base.UpdateFont();
- ApplyTypographyScheme();
+ Control?.ApplyTypographyScheme(Element);
}
protected internal override void UpdateColor()
{
- var uIColor = MaterialColors.GetEntryTextColor(Element.TextColor);
-
- _colorScheme.OnSurfaceColor = uIColor;
- _colorScheme.PrimaryColor = uIColor;
-
- ApplyTheme();
+ Control?.UpdateTextColor(this);
}
protected virtual void ApplyTheme()
{
- if (_activeTextinputController == null)
- return;
-
- FilledTextFieldColorThemer.ApplySemanticColorScheme(_colorScheme, (MTextInputControllerFilled)_activeTextinputController);
-
- OverrideThemeColors();
- }
-
- protected virtual void OverrideThemeColors()
- {
- var textColor = MaterialColors.GetEntryTextColor(Element.TextColor);
- var placeHolderColors = MaterialColors.GetPlaceHolderColor(Element.PlaceholderColor, Element.TextColor);
- var underlineColors = MaterialColors.GetUnderlineColor(Element.TextColor);
-
- Control.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;
+ Control?.ApplyTheme(this);
}
protected internal override void UpdatePlaceholder()
{
- var placeholderText = Element.Placeholder;
+ Control?.UpdatePlaceholder(this);
+
+ }
- if (placeholderText == null)
- return;
- _activeTextinputController.PlaceholderText = placeholderText;
- ApplyTheme();
- }
+ Color IMaterialEntryRenderer.TextColor => Element?.TextColor ?? Color.Default;
+ Color IMaterialEntryRenderer.PlaceholderColor => Element?.PlaceholderColor ?? Color.Default;
+ Color IMaterialEntryRenderer.BackgroundColor => Element?.BackgroundColor ?? Color.Default;
+ string IMaterialEntryRenderer.Placeholder => Element?.Placeholder ?? string.Empty;
}
}
\ No newline at end of file
--- /dev/null
+using System.ComponentModel;
+using UIKit;
+
+namespace Xamarin.Forms.Platform.iOS.Material
+{
+ public class MaterialPickerRenderer : PickerRendererBase<MaterialTextField>, IMaterialEntryRenderer
+ {
+ public MaterialPickerRenderer()
+ {
+ VisualElement.VerifyVisualFlagEnabled();
+ }
+
+ protected override MaterialTextField CreateNativeControl()
+ {
+ var field = new ReadOnlyMaterialTextField(this, Element);
+ return field;
+ }
+
+ protected override void SetBackgroundColor(Color color)
+ {
+ ApplyTheme();
+ }
+
+ protected internal override void UpdateFont()
+ {
+ base.UpdateFont();
+ Control?.ApplyTypographyScheme(Element);
+ }
+
+
+ protected internal override void UpdateTextColor()
+ {
+ Control?.UpdateTextColor(this);
+ }
+
+
+ protected virtual void ApplyTheme()
+ {
+ Control?.ApplyTheme(this);
+ }
+
+ protected internal override void UpdatePlaceholder()
+ {
+ Control?.UpdatePlaceholder(this);
+ }
+
+ protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
+ {
+ base.OnElementChanged(e);
+ UpdatePlaceholder();
+ }
+
+ string IMaterialEntryRenderer.Placeholder => string.Empty;
+ Color IMaterialEntryRenderer.PlaceholderColor => Color.Default;
+ Color IMaterialEntryRenderer.TextColor => Element?.TextColor ?? Color.Default;
+ Color IMaterialEntryRenderer.BackgroundColor => Element?.BackgroundColor ?? Color.Default;
+
+ }
+}
\ No newline at end of file
--- /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
+{
+ public class MaterialTextField : MTextField
+ {
+ SemanticColorScheme _colorScheme;
+ TypographyScheme _typographyScheme;
+ MTextInputControllerBase _activeTextinputController;
+
+ 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);
+
+ }
+
+ public override CGSize SizeThatFits(CGSize size)
+ {
+ var result = base.SizeThatFits(size);
+
+ if (nfloat.IsInfinity(result.Width))
+ result = SystemLayoutSizeFittingSize(result, (float)UILayoutPriority.FittingSizeLevel, (float)UILayoutPriority.DefaultHigh);
+
+ 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 UpdateTextColor(IMaterialEntryRenderer element)
+ {
+ var uIColor = MaterialColors.GetEntryTextColor(element.TextColor);
+ _colorScheme.OnSurfaceColor = uIColor;
+ _colorScheme.PrimaryColor = uIColor;
+ }
+
+ protected virtual IColorScheming CreateColorScheme()
+ {
+ var returnValue = MaterialColors.Light.CreateColorScheme();
+ return returnValue;
+ }
+
+ protected virtual TypographyScheme CreateTypographyScheme()
+ {
+ return new TypographyScheme();
+ }
+ }
+
+
+ internal class NoCaretMaterialTextField : MaterialTextField
+ {
+ public NoCaretMaterialTextField(IMaterialEntryRenderer element, IFontElement fontElement) : base(element, fontElement)
+ {
+ SpellCheckingType = UITextSpellCheckingType.No;
+ AutocorrectionType = UITextAutocorrectionType.No;
+ AutocapitalizationType = UITextAutocapitalizationType.None;
+ }
+
+ public override CGRect GetCaretRectForPosition(UITextPosition position)
+ {
+ return new CGRect();
+ }
+ }
+
+ internal class ReadOnlyMaterialTextField : NoCaretMaterialTextField
+ {
+ readonly HashSet<string> enableActions;
+
+ public ReadOnlyMaterialTextField(IMaterialEntryRenderer element, IFontElement fontElement) : base(element, fontElement)
+ {
+ string[] actions = { "copy:", "select:", "selectAll:" };
+ enableActions = new HashSet<string>(actions);
+ }
+
+ public override bool CanPerform(Selector action, NSObject withSender)
+ => enableActions.Contains(action.Name);
+ }
+}
\ No newline at end of file
--- /dev/null
+using System.ComponentModel;
+using UIKit;
+
+namespace Xamarin.Forms.Platform.iOS.Material
+{
+ public class MaterialTimePickerRenderer : TimePickerRendererBase<MaterialTextField>, IMaterialEntryRenderer
+ {
+ public MaterialTimePickerRenderer()
+ {
+ VisualElement.VerifyVisualFlagEnabled();
+ }
+
+ protected override MaterialTextField CreateNativeControl()
+ {
+ var field = new NoCaretMaterialTextField(this, Element);
+ return field;
+ }
+
+ protected override void SetBackgroundColor(Color color)
+ {
+ ApplyTheme();
+ }
+
+ protected internal override void UpdateFont()
+ {
+ base.UpdateFont();
+ Control?.ApplyTypographyScheme(Element);
+ }
+
+ protected internal override void UpdateTextColor()
+ {
+ Control?.UpdateTextColor(this);
+ }
+
+
+ protected virtual void ApplyTheme()
+ {
+ Control?.ApplyTheme(this);
+ }
+
+ internal void UpdatePlaceholder()
+ {
+ Control?.UpdatePlaceholder(this);
+ }
+
+ protected override void OnElementChanged(ElementChangedEventArgs<TimePicker> e)
+ {
+ base.OnElementChanged(e);
+ UpdatePlaceholder();
+ }
+
+ string IMaterialEntryRenderer.Placeholder => string.Empty;
+ Color IMaterialEntryRenderer.PlaceholderColor => Color.Default;
+
+ Color IMaterialEntryRenderer.TextColor => Element?.TextColor ?? Color.Default;
+ Color IMaterialEntryRenderer.BackgroundColor => Element?.BackgroundColor ?? Color.Default;
+ }
+}
\ No newline at end of file
[assembly: ExportRenderer(typeof(Xamarin.Forms.Entry), typeof(Xamarin.Forms.Platform.iOS.Material.MaterialEntryRenderer), new[] { typeof(VisualRendererMarker.Material) })]
[assembly: ExportRenderer(typeof(Xamarin.Forms.Frame), typeof(Xamarin.Forms.Platform.iOS.Material.MaterialFrameRenderer), new[] { typeof(VisualRendererMarker.Material) })]
[assembly: ExportRenderer(typeof(Xamarin.Forms.ProgressBar), typeof(Xamarin.Forms.Platform.iOS.Material.MaterialProgressBarRenderer), new[] { typeof(VisualRendererMarker.Material) })]
-[assembly: ExportRenderer(typeof(Xamarin.Forms.Slider), typeof(Xamarin.Forms.Platform.iOS.Material.MaterialSliderRenderer), new[] { typeof(VisualRendererMarker.Material) })]
\ No newline at end of file
+[assembly: ExportRenderer(typeof(Xamarin.Forms.Slider), typeof(Xamarin.Forms.Platform.iOS.Material.MaterialSliderRenderer), new[] { typeof(VisualRendererMarker.Material) })]
+[assembly: ExportRenderer(typeof(Xamarin.Forms.TimePicker), typeof(Xamarin.Forms.Platform.iOS.Material.MaterialTimePickerRenderer), new[] { typeof(VisualRendererMarker.Material) })]
+[assembly: ExportRenderer(typeof(Xamarin.Forms.Picker), typeof(Xamarin.Forms.Platform.iOS.Material.MaterialPickerRenderer), new[] { typeof(VisualRendererMarker.Material) })]
+[assembly: ExportRenderer(typeof(Xamarin.Forms.DatePicker), typeof(Xamarin.Forms.Platform.iOS.Material.MaterialDatePickerRenderer), new[] { typeof(VisualRendererMarker.Material) })]
\ No newline at end of file
<Compile Include="..\Xamarin.Forms.Platform.Android\Material\MaterialColors.cs">
<Link>MaterialColors.cs</Link>
</Compile>
+ <Compile Include="IMaterialEntryRenderer.cs" />
+ <Compile Include="MaterialPickerRenderer.cs" />
+ <Compile Include="MaterialDatePickerRenderer.cs" />
+ <Compile Include="MaterialTimePickerRenderer.cs" />
+ <Compile Include="MaterialTextField.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="MaterialActivityIndicatorRenderer.cs" />
<Compile Include="MaterialButtonRenderer.cs" />
using System.Linq;
using Android.Content;
using Android.Widget;
-using AColor = Android.Graphics.Color;
using Android.Text;
using Android.Text.Style;
namespace Xamarin.Forms.Platform.Android.AppCompat
{
- public class PickerRenderer : ViewRenderer<Picker, EditText>, IPickerRenderer
+ public abstract class PickerRendererBase<TControl> : ViewRenderer<Picker, TControl>, IPickerRenderer
+ where TControl : global::Android.Views.View
{
AlertDialog _dialog;
bool _disposed;
- TextColorSwitcher _textColorSwitcher;
- int _originalHintTextColor;
- public PickerRenderer(Context context) : base(context)
+ public PickerRendererBase(Context context) : base(context)
{
AutoPackage = false;
}
[Obsolete("This constructor is obsolete as of version 2.5. Please use PickerRenderer(Context) instead.")]
[EditorBrowsable(EditorBrowsableState.Never)]
- public PickerRenderer()
+ public PickerRendererBase()
{
AutoPackage = false;
}
- protected override EditText CreateNativeControl()
- {
- return new PickerEditText(Context, this);
- }
+ protected abstract EditText EditText { get; }
protected override void Dispose(bool disposing)
{
if (Control == null)
{
var textField = CreateNativeControl();
-
- var useLegacyColorManagement = e.NewElement.UseLegacyColorManagement();
- _textColorSwitcher = new TextColorSwitcher(textField.TextColors, useLegacyColorManagement);
-
SetNativeControl(textField);
-
- _originalHintTextColor = Control.CurrentHintTextColor;
}
UpdateFont();
UpdatePicker();
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 UpdatePicker()
{
- Control.Hint = Element.Title;
-
- if (Element.IsSet(Picker.TitleColorProperty))
- Control.SetHintTextColor(Element.TitleColor.ToAndroid());
- else
- Control.SetHintTextColor(new AColor(_originalHintTextColor));
+ UpdatePlaceHolderText();
+ UpdateTitleColor();
if (Element.SelectedIndex == -1 || Element.Items == null || Element.SelectedIndex >= Element.Items.Count)
- Control.Text = null;
+ EditText.Text = null;
else
- Control.Text = Element.Items[Element.SelectedIndex];
+ EditText.Text = Element.Items[Element.SelectedIndex];
+ }
+
+ abstract protected void UpdateTextColor();
+ abstract protected internal void UpdateTitleColor();
+ abstract protected internal void UpdatePlaceHolderText();
+ }
+
+ public class PickerRenderer : PickerRendererBase<EditText>
+ {
+ TextColorSwitcher _textColorSwitcher;
+ TextColorSwitcher _hintColorSwitcher;
+
+ [Obsolete("This constructor is obsolete as of version 2.5. Please use PickerRenderer(Context) instead.")]
+ public PickerRenderer()
+ {
+ }
+
+ public PickerRenderer(Context context) : base(context)
+ {
+ }
+
+ protected override EditText CreateNativeControl()
+ {
+ return new PickerEditText(Context);
+ }
+
+ protected override EditText EditText => Control;
+
+ protected internal override void UpdateTitleColor()
+ {
+ _hintColorSwitcher = _hintColorSwitcher ?? new TextColorSwitcher(EditText.HintTextColors, Element.UseLegacyColorManagement());
+ _hintColorSwitcher.UpdateTextColor(EditText, Element.TitleColor, EditText.SetHintTextColor);
}
- void UpdateTextColor()
+ protected override void UpdateTextColor()
{
- _textColorSwitcher?.UpdateTextColor(Control, Element.TextColor);
+ _textColorSwitcher = _textColorSwitcher ?? new TextColorSwitcher(EditText.TextColors, Element.UseLegacyColorManagement());
+ _textColorSwitcher.UpdateTextColor(EditText, Element.TextColor);
}
+ protected internal override void UpdatePlaceHolderText() => EditText.Hint = Element.Title;
}
}
\ No newline at end of file
#if __ANDROID__
using Android.Content.Res;
using Android.Graphics;
-using AColor = Android.Graphics.Color;
using AProgressBar = Android.Widget.ProgressBar;
using ASeekBar = Android.Widget.AbsSeekBar;
+using PlatformColor = Android.Graphics.Color;
#else
using MaterialComponents;
-using AColor = UIKit.UIColor;
+using PlatformColor = UIKit.UIColor;
#endif
#if __ANDROID__
// State list from material-components-android
// https://github.com/material-components/material-components-android/blob/71694616056012fe1162adb9144be903d1e510d5/lib/java/com/google/android/material/textfield/res/values/colors.xml#L28
- public static AColor CreateEntryFilledInputBackgroundColor(Color backgroundColor, Color textColor)
+ public static PlatformColor CreateEntryFilledInputBackgroundColor(Color backgroundColor, Color textColor)
{
var platformTextColor = GetEntryTextColor(textColor);
return ToPlatformColor(backgroundColor);
}
- public static (AColor InlineColor, AColor FloatingColor) GetPlaceHolderColor(Color placeholderColor, Color textColor)
+ public static (PlatformColor InlineColor, PlatformColor FloatingColor) GetPlaceHolderColor(Color placeholderColor, Color textColor)
{
- AColor color;
+ PlatformColor color;
if (placeholderColor == Color.Default)
{
return (inlineColor, floatingColor);
}
- public static (AColor FocusedColor, AColor UnFocusedColor) GetUnderlineColor(Color textColor)
+ public static (PlatformColor FocusedColor, PlatformColor UnFocusedColor) GetUnderlineColor(Color textColor)
{
- AColor color = GetEntryTextColor(textColor);
+ PlatformColor color = GetEntryTextColor(textColor);
return (color, WithAlpha(color, kFilledTextFieldIndicatorLineAlpha));
}
- public static AColor GetEntryTextColor(Color textColor)
+ public static PlatformColor GetEntryTextColor(Color textColor)
{
return textColor != Color.Default ? ToPlatformColor(textColor) : MaterialColors.Light.PrimaryColor;
}
// State list from material-components-android
// https://github.com/material-components/material-components-android/blob/3637c23078afc909e42833fd1c5fd47bb3271b5f/lib/java/com/google/android/material/button/res/color/mtrl_btn_bg_color_selector.xml
- public static ColorStateList CreateButtonBackgroundColors(AColor primary)
+ public static ColorStateList CreateButtonBackgroundColors(PlatformColor primary)
{
var colors = new int[] { primary, primary.WithAlpha(0.12) };
return new ColorStateList(ButtonStates, colors);
// State list from material-components-android
// https://github.com/material-components/material-components-android/blob/3637c23078afc909e42833fd1c5fd47bb3271b5f/lib/java/com/google/android/material/button/res/color/mtrl_btn_text_color_selector.xml
- public static ColorStateList CreateButtonTextColors(AColor primary, AColor text)
+ public static ColorStateList CreateButtonTextColors(PlatformColor primary, PlatformColor text)
{
var colors = new int[] { text, primary.WithAlpha(0.38) };
return new ColorStateList(ButtonStates, colors);
}
- public static ColorStateList CreateEntryFilledPlaceholderColors(AColor inlineColor, AColor floatingColor)
+ public static ColorStateList CreateEntryFilledPlaceholderColors(PlatformColor inlineColor, PlatformColor floatingColor)
{
int[][] States =
{
return new ColorStateList(States, colors);
}
- public static ColorStateList CreateEntryUnderlineColors(AColor focusedColor, AColor unfocusedColor)
+ public static ColorStateList CreateEntryUnderlineColors(PlatformColor focusedColor, PlatformColor unfocusedColor)
{
var colors = new int[] { focusedColor, unfocusedColor };
return new ColorStateList(EntryUnderlineStates, colors);
}
- internal static AColor WithAlpha(this AColor color, double alpha) =>
- new AColor(color.R, color.G, color.B, (byte)(alpha * 255));
+ internal static PlatformColor WithAlpha(this PlatformColor color, double alpha) =>
+ new PlatformColor(color.R, color.G, color.B, (byte)(alpha * 255));
internal static void ApplySeekBarColors(this ASeekBar seekBar, Color progressColor, Color backgroundColor, Color thumbColor)
{
internal static void ApplyProgressBarColors(this AProgressBar progressBar, Color progressColor, Color backgroundColor)
{
- AColor defaultProgress = Dark.PrimaryColor;
+ PlatformColor defaultProgress = Dark.PrimaryColor;
if (progressColor.IsDefault)
{
{
// the Colors for "branding"
// - we selected the "black" theme from the default DarkActionBar theme
- public static readonly AColor PrimaryColor = FromRgb(33, 33, 33);
- public static readonly AColor PrimaryColorVariant = AColor.Black;
- public static readonly AColor OnPrimaryColor = AColor.White;
- public static readonly AColor SecondaryColor = FromRgb(33, 33, 33);
- public static readonly AColor OnSecondaryColor = AColor.White;
+ public static readonly PlatformColor PrimaryColor = FromRgb(33, 33, 33);
+ public static readonly PlatformColor PrimaryColorVariant = PlatformColor.Black;
+ public static readonly PlatformColor OnPrimaryColor = PlatformColor.White;
+ public static readonly PlatformColor SecondaryColor = FromRgb(33, 33, 33);
+ public static readonly PlatformColor OnSecondaryColor = PlatformColor.White;
// the Colors for "UI"
- public static readonly AColor BackgroundColor = AColor.White;
- public static readonly AColor OnBackgroundColor = AColor.Black;
- public static readonly AColor SurfaceColor = AColor.White;
- public static readonly AColor OnSurfaceColor = AColor.Black;
- public static readonly AColor ErrorColor = FromRgb(176, 0, 32);
- public static readonly AColor OnErrorColor = AColor.White;
+ public static readonly PlatformColor BackgroundColor = PlatformColor.White;
+ public static readonly PlatformColor OnBackgroundColor = PlatformColor.Black;
+ public static readonly PlatformColor SurfaceColor = PlatformColor.White;
+ public static readonly PlatformColor OnSurfaceColor = PlatformColor.Black;
+ public static readonly PlatformColor ErrorColor = FromRgb(176, 0, 32);
+ public static readonly PlatformColor OnErrorColor = PlatformColor.White;
#if __IOS__
public static SemanticColorScheme CreateColorScheme()
{
// the Colors for "branding"
// - we selected the "black" theme from the default DarkActionBar theme
- public static readonly AColor PrimaryColor = FromRgb(33, 33, 33);
- public static readonly AColor PrimaryColorVariant = AColor.Black;
- public static readonly AColor OnPrimaryColor = AColor.White;
- public static readonly AColor SecondaryColor = FromRgb(33, 33, 33);
- public static readonly AColor OnSecondaryColor = AColor.White;
+ public static readonly PlatformColor PrimaryColor = FromRgb(33, 33, 33);
+ public static readonly PlatformColor PrimaryColorVariant = PlatformColor.Black;
+ public static readonly PlatformColor OnPrimaryColor = PlatformColor.White;
+ public static readonly PlatformColor SecondaryColor = FromRgb(33, 33, 33);
+ public static readonly PlatformColor OnSecondaryColor = PlatformColor.White;
// the Colors for "UI"
- public static readonly AColor BackgroundColor = FromRgb(20, 20, 20);
- public static readonly AColor OnBackgroundColor = AColor.White;
- public static readonly AColor SurfaceColor = FromRgb(40, 40, 40);
- public static readonly AColor OnSurfaceColor = AColor.White;
- public static readonly AColor ErrorColor = FromRgb(194, 108, 122);
- public static readonly AColor OnErrorColor = AColor.White;
+ public static readonly PlatformColor BackgroundColor = FromRgb(20, 20, 20);
+ public static readonly PlatformColor OnBackgroundColor = PlatformColor.White;
+ public static readonly PlatformColor SurfaceColor = FromRgb(40, 40, 40);
+ public static readonly PlatformColor OnSurfaceColor = PlatformColor.White;
+ public static readonly PlatformColor ErrorColor = FromRgb(194, 108, 122);
+ public static readonly PlatformColor OnErrorColor = PlatformColor.White;
#if __IOS__
public static SemanticColorScheme CreateColorScheme()
}
- static AColor ToPlatformColor(Color color)
+ static PlatformColor ToPlatformColor(Color color)
{
#if __ANDROID__
return color.ToAndroid();
- static AColor WithMultipliedAlpha(AColor color, float alpha)
+ static PlatformColor WithMultipliedAlpha(PlatformColor color, float alpha)
{
#if __ANDROID__
return color.WithAlpha(color.A / 255f * alpha);
#endif
}
- static AColor WithAlpha(AColor color, float alpha)
+ static PlatformColor WithAlpha(PlatformColor color, float alpha)
{
#if __ANDROID__
return color.WithAlpha(alpha);
}
- static AColor FromRgb(int red, int green, int blue)
+ static PlatformColor FromRgb(int red, int green, int blue)
{
#if __ANDROID__
- return AColor.Rgb(red, green, blue);
+ return PlatformColor.Rgb(red, green, blue);
#else
- return AColor.FromRGB(red, green, blue);
+ return PlatformColor.FromRGB(red, green, blue);
#endif
}
--- /dev/null
+#if __ANDROID_28__
+using System.ComponentModel;
+using Android.Content;
+using Android.Support.V4.View;
+using Android.Views;
+using Android.Widget;
+using Xamarin.Forms;
+using Xamarin.Forms.Platform.Android.Material;
+
+[assembly: ExportRenderer(typeof(Xamarin.Forms.DatePicker), typeof(MaterialDatePickerRenderer), new[] { typeof(VisualRendererMarker.Material) })]
+
+namespace Xamarin.Forms.Platform.Android.Material
+{
+ public class MaterialDatePickerRenderer : DatePickerRendererBase<MaterialPickerTextInputLayout>
+ {
+ MaterialPickerTextInputLayout _textInputLayout;
+ MaterialPickerEditText _textInputEditText;
+
+ public MaterialDatePickerRenderer(Context context) : base(MaterialContextThemeWrapper.Create(context))
+ {
+ }
+
+ protected override EditText EditText => _textInputEditText;
+
+ protected override MaterialPickerTextInputLayout CreateNativeControl()
+ {
+ LayoutInflater inflater = LayoutInflater.FromContext(Context);
+ var view = inflater.Inflate(Resource.Layout.MaterialPickerTextInput, null);
+ _textInputLayout = (MaterialPickerTextInputLayout)view;
+ _textInputEditText = _textInputLayout.FindViewById<MaterialPickerEditText>(Resource.Id.materialformsedittext);
+
+ return _textInputLayout;
+ }
+
+ protected override void OnElementChanged(ElementChangedEventArgs<DatePicker> e)
+ {
+ base.OnElementChanged(e);
+ _textInputLayout.SetHint(string.Empty, Element);
+ }
+
+ protected override void UpdateBackgroundColor()
+ {
+ if (_textInputLayout == null)
+ return;
+
+ _textInputLayout.BoxBackgroundColor = MaterialColors.CreateEntryFilledInputBackgroundColor(Element.BackgroundColor, Element.TextColor);
+ }
+
+ protected override void UpdateTextColor() => ApplyTheme();
+ void ApplyTheme() => _textInputLayout?.ApplyTheme(Element.TextColor, Color.Default);
+
+ }
+}
+#endif
\ No newline at end of file
#if __ANDROID_28__
-using System.Threading.Tasks;
using Android.Content;
-using Android.Content.Res;
using Android.OS;
using Android.Support.V4.View;
using Android.Util;
using Android.Widget;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android.Material;
-using AColor = Android.Graphics.Color;
[assembly: ExportRenderer(typeof(Xamarin.Forms.Entry), typeof(MaterialEntryRenderer), new[] { typeof(VisualRendererMarker.Material) })]
namespace Xamarin.Forms.Platform.Android.Material
public sealed class MaterialEntryRenderer : EntryRendererBase<MaterialFormsTextInputLayout>
{
bool _disposed;
- private MaterialFormsEditText _textInputEditText;
- private MaterialFormsTextInputLayout _textInputLayout;
+ MaterialFormsEditText _textInputEditText;
+ MaterialFormsTextInputLayout _textInputLayout;
public MaterialEntryRenderer(Context context) :
base(MaterialContextThemeWrapper.Create(context))
var view = inflater.Inflate(Resource.Layout.TextInputLayoutFilledBox, null);
_textInputLayout = (MaterialFormsTextInputLayout)view;
_textInputEditText = _textInputLayout.FindViewById<MaterialFormsEditText>(Resource.Id.materialformsedittext);
- _textInputEditText.FocusChange += TextInputEditTextFocusChange;
- _textInputLayout.Hint = Element.Placeholder;
return _textInputLayout;
}
base.Dispose(disposing);
}
-
- void TextInputEditTextFocusChange(object sender, FocusChangeEventArgs e)
- {
- // TODO figure out better way to do this
- // this is a hack that changes the active underline color from the accent color to whatever the user
- // specified
- Device.BeginInvokeOnMainThread(() => UpdatePlaceholderColor());
- }
-
- protected internal override void UpdateColor() => ApplyTheme();
+ protected override void UpdateTextColor() => ApplyTheme();
protected override void UpdateBackgroundColor()
{
protected internal override void UpdatePlaceHolderText()
{
- _textInputLayout.Hint = Element.Placeholder;
+ _textInputLayout.SetHint(Element.Placeholder, Element);
+ Element.InvalidateMeasureNonVirtual(Internals.InvalidationTrigger.VerticalOptionsChanged);
}
- protected internal override void UpdatePlaceholderColor() => ApplyTheme();
-
- void ApplyTheme()
- {
- if (_textInputLayout == null)
- return;
-
- // set text color
- var textColor = MaterialColors.GetEntryTextColor(Element.TextColor);
- UpdateTextColor(Color.FromUint((uint)textColor.ToArgb()));
-
- var placeHolderColors = MaterialColors.GetPlaceHolderColor(Element.PlaceholderColor, Element.TextColor);
- var underlineColors = MaterialColors.GetUnderlineColor(Element.TextColor);
-
- var colors = MaterialColors.CreateEntryUnderlineColors(underlineColors.FocusedColor, underlineColors.UnFocusedColor);
-
- ViewCompat.SetBackgroundTintList(_textInputEditText, colors);
-
-
- if (HasFocus || !string.IsNullOrWhiteSpace(_textInputEditText.Text))
- _textInputLayout.DefaultHintTextColor = MaterialColors.CreateEntryFilledPlaceholderColors(placeHolderColors.FloatingColor, placeHolderColors.FloatingColor);
- else
- _textInputLayout.DefaultHintTextColor = MaterialColors.CreateEntryFilledPlaceholderColors(placeHolderColors.InlineColor, placeHolderColors.FloatingColor);
- }
+
+ protected override void UpdatePlaceholderColor() => ApplyTheme();
+ void ApplyTheme() => _textInputLayout?.ApplyTheme(Element.TextColor, Element.PlaceholderColor);
protected internal override void UpdateFont()
{
#if __ANDROID_28__
using System;
using Android.Content;
-using Android.Graphics;
using Android.Views;
-using Android.Widget;
-using Android.Support.V4.Graphics.Drawable;
-using Android.Support.Design.Widget;
using Android.Runtime;
using Android.Util;
-
namespace Xamarin.Forms.Platform.Android.Material
{
-
- public class MaterialFormsTextInputLayout : TextInputLayout
+ public class MaterialFormsEditText : MaterialFormsEditTextBase, IFormsEditText
{
- public MaterialFormsTextInputLayout(Context context) : base(context)
- {
- Init();
- }
-
- public MaterialFormsTextInputLayout(Context context, IAttributeSet attrs) : base(context, attrs)
- {
- Init();
- }
-
- public MaterialFormsTextInputLayout(Context context, IAttributeSet attrs, int defStyleAttr) : base(context, attrs, defStyleAttr)
- {
- Init();
- }
-
- protected MaterialFormsTextInputLayout(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
- {
- Init();
- }
-
- void Init()
- {
- VisualElement.VerifyVisualFlagEnabled();
- }
-
- }
-
- public class MaterialFormsEditText : TextInputEditText, IDescendantFocusToggler, IFormsEditText
- {
- DescendantFocusToggler _descendantFocusToggler;
-
- // These paddings are a hack to center the hint
- // once this issue is resolved we can get rid of these paddings
- // https://github.com/material-components/material-components-android/issues/120
- // https://stackoverflow.com/questions/50487871/how-to-make-the-hint-text-of-textinputlayout-vertically-center
-
- static Thickness _centeredText = new Thickness(16, 8, 12, 27);
- static Thickness _alignedWithUnderlineText = new Thickness(16, 20, 12, 16);
public MaterialFormsEditText(Context context) : base(context)
{
- Init();
}
protected MaterialFormsEditText(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
{
- Init();
}
public MaterialFormsEditText(Context context, IAttributeSet attrs) : base(context, attrs)
{
- Init();
}
public MaterialFormsEditText(Context context, IAttributeSet attrs, int defStyleAttr) : base(context, attrs, defStyleAttr)
{
- Init();
}
- void Init()
- {
- VisualElement.VerifyVisualFlagEnabled();
- UpdatePadding();
- }
-
- void UpdatePadding()
- {
- Thickness rect = _centeredText;
-
- if (!String.IsNullOrWhiteSpace(Text) || HasFocus)
- {
- rect = _alignedWithUnderlineText;
- }
-
- SetPadding((int)Context.ToPixels(rect.Left), (int)Context.ToPixels(rect.Top), (int)Context.ToPixels(rect.Right), (int)Context.ToPixels(rect.Bottom));
- }
-
- protected override void OnTextChanged(Java.Lang.ICharSequence text, int start, int lengthBefore, int lengthAfter)
- {
- base.OnTextChanged(text, start, lengthBefore, lengthAfter);
- if (lengthBefore == 0 || lengthAfter == 0)
- UpdatePadding();
- }
-
- protected override void OnFocusChanged(bool gainFocus, [GeneratedEnum] FocusSearchDirection direction, Rect previouslyFocusedRect)
- {
- base.OnFocusChanged(gainFocus, direction, previouslyFocusedRect);
-
- // Delay padding update until after the keyboard has showed up otherwise updating the padding
- // stops the keyboard from showing up
- if (gainFocus)
- Device.BeginInvokeOnMainThread(() => UpdatePadding());
- else
- UpdatePadding();
- }
-
- bool IDescendantFocusToggler.RequestFocus(global::Android.Views.View control, Func<bool> baseRequestFocus)
- {
- _descendantFocusToggler = _descendantFocusToggler ?? new DescendantFocusToggler();
-
- return _descendantFocusToggler.RequestFocus(control, baseRequestFocus);
- }
public override bool OnKeyPreIme(Keycode keyCode, KeyEvent e)
{
return true;
}
- public override bool RequestFocus(FocusSearchDirection direction, Rect previouslyFocusedRect)
- {
- return (this as IDescendantFocusToggler).RequestFocus(this, () => base.RequestFocus(direction, previouslyFocusedRect));
- }
-
- protected override void OnSelectionChanged(int selStart, int selEnd)
- {
- base.OnSelectionChanged(selStart, selEnd);
- _selectionChanged?.Invoke(this, new SelectionChangedEventArgs(selStart, selEnd));
- }
-
event EventHandler _onKeyboardBackPressed;
event EventHandler IFormsEditText.OnKeyboardBackPressed
{
add => _selectionChanged += value;
remove => _selectionChanged -= value;
}
+
+ protected override void OnSelectionChanged(int selStart, int selEnd)
+ {
+ base.OnSelectionChanged(selStart, selEnd);
+ _selectionChanged?.Invoke(this, new SelectionChangedEventArgs(selStart, selEnd));
+ }
}
}
#endif
\ No newline at end of file
--- /dev/null
+#if __ANDROID_28__
+using System;
+using Android.Content;
+using Android.Graphics;
+using Android.Views;
+using Android.Support.Design.Widget;
+using Android.Runtime;
+using Android.Util;
+
+namespace Xamarin.Forms.Platform.Android.Material
+{
+ public class MaterialFormsEditTextBase : TextInputEditText, IDescendantFocusToggler
+ {
+ DescendantFocusToggler _descendantFocusToggler;
+ public MaterialFormsEditTextBase(Context context) : base(context)
+ {
+ MaterialFormsEditTextManager.Init(this);
+ }
+
+ protected MaterialFormsEditTextBase(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
+ {
+ MaterialFormsEditTextManager.Init(this);
+ }
+
+ public MaterialFormsEditTextBase(Context context, IAttributeSet attrs) : base(context, attrs)
+ {
+ MaterialFormsEditTextManager.Init(this);
+ }
+
+ public MaterialFormsEditTextBase(Context context, IAttributeSet attrs, int defStyleAttr) : base(context, attrs, defStyleAttr)
+ {
+ MaterialFormsEditTextManager.Init(this);
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ MaterialFormsEditTextManager.Dispose(this);
+
+ base.Dispose(disposing);
+ }
+
+ bool IDescendantFocusToggler.RequestFocus(global::Android.Views.View control, Func<bool> baseRequestFocus)
+ {
+ _descendantFocusToggler = _descendantFocusToggler ?? new DescendantFocusToggler();
+ return _descendantFocusToggler.RequestFocus(this, baseRequestFocus);
+ }
+
+ public override bool RequestFocus(FocusSearchDirection direction, Rect previouslyFocusedRect)
+ {
+ return (this as IDescendantFocusToggler).RequestFocus(this, () => base.RequestFocus(direction, previouslyFocusedRect));
+ }
+ }
+}
+#endif
\ No newline at end of file
--- /dev/null
+#if __ANDROID_28__
+using System;
+using Android.Content;
+using Android.Support.Design.Widget;
+
+
+namespace Xamarin.Forms.Platform.Android.Material
+{
+ internal static class MaterialFormsEditTextManager
+ {
+
+ // These paddings are a hack to center the hint
+ // once this issue is resolved we can get rid of these paddings
+ // https://github.com/material-components/material-components-android/issues/120
+ // https://stackoverflow.com/questions/50487871/how-to-make-the-hint-text-of-textinputlayout-vertically-center
+
+ static Thickness _centeredText = new Thickness(16, 8, 12, 27);
+ static Thickness _alignedWithUnderlineText = new Thickness(16, 20, 12, 16);
+
+ public static void Init(TextInputEditText textInputEditText)
+ {
+ VisualElement.VerifyVisualFlagEnabled();
+
+ textInputEditText.TextChanged += OnTextChanged;
+ textInputEditText.FocusChange += OnFocusChanged;
+ }
+
+ public static void Dispose(TextInputEditText textInputEditText)
+ {
+ textInputEditText.TextChanged -= OnTextChanged;
+ textInputEditText.FocusChange -= OnFocusChanged;
+ }
+
+ private static void OnFocusChanged(object sender, global::Android.Views.View.FocusChangeEventArgs e)
+ {
+ if (sender is TextInputEditText textInputEditText)
+ {
+ // Delay padding update until after the keyboard has showed up otherwise updating the padding
+ // stops the keyboard from showing up
+ // TODO closure
+ if (e.HasFocus)
+ Device.BeginInvokeOnMainThread(() => UpdatePadding(textInputEditText));
+ else
+ UpdatePadding(textInputEditText);
+ }
+ }
+
+ private static void OnTextChanged(object sender, global::Android.Text.TextChangedEventArgs e)
+ {
+ if (e.BeforeCount == 0 || e.AfterCount == 0)
+ UpdatePadding(sender as TextInputEditText);
+ }
+
+ static void UpdatePadding(TextInputEditText textInputEditText)
+ {
+ Thickness rect = _centeredText;
+
+ if (!String.IsNullOrWhiteSpace(textInputEditText.Text) || textInputEditText.HasFocus)
+ {
+ rect = _alignedWithUnderlineText;
+ }
+
+ 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));
+ }
+ }
+}
+#endif
\ No newline at end of file
--- /dev/null
+#if __ANDROID_28__
+using System;
+using Android.Content;
+using Android.Runtime;
+using Android.Util;
+
+namespace Xamarin.Forms.Platform.Android.Material
+{
+ public class MaterialFormsTextInputLayout : MaterialFormsTextInputLayoutBase
+ {
+ public MaterialFormsTextInputLayout(Context context) : base(context)
+ {
+ }
+
+ public MaterialFormsTextInputLayout(Context context, IAttributeSet attrs) : base(context, attrs)
+ {
+ }
+
+ public MaterialFormsTextInputLayout(Context context, IAttributeSet attrs, int defStyleAttr) : base(context, attrs, defStyleAttr)
+ {
+ }
+
+ protected MaterialFormsTextInputLayout(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
+ {
+ }
+ }
+}
+#endif
\ No newline at end of file
--- /dev/null
+#if __ANDROID_28__
+using System;
+using Android.Content;
+using Android.Support.Design.Widget;
+using Android.Runtime;
+using Android.Util;
+using Android.Views;
+using Android.Graphics;
+using Android.Support.V4.View;
+using Android.Content.Res;
+
+namespace Xamarin.Forms.Platform.Android.Material
+{
+ public class MaterialFormsTextInputLayoutBase : TextInputLayout
+ {
+ Color _formsTextColor;
+ Color _formsPlaceholderColor;
+ bool _isSetup = false;
+ ColorStateList _focusedFilledColorList;
+ ColorStateList _unfocusedEmptyColorList;
+ private ColorStateList _unfocusedUnderlineColorsList;
+ private ColorStateList _focusedUnderlineColorsList;
+ static readonly int[][] s_colorStates = { new[] { global::Android.Resource.Attribute.StateEnabled }, new[] { -global::Android.Resource.Attribute.StateEnabled } };
+ bool _isDisposed = false;
+
+ public MaterialFormsTextInputLayoutBase(Context context) : base(context)
+ {
+ Init();
+ }
+
+ public MaterialFormsTextInputLayoutBase(Context context, IAttributeSet attrs) : base(context, attrs)
+ {
+ Init();
+ }
+
+ public MaterialFormsTextInputLayoutBase(Context context, IAttributeSet attrs, int defStyleAttr) : base(context, attrs, defStyleAttr)
+ {
+ Init();
+ }
+
+ protected MaterialFormsTextInputLayoutBase(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
+ {
+ Init();
+ }
+
+ void Init()
+ {
+ VisualElement.VerifyVisualFlagEnabled();
+ }
+
+ void ResetTextColors(Color formsTextColor, Color formsPlaceHolderColor)
+ {
+ _formsPlaceholderColor = formsPlaceHolderColor;
+ _formsTextColor = formsTextColor;
+
+ var underlineColors = MaterialColors.GetUnderlineColor(_formsTextColor);
+ var placeHolderColors = MaterialColors.GetPlaceHolderColor(_formsPlaceholderColor, _formsTextColor);
+
+ // I realize these are the same but I have to set it to a difference instance
+ // otherwise when focused it won't change to the color I want it to and it'll just think
+ // I'm not actually changing anything
+ _unfocusedUnderlineColorsList = MaterialColors.CreateEntryUnderlineColors(underlineColors.FocusedColor, underlineColors.UnFocusedColor);
+ _focusedUnderlineColorsList = MaterialColors.CreateEntryUnderlineColors(underlineColors.FocusedColor, underlineColors.UnFocusedColor);
+
+ _focusedFilledColorList = MaterialColors.CreateEntryFilledPlaceholderColors(placeHolderColors.FloatingColor, placeHolderColors.FloatingColor);
+ _unfocusedEmptyColorList = MaterialColors.CreateEntryFilledPlaceholderColors(placeHolderColors.InlineColor, placeHolderColors.FloatingColor);
+
+
+ var textColor = MaterialColors.GetEntryTextColor(formsTextColor).ToArgb();
+ EditText.SetTextColor(new ColorStateList(s_colorStates, new[] { textColor, textColor }));
+ }
+
+ internal void ApplyTheme(Color formsTextColor, Color formsPlaceHolderColor)
+ {
+ if (_isDisposed)
+ return;
+
+ if(!_isSetup)
+ {
+ _isSetup = true;
+ EditText.FocusChange += OnFocusChange;
+ ResetTextColors(formsTextColor, formsPlaceHolderColor);
+ }
+ else if(formsTextColor != _formsTextColor || _formsPlaceholderColor != formsPlaceHolderColor)
+ {
+ ResetTextColors(formsTextColor, formsPlaceHolderColor);
+ }
+
+ if(HasFocus)
+ ViewCompat.SetBackgroundTintList(EditText, _focusedUnderlineColorsList);
+ else
+ ViewCompat.SetBackgroundTintList(EditText, _unfocusedUnderlineColorsList);
+
+ if (HasFocus || !string.IsNullOrWhiteSpace(EditText.Text))
+ this.DefaultHintTextColor = _focusedFilledColorList;
+ else
+ this.DefaultHintTextColor = _unfocusedEmptyColorList;
+ }
+
+ void ApplyTheme() => ApplyTheme(_formsTextColor, _formsPlaceholderColor);
+
+ /*
+ * This currently does two things
+ * 1) It's a hacky way of keeping the underline color matching the TextColor.
+ * when the entry gets focused the underline gets changed to the themes active color
+ * and this is the only way to set it away from that and to whatever the user specified
+ * 2) The HintTextColor has a different alpha when focused vs not focused
+ * */
+ void OnFocusChange(object sender, FocusChangeEventArgs e) =>
+ Device.BeginInvokeOnMainThread(() => ApplyTheme());
+
+
+ internal void SetHint(string hint, VisualElement element)
+ {
+ if (HintEnabled != !String.IsNullOrWhiteSpace(hint))
+ {
+ HintEnabled = !String.IsNullOrWhiteSpace(hint);
+ Hint = hint ?? String.Empty;
+ EditText.Hint = String.Empty;
+ element?.InvalidateMeasureNonVirtual(Internals.InvalidationTrigger.VerticalOptionsChanged);
+ }
+ else
+ {
+ Hint = hint ?? String.Empty;
+ }
+ }
+
+
+ protected override void Dispose(bool disposing)
+ {
+ if (!_isDisposed)
+ {
+ _isDisposed = true;
+ if (EditText != null)
+ EditText.FocusChange -= OnFocusChange;
+ }
+
+ base.Dispose(disposing);
+ }
+ }
+}
+#endif
\ No newline at end of file
--- /dev/null
+#if __ANDROID_28__
+using System;
+using Android.Content;
+using Android.Graphics;
+using Android.Runtime;
+using Android.Support.Design.Widget;
+using Android.Util;
+using Android.Views;
+
+namespace Xamarin.Forms.Platform.Android.Material
+{
+ public class MaterialPickerEditText : MaterialFormsEditTextBase
+ {
+ bool _isDisposed = false;
+ public MaterialPickerEditText(Context context) : base(context)
+ {
+ PickerManager.Init(this);
+ }
+
+ protected MaterialPickerEditText(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
+ {
+ PickerManager.Init(this);
+ }
+
+ public MaterialPickerEditText(Context context, IAttributeSet attrs) : base(context, attrs)
+ {
+ PickerManager.Init(this);
+ }
+
+ public MaterialPickerEditText(Context context, IAttributeSet attrs, int defStyleAttr) : base(context, attrs, defStyleAttr)
+ {
+ PickerManager.Init(this);
+ }
+
+ public override bool OnTouchEvent(MotionEvent e)
+ {
+ PickerManager.OnTouchEvent(this, e);
+ return base.OnTouchEvent(e); // raises the OnClick event if focus is already received
+ }
+
+ protected override void OnFocusChanged(bool gainFocus, [GeneratedEnum] FocusSearchDirection direction, Rect previouslyFocusedRect)
+ {
+ base.OnFocusChanged(gainFocus, direction, previouslyFocusedRect);
+ PickerManager.OnFocusChanged(gainFocus, this, (IPopupTrigger)Parent.Parent);
+
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && !_isDisposed)
+ {
+ _isDisposed = true;
+ PickerManager.Dispose(this);
+ }
+
+ base.Dispose(disposing);
+ }
+ }
+}
+#endif
\ No newline at end of file
--- /dev/null
+#if __ANDROID_28__
+using System.ComponentModel;
+using Android.Content;
+using Android.Support.V4.View;
+using Android.Views;
+using Android.Widget;
+using Xamarin.Forms;
+using Xamarin.Forms.Platform.Android.Material;
+
+[assembly: ExportRenderer(typeof(Xamarin.Forms.Picker), typeof(MaterialPickerRenderer), new[] { typeof(VisualRendererMarker.Material) })]
+
+namespace Xamarin.Forms.Platform.Android.Material
+{
+ public class MaterialPickerRenderer : AppCompat.PickerRendererBase<MaterialPickerTextInputLayout>
+ {
+ MaterialPickerTextInputLayout _textInputLayout;
+ MaterialPickerEditText _textInputEditText;
+
+ public MaterialPickerRenderer(Context context) : base(MaterialContextThemeWrapper.Create(context))
+ {
+ }
+
+
+ protected override EditText EditText => _textInputEditText;
+
+ protected override MaterialPickerTextInputLayout CreateNativeControl()
+ {
+ var inflater = LayoutInflater.FromContext(Context);
+ var view = inflater.Inflate(Resource.Layout.MaterialPickerTextInput, null);
+ _textInputLayout = (MaterialPickerTextInputLayout)view;
+ _textInputEditText = _textInputLayout.FindViewById<MaterialPickerEditText>(Resource.Id.materialformsedittext);
+
+ return _textInputLayout;
+ }
+
+ protected override void UpdateBackgroundColor()
+ {
+ if (_textInputLayout == null)
+ return;
+
+ _textInputLayout.BoxBackgroundColor = MaterialColors.CreateEntryFilledInputBackgroundColor(Element.BackgroundColor, Element.TextColor);
+ }
+
+ protected internal override void UpdatePlaceHolderText()
+ {
+ _textInputLayout.SetHint(string.Empty, Element);
+ }
+
+ protected internal override void UpdateTitleColor() => ApplyTheme();
+ protected override void UpdateTextColor() => ApplyTheme();
+
+ void ApplyTheme() => _textInputLayout?.ApplyTheme(Element.TextColor, Color.Default);
+ }
+}
+#endif
\ No newline at end of file
--- /dev/null
+#if __ANDROID_28__
+using System;
+using Android.Content;
+using Android.Runtime;
+using Android.Util;
+
+namespace Xamarin.Forms.Platform.Android.Material
+{
+ public class MaterialPickerTextInputLayout : MaterialFormsTextInputLayoutBase, IPopupTrigger
+ {
+ public bool ShowPopupOnFocus { get; set; }
+
+ public MaterialPickerTextInputLayout(Context context) : base(context)
+ {
+ }
+
+ public MaterialPickerTextInputLayout(Context context, IAttributeSet attrs) : base(context, attrs)
+ {
+ }
+
+ public MaterialPickerTextInputLayout(Context context, IAttributeSet attrs, int defStyleAttr) : base(context, attrs, defStyleAttr)
+ {
+ }
+
+ protected MaterialPickerTextInputLayout(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
+ {
+ }
+ }
+}
+#endif
\ No newline at end of file
--- /dev/null
+#if __ANDROID_28__
+using System.ComponentModel;
+using Android.Content;
+using Android.Support.V4.View;
+using Android.Views;
+using Android.Widget;
+using Xamarin.Forms;
+using Xamarin.Forms.Platform.Android.Material;
+
+[assembly: ExportRenderer(typeof(Xamarin.Forms.TimePicker), typeof(MaterialTimePickerRenderer), new[] { typeof(VisualRendererMarker.Material) })]
+
+namespace Xamarin.Forms.Platform.Android.Material
+{
+ public class MaterialTimePickerRenderer : TimePickerRendererBase<MaterialPickerTextInputLayout>
+ {
+ MaterialPickerTextInputLayout _textInputLayout;
+ MaterialPickerEditText _textInputEditText;
+
+ public MaterialTimePickerRenderer(Context context) : base(MaterialContextThemeWrapper.Create(context))
+ {
+ }
+
+ protected override EditText EditText => _textInputEditText;
+
+ protected override MaterialPickerTextInputLayout CreateNativeControl()
+ {
+ LayoutInflater inflater = LayoutInflater.FromContext(Context);
+ var view = inflater.Inflate(Resource.Layout.MaterialPickerTextInput, null);
+ _textInputLayout = (MaterialPickerTextInputLayout)view;
+ _textInputEditText = _textInputLayout.FindViewById<MaterialPickerEditText>(Resource.Id.materialformsedittext);
+
+ return _textInputLayout;
+ }
+
+
+ protected override void OnElementChanged(ElementChangedEventArgs<TimePicker> e)
+ {
+ base.OnElementChanged(e);
+ _textInputLayout.SetHint(string.Empty, Element);
+ }
+
+ protected override void UpdateBackgroundColor()
+ {
+ if (_textInputLayout == null)
+ return;
+
+ _textInputLayout.BoxBackgroundColor = MaterialColors.CreateEntryFilledInputBackgroundColor(Element.BackgroundColor, Element.TextColor);
+ }
+
+ protected override void UpdateTextColor() => ApplyTheme();
+
+ void ApplyTheme()
+ {
+ _textInputLayout?.ApplyTheme(Element.TextColor, Color.Default);
+ }
+
+ }
+}
+#endif
\ No newline at end of file
--- /dev/null
+using Android.Views;
+using Android.Widget;
+using Android.Text;
+using System.Collections.Generic;
+using AView = global::Android.Views.View;
+using Java.Lang;
+using Android.Text.Style;
+
+namespace Xamarin.Forms.Platform.Android
+{
+ internal static class PickerManager
+ {
+ readonly static HashSet<Keycode> availableKeys = new HashSet<Keycode>(new[] {
+ Keycode.Tab, Keycode.Forward, Keycode.Back, Keycode.DpadDown, Keycode.DpadLeft, Keycode.DpadRight, Keycode.DpadUp
+ });
+
+ public static void Init(EditText editText)
+ {
+ editText.Focusable = true;
+ editText.Clickable = true;
+ editText.InputType = InputTypes.Null;
+ editText.KeyPress += OnKeyPress;
+
+ editText.SetOnClickListener(PickerListener.Instance);
+ }
+
+ public static void OnTouchEvent(EditText sender, MotionEvent e)
+ {
+ if (e.Action == MotionEventActions.Up && !sender.IsFocused)
+ {
+ sender.RequestFocus();
+ }
+ }
+
+ public static void OnFocusChanged(bool gainFocus, EditText sender, IPopupTrigger popupTrigger)
+ {
+ if (gainFocus && popupTrigger.ShowPopupOnFocus)
+ sender.CallOnClick();
+
+ popupTrigger.ShowPopupOnFocus = false;
+ }
+
+ static void OnKeyPress(object sender, AView.KeyEventArgs e)
+ {
+ if (availableKeys.Contains(e.KeyCode))
+ {
+ e.Handled = false;
+ return;
+ }
+ e.Handled = true;
+ (sender as AView)?.CallOnClick();
+ }
+
+ public static void Dispose(EditText editText)
+ {
+ editText.KeyPress -= OnKeyPress;
+ editText.SetOnClickListener(null);
+ }
+
+ public static ICharSequence GetTitle(Color titleColor, string title)
+ {
+ if(titleColor == Color.Default)
+ return new Java.Lang.String(title);
+
+ var spannableTitle = new SpannableString(title ?? "");
+ spannableTitle.SetSpan(new ForegroundColorSpan(titleColor.ToAndroid()), 0, spannableTitle.Length(), SpanTypes.ExclusiveExclusive);
+ return spannableTitle;
+ }
+
+ class PickerListener : global::Java.Lang.Object, AView.IOnClickListener
+ {
+ public static readonly PickerListener Instance = new PickerListener();
+
+ public void OnClick(global::Android.Views.View v)
+ {
+ if (v is AView picker)
+ {
+ if (picker?.Parent is IPickerRenderer renderer1)
+ renderer1.OnClick();
+ else if (picker?.Parent?.Parent?.Parent is IPickerRenderer renderer2)
+ renderer2.OnClick();
+ else
+ throw new System.Exception("Renderer not found temp check for Shane things");
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
using Android.App;
using Android.Content;
using Android.Util;
+using Android.Views;
using Android.Widget;
+using AColor = Android.Graphics.Color;
namespace Xamarin.Forms.Platform.Android
{
- public class DatePickerRenderer : ViewRenderer<DatePicker, EditText>, IPickerRenderer
+ public abstract class DatePickerRendererBase<TControl> : ViewRenderer<DatePicker, TControl>, IPickerRenderer
+ where TControl : global::Android.Views.View
{
+ int _originalHintTextColor;
DatePickerDialog _dialog;
bool _disposed;
- TextColorSwitcher _textColorSwitcher;
+ protected abstract EditText EditText { get; }
- public DatePickerRenderer(Context context) : base(context)
+ public DatePickerRendererBase(Context context) : base(context)
{
AutoPackage = false;
if (Forms.IsLollipopOrNewer)
[Obsolete("This constructor is obsolete as of version 2.5. Please use DatePickerRenderer(Context) instead.")]
[EditorBrowsable(EditorBrowsableState.Never)]
- public DatePickerRenderer()
+ public DatePickerRendererBase()
{
AutoPackage = false;
if (Forms.IsLollipopOrNewer)
base.Dispose(disposing);
}
- protected override EditText CreateNativeControl()
+ public override bool DispatchTouchEvent(MotionEvent e)
{
- return new PickerEditText(Context, this);
+ return base.DispatchTouchEvent(e);
}
protected override void OnElementChanged(ElementChangedEventArgs<DatePicker> e)
if (e.OldElement == null)
{
var textField = CreateNativeControl();
-
SetNativeControl(textField);
-
- var useLegacyColorManagement = e.NewElement.UseLegacyColorManagement();
- _textColorSwitcher = new TextColorSwitcher(textField.TextColors, useLegacyColorManagement);
+ _originalHintTextColor = EditText.CurrentHintTextColor;
}
SetDate(Element.Date);
UpdateMinimumDate();
UpdateMaximumDate();
-
if (Forms.IsLollipopOrNewer)
_dialog.CancelEvent += OnCancelButtonClicked;
void SetDate(DateTime date)
{
- Control.Text = date.ToString(Element.Format);
+ EditText.Text = date.ToString(Element.Format);
}
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 UpdateMaximumDate()
}
}
- void UpdateTextColor()
+ abstract protected void UpdateTextColor();
+ }
+
+
+ public class DatePickerRenderer : DatePickerRendererBase<EditText>
+ {
+ TextColorSwitcher _textColorSwitcher;
+ [Obsolete("This constructor is obsolete as of version 2.5. Please use DatePickerRenderer(Context) instead.")]
+ public DatePickerRenderer()
+ {
+ }
+
+ public DatePickerRenderer(Context context) : base(context)
+ {
+ }
+
+ protected override EditText CreateNativeControl()
+ {
+ return new PickerEditText(Context);
+ }
+
+ protected override EditText EditText => Control;
+
+ protected override void UpdateTextColor()
{
- _textColorSwitcher?.UpdateTextColor(Control, Element.TextColor);
+ _textColorSwitcher = _textColorSwitcher ?? new TextColorSwitcher(EditText.TextColors, Element.UseLegacyColorManagement());
+ _textColorSwitcher.UpdateTextColor(EditText, Element.TextColor);
}
}
}
\ No newline at end of file
using System.Collections.Generic;
using System.ComponentModel;
using Android.Content;
-using Android.Content.Res;
-using Android.OS;
using Android.Text;
using Android.Text.Method;
using Android.Util;
{
public class EntryRenderer : EntryRendererBase<FormsEditText>
{
+ TextColorSwitcher _hintColorSwitcher;
+ TextColorSwitcher _textColorSwitcher;
+
public EntryRenderer(Context context) : base(context)
{
}
bool isReadOnly = !Element.IsReadOnly;
Control.SetCursorVisible(isReadOnly);
}
+
+ 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 EntryRendererBase<TControl> : ViewRenderer<Entry, TControl>, ITextWatcher, TextView.IOnEditorActionListener
where TControl : global::Android.Views.View
{
- TextColorSwitcher _hintColorSwitcher;
- TextColorSwitcher _textColorSwitcher;
bool _disposed;
ImeAction _currentInputImeFlag;
IElementController ElementController => Element as IElementController;
bool _selectionLengthChangePending;
bool _nativeSelectionIsUpdating;
-
protected abstract EditText EditText { get; }
-
public EntryRendererBase(Context context) : base(context)
{
AutoPackage = false;
formsEditText.OnKeyboardBackPressed += OnKeyboardBackPressed;
formsEditText.SelectionChanged += SelectionChanged;
}
-
- var useLegacyColorManagement = e.NewElement.UseLegacyColorManagement();
-
- _textColorSwitcher = new TextColorSwitcher(EditText.TextColors, useLegacyColorManagement);
- _hintColorSwitcher = new TextColorSwitcher(EditText.HintTextColors, useLegacyColorManagement);
}
// When we set the control text, it triggers the SelectionChanged event, which updates CursorPosition and SelectionLength;
EditText.Text = Element.Text;
UpdateInputType();
- UpdateColor();
+ UpdateTextColor();
UpdateAlignment();
UpdateFont();
UpdatePlaceholderColor();
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == Entry.PlaceholderProperty.PropertyName)
- EditText.Hint = Element.Placeholder;
+ UpdatePlaceHolderText();
else if (e.PropertyName == Entry.IsPasswordProperty.PropertyName)
UpdateInputType();
else if (e.PropertyName == Entry.TextProperty.PropertyName)
}
}
else if (e.PropertyName == Entry.TextColorProperty.PropertyName)
- UpdateColor();
+ UpdateTextColor();
else if (e.PropertyName == InputView.KeyboardProperty.PropertyName)
UpdateInputType();
else if (e.PropertyName == InputView.IsSpellCheckEnabledProperty.PropertyName)
EditText.UpdateHorizontalAlignment(Element.HorizontalTextAlignment, Context.HasRtlSupport());
}
- internal protected virtual void UpdateColor() => UpdateTextColor(Element.TextColor);
-
- internal protected void UpdateTextColor(Color color) => _textColorSwitcher.UpdateTextColor(EditText, color);
+ abstract protected void UpdateTextColor();
protected internal virtual void UpdateFont()
{
UpdateFont();
}
- protected internal virtual void UpdatePlaceholderColor()
- {
- _hintColorSwitcher.UpdateTextColor(EditText, Element.PlaceholderColor, EditText.SetHintTextColor);
- }
+ abstract protected void UpdatePlaceholderColor();
void OnKeyboardBackPressed(object sender, EventArgs eventArgs)
{
namespace Xamarin.Forms.Platform.Android
{
- public class FormsEditText : EditText, IDescendantFocusToggler, IFormsEditText
+ public class FormsEditText : FormsEditTextBase, IFormsEditText
{
- DescendantFocusToggler _descendantFocusToggler;
-
public FormsEditText(Context context) : base(context)
{
- DrawableCompat.Wrap(Background);
}
- bool IDescendantFocusToggler.RequestFocus(global::Android.Views.View control, Func<bool> baseRequestFocus)
- {
- _descendantFocusToggler = _descendantFocusToggler ?? new DescendantFocusToggler();
-
- return _descendantFocusToggler.RequestFocus(control, baseRequestFocus);
- }
public override bool OnKeyPreIme(Keycode keyCode, KeyEvent e)
{
return true;
}
- public override bool RequestFocus(FocusSearchDirection direction, Rect previouslyFocusedRect)
- {
- return (this as IDescendantFocusToggler).RequestFocus(this, () => base.RequestFocus(direction, previouslyFocusedRect));
- }
-
protected override void OnSelectionChanged(int selStart, int selEnd)
{
base.OnSelectionChanged(selStart, selEnd);
}
}
+ public class FormsEditTextBase : EditText, IDescendantFocusToggler
+ {
+ DescendantFocusToggler _descendantFocusToggler;
+
+ public FormsEditTextBase(Context context) : base(context)
+ {
+ DrawableCompat.Wrap(Background);
+ }
+
+ bool IDescendantFocusToggler.RequestFocus(global::Android.Views.View control, Func<bool> baseRequestFocus)
+ {
+ _descendantFocusToggler = _descendantFocusToggler ?? new DescendantFocusToggler();
+
+ return _descendantFocusToggler.RequestFocus(control, baseRequestFocus);
+ }
+
+
+ public override bool RequestFocus(FocusSearchDirection direction, Rect previouslyFocusedRect)
+ {
+ return (this as IDescendantFocusToggler).RequestFocus(this, () => base.RequestFocus(direction, previouslyFocusedRect));
+ }
+
+
+ }
+
public class SelectionChangedEventArgs : EventArgs
{
public int Start { get; private set; }
+using System;
using Android.Content;
-using Android.Views;
-using Android.Widget;
-using Android.Text;
-using Java.Lang;
-using System.Collections.Generic;
using Android.Graphics;
using Android.Runtime;
+using Android.Views;
+using Android.Widget;
namespace Xamarin.Forms.Platform.Android
{
- public class PickerEditText : EditText, IPopupTrigger
+ public class PickerEditText : FormsEditTextBase, IPopupTrigger
{
- readonly static HashSet<Keycode> availableKeys = new HashSet<Keycode>(new[] {
- Keycode.Tab, Keycode.Forward, Keycode.Back, Keycode.DpadDown, Keycode.DpadLeft, Keycode.DpadRight, Keycode.DpadUp
- });
-
- System.WeakReference<IPickerRenderer> rendererRef;
-
public bool ShowPopupOnFocus { get; set; }
- public PickerEditText(Context context, IPickerRenderer pickerRenderer) : base(context)
- {
- Focusable = true;
- Clickable = true;
- InputType = InputTypes.Null;
- KeyPress += OnKeyPress;
- rendererRef = new System.WeakReference<IPickerRenderer>(pickerRenderer);
- SetOnClickListener(PickerListener.Instance);
- }
-
- protected override void OnFocusChanged(bool gainFocus, [GeneratedEnum] FocusSearchDirection direction, Rect previouslyFocusedRect)
- {
- base.OnFocusChanged(gainFocus, direction, previouslyFocusedRect);
- if (gainFocus && ShowPopupOnFocus)
- CallOnClick();
- ShowPopupOnFocus = false;
- }
-
- void OnKeyPress(object sender, KeyEventArgs e)
+ public PickerEditText(Context context) : base(context)
{
- if (availableKeys.Contains(e.KeyCode))
- {
- e.Handled = false;
- return;
- }
- e.Handled = true;
- CallOnClick();
+ PickerManager.Init(this);
}
public override bool OnTouchEvent(MotionEvent e)
{
- if (e.Action == MotionEventActions.Up && !IsFocused)
- RequestFocus();
+ PickerManager.OnTouchEvent(this, e);
return base.OnTouchEvent(e); // raises the OnClick event if focus is already received
}
- protected override void Dispose(bool disposing)
+ protected override void OnFocusChanged(bool gainFocus, [GeneratedEnum] FocusSearchDirection direction, Rect previouslyFocusedRect)
{
- if (disposing)
- {
- KeyPress -= OnKeyPress;
- rendererRef = null;
- }
- base.Dispose(disposing);
+ base.OnFocusChanged(gainFocus, direction, previouslyFocusedRect);
+ PickerManager.OnFocusChanged(gainFocus, this, this);
}
- class PickerListener : Object, IOnClickListener
+ protected override void Dispose(bool disposing)
{
- public static readonly PickerListener Instance = new PickerListener();
+ if (disposing)
+ PickerManager.Dispose(this);
- public void OnClick(global::Android.Views.View v)
- {
- if (v is PickerEditText picker)
- {
- picker.rendererRef.TryGetTarget(out IPickerRenderer renderer);
- renderer?.OnClick();
- }
- }
+ base.Dispose(disposing);
}
}
}
\ No newline at end of file
protected override EditText CreateNativeControl()
{
- return new PickerEditText(Context, this);
+ return new PickerEditText(Context);
}
protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
using ATimePicker = Android.Widget.TimePicker;
using Android.OS;
using Android.Widget;
+using AColor = Android.Graphics.Color;
namespace Xamarin.Forms.Platform.Android
{
- public class TimePickerRenderer : ViewRenderer<TimePicker, EditText>, TimePickerDialog.IOnTimeSetListener, IPickerRenderer
+ public abstract class TimePickerRendererBase<TControl> : ViewRenderer<TimePicker, TControl>, TimePickerDialog.IOnTimeSetListener, IPickerRenderer
+ where TControl : global::Android.Views.View
{
+ int _originalHintTextColor;
AlertDialog _dialog;
- TextColorSwitcher _textColorSwitcher;
bool Is24HourView
{
get => (DateFormat.Is24HourFormat(Context) && Element.Format == (string)TimePicker.FormatProperty.DefaultValue) || Element.Format == "HH:mm";
}
- public TimePickerRenderer(Context context) : base(context)
+ public TimePickerRendererBase(Context context) : base(context)
{
AutoPackage = false;
}
[Obsolete("This constructor is obsolete as of version 2.5. Please use TimePickerRenderer(Context) instead.")]
[EditorBrowsable(EditorBrowsableState.Never)]
- public TimePickerRenderer()
+ public TimePickerRendererBase()
{
AutoPackage = false;
}
+ protected abstract EditText EditText { get; }
+
IElementController ElementController => Element as IElementController;
void TimePickerDialog.IOnTimeSetListener.OnTimeSet(ATimePicker view, int hourOfDay, int minute)
_dialog = null;
}
- protected override EditText CreateNativeControl()
- {
- return new PickerEditText(Context, this);
- }
-
protected override void OnElementChanged(ElementChangedEventArgs<TimePicker> e)
{
base.OnElementChanged(e);
var textField = CreateNativeControl();
SetNativeControl(textField);
-
- var useLegacyColorManagement = e.NewElement.UseLegacyColorManagement();
- _textColorSwitcher = new TextColorSwitcher(textField.TextColors, useLegacyColorManagement);
+ _originalHintTextColor = EditText.CurrentHintTextColor;
}
SetTime(e.NewElement.Time);
Element.Unfocus();
}
+
void SetTime(TimeSpan time)
{
var timeFormat = Is24HourView ? "HH:mm" : Element.Format;
- Control.Text = DateTime.Today.Add(time).ToString(timeFormat);
+ EditText.Text = DateTime.Today.Add(time).ToString(timeFormat);
}
void UpdateFont()
{
- Control.Typeface = Element.ToTypeface();
- Control.SetTextSize(ComplexUnitType.Sp, (float)Element.FontSize);
+ EditText.Typeface = Element.ToTypeface();
+ EditText.SetTextSize(ComplexUnitType.Sp, (float)Element.FontSize);
}
+
+ abstract protected void UpdateTextColor();
+ }
- void UpdateTextColor()
+ public class TimePickerRenderer : TimePickerRendererBase<EditText>
+ {
+ TextColorSwitcher _textColorSwitcher;
+ [Obsolete("This constructor is obsolete as of version 2.5. Please use TimePickerRenderer(Context) instead.")]
+ public TimePickerRenderer()
{
- _textColorSwitcher?.UpdateTextColor(Control, Element.TextColor);
+ }
+
+ public TimePickerRenderer(Context context) : base(context)
+ {
+ }
+
+ protected override EditText CreateNativeControl()
+ {
+ return new PickerEditText(Context);
+ }
+
+ protected override EditText EditText => Control;
+ protected override void UpdateTextColor()
+ {
+ _textColorSwitcher = _textColorSwitcher ?? new TextColorSwitcher(EditText.TextColors, Element.UseLegacyColorManagement());
+ _textColorSwitcher.UpdateTextColor(EditText, Element.TextColor);
}
}
+
}
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<xamarin.forms.platform.android.material.MaterialPickerTextInputLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ style="@style/XamarinFormsMaterialEntryFilled">
+ <xamarin.forms.platform.android.material.MaterialPickerEditText
+ android:id="@+id/materialformsedittext"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="-7dp"/>
+</xamarin.forms.platform.android.material.MaterialPickerTextInputLayout>
style="@style/XamarinFormsMaterialEntryFilled">
<xamarin.forms.platform.android.material.MaterialFormsEditText
android:id="@+id/materialformsedittext"
- android:layout_marginBottom="-7dp"
android:layout_width="match_parent"
- android:layout_height="wrap_content" />
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="-7dp" />
</xamarin.forms.platform.android.material.MaterialFormsTextInputLayout>
<Compile Include="IBorderVisualElementRenderer.cs" />
<Compile Include="IDeviceInfoProvider.cs" />
<Compile Include="ITabStop.cs" />
+ <Compile Include="Material\MaterialFormsTextInputLayoutBase.cs" />
+ <Compile Include="Material\MaterialFormsEditTextBase.cs" />
+ <Compile Include="Material\MaterialFormsEditTextManager.cs" />
+ <Compile Include="Material\MaterialPickerTextInputLayout.cs" />
+ <Compile Include="Material\MaterialFormsTextInputLayout.cs" />
+ <Compile Include="Material\MaterialPickerEditText.cs" />
<Compile Include="Material\MaterialContextThemeWrapper.cs" />
<Compile Include="Material\MaterialFrameRenderer.cs" />
<Compile Include="Material\MaterialFormsEditText.cs" />
<Compile Include="Material\MaterialButtonRenderer.cs" />
<Compile Include="Material\MaterialEntryRenderer.cs" />
+ <Compile Include="Material\MaterialDatePickerRenderer.cs" />
+ <Compile Include="Material\MaterialPickerRenderer.cs" />
+ <Compile Include="Material\MaterialTimePickerRenderer.cs" />
<Compile Include="Material\MaterialProgressBarRenderer.cs" />
<Compile Include="IPickerRenderer.cs" />
+ <Compile Include="PickerManager.cs" />
<Compile Include="Renderers\CircularProgress.cs" />
<Compile Include="Renderers\PickerEditText.cs" />
<Compile Include="Renderers\FontImageSourceHandler.cs" />
<Generator>MSBuild:UpdateGeneratedFiles</Generator>
<SubType>Designer</SubType>
</AndroidResource>
- </ItemGroup>
- <ItemGroup Condition=" '$(TargetFrameworkVersion)' == 'v9.0' ">
<AndroidResource Include="Resources\values\styles.xml">
<SubType>Designer</SubType>
</AndroidResource>
+ <AndroidResource Include="Resources\Layout\MaterialPickerTextInput.axml">
+ <Generator>MSBuild:UpdateGeneratedFiles</Generator>
+ <SubType>Designer</SubType>
+ </AndroidResource>
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\MaterialActivityIndicatorBackground.xml">
}
}
- public class DatePickerRenderer : ViewRenderer<DatePicker, UITextField>
+ public class DatePickerRenderer : DatePickerRendererBase<UITextField>
+ {
+ protected override UITextField CreateNativeControl()
+ {
+ return new NoCaretField { BorderStyle = UITextBorderStyle.RoundedRect };
+ }
+ }
+
+ public abstract class DatePickerRendererBase<TControl> : ViewRenderer<DatePicker, TControl>
+ where TControl : UITextField
{
UIDatePicker _picker;
UIColor _defaultTextColor;
IElementController ElementController => Element as IElementController;
+
+ abstract protected override TControl CreateNativeControl();
+
protected override void OnElementChanged(ElementChangedEventArgs<DatePicker> e)
{
base.OnElementChanged(e);
if (Control == null)
{
- var entry = new NoCaretField { BorderStyle = UITextBorderStyle.RoundedRect };
+ var entry = CreateNativeControl();
entry.EditingDidBegin += OnStarted;
entry.EditingDidEnd += OnEnded;
(Control as UITextField).UpdateTextAlignment(Element);
}
- void UpdateFont()
+ protected internal virtual void UpdateFont()
{
Control.Font = Element.ToUIFont();
}
_picker.MinimumDate = Element.MinimumDate.ToNSDate();
}
- void UpdateTextColor()
+ protected internal virtual void UpdateTextColor()
{
var textColor = Element.TextColor;
namespace Xamarin.Forms.Platform.iOS
{
- public class EntryRenderer : ViewRenderer<Entry, UITextField>
+ public class EntryRenderer : EntryRendererBase<UITextField>
+ {
+ public EntryRenderer()
+ {
+ Frame = new RectangleF(0, 20, 320, 40);
+ }
+
+ protected override UITextField CreateNativeControl()
+ {
+ var textField = new UITextField(RectangleF.Empty);
+ textField.BorderStyle = UITextBorderStyle.RoundedRect;
+ textField.ClipsToBounds = true;
+ return textField;
+ }
+ }
+
+ public abstract class EntryRendererBase<TControl> : ViewRenderer<Entry, TControl>
+ where TControl : UITextField
{
UIColor _defaultTextColor;
static readonly int baseHeight = 30;
static CGSize initialSize = CGSize.Empty;
- public EntryRenderer()
+ public EntryRendererBase()
{
- Frame = new RectangleF(0, 20, 320, 40);
}
public override SizeRequest GetDesiredSize(double widthConstraint, double heightConstraint)
base.Dispose(disposing);
}
- protected override UITextField CreateNativeControl()
- {
- var textField = new UITextField(RectangleF.Empty);
- textField.BorderStyle = UITextBorderStyle.RoundedRect;
- textField.ClipsToBounds = true;
- return textField;
- }
+ abstract protected override TControl CreateNativeControl();
+
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
=> enableActions.Contains(action.Name);
}
- public class PickerRenderer : ViewRenderer<Picker, UITextField>
+ public class PickerRenderer : PickerRendererBase<UITextField>
+ {
+ protected override UITextField CreateNativeControl()
+ {
+ return new ReadOnlyField { BorderStyle = UITextBorderStyle.RoundedRect };
+ }
+ }
+
+ public abstract class PickerRendererBase<TControl> : ViewRenderer<Picker, TControl>
+ where TControl : UITextField
{
UIPickerView _picker;
UIColor _defaultTextColor;
IElementController ElementController => Element as IElementController;
+
+ protected abstract override TControl CreateNativeControl();
protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
{
if (e.OldElement != null)
if (Control == null)
{
// disabled cut, delete, and toggle actions because they can throw an unhandled native exception
- var entry = new ReadOnlyField { BorderStyle = UITextBorderStyle.RoundedRect };
+ var entry = CreateNativeControl();
entry.EditingDidBegin += OnStarted;
entry.EditingDidEnd += OnEnded;
UpdatePicker();
}
- void UpdateFont()
+ protected internal virtual void UpdateFont()
{
Control.Font = Element.ToUIFont();
}
- void UpdatePicker()
+ readonly Color _defaultPlaceholderColor = ColorExtensions.SeventyPercentGrey.ToColor();
+ protected internal virtual void UpdatePlaceholder()
{
- var selectedIndex = Element.SelectedIndex;
- var items = Element.Items;
+ var formatted = (FormattedString)Element.Title;
+
+ if (formatted == null)
+ return;
- if (!Element.IsSet(Picker.TitleColorProperty))
+ var targetColor = Element.TitleColor;
+
+ if (_useLegacyColorManagement)
{
- Control.AttributedPlaceholder = null;
- Control.Placeholder = Element.Title;
+ var color = targetColor.IsDefault || !Element.IsEnabled ? _defaultPlaceholderColor : targetColor;
+ Control.AttributedPlaceholder = formatted.ToAttributed(Element, color);
}
else
{
- Control.AttributedPlaceholder = new NSAttributedString(Element.Title, new UIStringAttributes
- {
- ForegroundColor = Element.TitleColor.ToUIColor()
- });
+ // Using VSM color management; take whatever is in Element.PlaceholderColor
+ var color = targetColor.IsDefault ? _defaultPlaceholderColor : targetColor;
+ Control.AttributedPlaceholder = formatted.ToAttributed(Element, color);
}
+ }
+
+
+ void UpdatePicker()
+ {
+ var selectedIndex = Element.SelectedIndex;
+ var items = Element.Items;
+
+ UpdatePlaceholder();
var oldText = Control.Text;
Control.Text = selectedIndex == -1 || items == null || selectedIndex >= items.Count ? "" : items[selectedIndex];
_picker.Select(Math.Max(formsIndex, 0), 0, true);
}
- void UpdateTextColor()
+ protected internal virtual void UpdateTextColor()
{
var textColor = Element.TextColor;
class PickerSource : UIPickerViewModel
{
- PickerRenderer _renderer;
+ PickerRendererBase<TControl> _renderer;
bool _disposed;
- public PickerSource(PickerRenderer renderer)
+ public PickerSource(PickerRendererBase<TControl> renderer)
{
_renderer = renderer;
}
namespace Xamarin.Forms.Platform.iOS
{
- public class TimePickerRenderer : ViewRenderer<TimePicker, UITextField>
+ public class TimePickerRenderer : TimePickerRendererBase<UITextField>
+ {
+ protected override UITextField CreateNativeControl()
+ {
+ return new NoCaretField { BorderStyle = UITextBorderStyle.RoundedRect };
+ }
+ }
+
+ public abstract class TimePickerRendererBase<TControl> : ViewRenderer<TimePicker, TControl>
+ where TControl : UITextField
{
UIDatePicker _picker;
UIColor _defaultTextColor;
base.Dispose(disposing);
}
+
+ protected abstract override TControl CreateNativeControl();
+
protected override void OnElementChanged(ElementChangedEventArgs<TimePicker> e)
{
if (e.NewElement != null)
{
if (Control == null)
{
- var entry = new NoCaretField { BorderStyle = UITextBorderStyle.RoundedRect };
+ var entry = CreateNativeControl();
entry.EditingDidBegin += OnStarted;
entry.EditingDidEnd += OnEnded;
UpdateTextColor();
else if (e.PropertyName == TimePicker.FontAttributesProperty.PropertyName || e.PropertyName == TimePicker.FontFamilyProperty.PropertyName || e.PropertyName == TimePicker.FontSizeProperty.PropertyName)
UpdateFont();
-
- if (e.PropertyName == VisualElement.FlowDirectionProperty.PropertyName)
+ else if (e.PropertyName == VisualElement.FlowDirectionProperty.PropertyName)
UpdateFlowDirection();
}
{
(Control as UITextField).UpdateTextAlignment(Element);
}
-
- void UpdateFont()
+
+ protected internal virtual void UpdateFont()
{
Control.Font = Element.ToUIFont();
}
- void UpdateTextColor()
+ protected internal virtual void UpdateTextColor()
{
var textColor = Element.TextColor;