var textColorDisabledContainer = new ViewContainer<Editor>(Test.Editor.TextColor,
new Editor { Text = "I should have the default disabled text color", TextColor = Color.Red, IsEnabled = false });
- var maxLengthContainer = new ViewContainer<Editor>(Test.Editor.MaxLength, new Editor { MaxLength = 3 });
+ var keyboardContainer = new ViewContainer<Editor>(Test.InputView.Keyboard,
+ new Editor { Keyboard = Keyboard.Numeric });
+
+ var maxLengthContainer = new ViewContainer<Editor>(Test.InputView.MaxLength, new Editor { MaxLength = 3 });
Add(completedContainer);
Add(textContainer);
Add(textFontSizeLargeContainer);
Add(textColorContainer);
Add(textColorDisabledContainer);
+ Add(keyboardContainer);
Add(maxLengthContainer);
}
}
var passwordColorContainer = new ViewContainer<Entry> (Test.Entry.PasswordColor,
new Entry { IsPassword = true, Text = "12345", TextColor = Color.Red });
- var maxLengthContainer = new ViewContainer<Entry>(Test.Entry.MaxLength, new Entry { MaxLength = 3 });
+ var maxLengthContainer = new ViewContainer<Entry>(Test.InputView.MaxLength, new Entry { MaxLength = 3 });
var isPasswordInputScopeContainer = new ViewContainer<Entry>(Test.Entry.IsPasswordNumeric, new Entry { Keyboard = Keyboard.Numeric });
var switchPasswordButton = new Button
var layout = new StackLayout ();
foreach (var keyboardType in keyboardTypes) {
- var viewContainer = new ViewContainer<Entry> (Test.Entry.Keyboard, new Entry { Placeholder = keyboardType.ToString (), Keyboard = keyboardType } );
+ var viewContainer = new ViewContainer<Entry> (Test.InputView.Keyboard, new Entry { Placeholder = keyboardType.ToString (), Keyboard = keyboardType } );
layout.Children.Add (viewContainer.ContainerLayout);
}
};
foreach (var customKeyboard in customKeyboards) {
- var viewContainer = new ViewContainer<Entry> (Test.Entry.Keyboard, new Entry { Placeholder = customKeyboard.Item1, Keyboard = customKeyboard.Item2 } );
+ var viewContainer = new ViewContainer<Entry> (Test.InputView.Keyboard, new Entry { Placeholder = customKeyboard.Item1, Keyboard = customKeyboard.Item2 } );
layout.Children.Add (viewContainer.ContainerLayout);
}
var placeholderColorContainer = new ViewContainer<SearchBar> (Test.SearchBar.PlaceholderColor,
new SearchBar { Placeholder = "I should be red", PlaceholderColor = Color.Red });
+
+ var keyboardContainer = new ViewContainer<SearchBar>(Test.InputView.Keyboard,
+ new SearchBar { Keyboard = Keyboard.Numeric });
+
+ var maxLengthContainer = new ViewContainer<SearchBar>(Test.InputView.MaxLength,
+ new SearchBar { MaxLength = 3 });
+
Add (placeholderContainer);
Add (searchButtonPressedContainer);
Add (searchCommandContainer);
Add (placeholderAlignmentEndContainer);
Add (textColorContainer);
Add (placeholderColorContainer);
+ Add (keyboardContainer);
+ Add (maxLengthContainer);
}
}
}
\ No newline at end of file
namespace Xamarin.Forms
{
[RenderWith(typeof(_SearchBarRenderer))]
- public class SearchBar : View, IFontElement, IPlaceholderElement, ITextElement, ITextAlignmentElement, ISearchBarController, IElementConfiguration<SearchBar>
+ public class SearchBar : InputView, IFontElement, IPlaceholderElement, ITextElement, ITextAlignmentElement, ISearchBarController, IElementConfiguration<SearchBar>
{
public static readonly BindableProperty SearchCommandProperty = BindableProperty.Create("SearchCommand", typeof(ICommand), typeof(SearchBar), null, propertyChanged: OnCommandChanged);
public enum InputView
{
Keyboard,
+ MaxLength,
}
public enum Editor
FontAttributes,
FontFamily,
FontSize,
- MaxLength
}
public enum Entry
IsPassword,
Text,
TextColor,
- Keyboard,
HorizontalTextAlignmentStart,
HorizontalTextAlignmentCenter,
HorizontalTextAlignmentEnd,
TextDisabledColor,
PlaceholderDisabledColor,
PasswordColor,
- MaxLength,
IsPasswordNumeric
}
using System;
+using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using Android.Content;
using Android.Graphics;
using Android.OS;
using Android.Text;
+using Android.Text.Method;
using Android.Util;
using Android.Widget;
using AView = Android.Views.View;
}
- BuildVersionCodes androidVersion = Build.VERSION.SdkInt;
- if (androidVersion >= BuildVersionCodes.JellyBean)
- _inputType = searchView.InputType;
- else
- {
- // < API 16, Cannot get the default InputType for a SearchView
- _inputType = InputTypes.ClassText | InputTypes.TextFlagAutoComplete | InputTypes.TextFlagNoSuggestions;
- }
-
ClearFocus(searchView);
+ UpdateInputType();
UpdatePlaceholder();
UpdateText();
UpdateEnabled();
UpdateAlignment();
UpdateTextColor();
UpdatePlaceholderColor();
+ UpdateMaxLength();
if (e.OldElement == null)
{
UpdatePlaceholderColor();
else if (e.PropertyName == VisualElement.FlowDirectionProperty.PropertyName)
UpdateAlignment();
+ else if (e.PropertyName == InputView.MaxLengthProperty.PropertyName)
+ UpdateMaxLength();
+ else if(e.PropertyName == InputView.KeyboardProperty.PropertyName)
+ UpdateInputType();
+ else if(e.PropertyName == InputView.IsSpellCheckEnabledProperty.PropertyName)
+ UpdateInputType();
}
internal override void OnNativeFocusChanged(bool hasFocus)
{
_textColorSwitcher?.UpdateTextColor(_editText, Element.TextColor);
}
+
+ void UpdateMaxLength()
+ {
+ _editText = _editText ?? Control.GetChildrenOfType<EditText>().FirstOrDefault();
+
+ var currentFilters = new List<IInputFilter>(_editText?.GetFilters() ?? new IInputFilter[0]);
+
+ for (var i = 0; i < currentFilters.Count; i++)
+ {
+ if (currentFilters[i] is InputFilterLengthFilter)
+ {
+ currentFilters.RemoveAt(i);
+ break;
+ }
+ }
+
+ currentFilters.Add(new InputFilterLengthFilter(Element.MaxLength));
+
+ _editText?.SetFilters(currentFilters.ToArray());
+
+ var currentControlText = Control.Query;
+
+ if (currentControlText.Length > Element.MaxLength)
+ Control.SetQuery(currentControlText.Substring(0, Element.MaxLength), false);
+ }
+
+ void UpdateInputType()
+ {
+ SearchBar model = Element;
+ var keyboard = model.Keyboard;
+
+ _inputType = keyboard.ToInputType();
+ if (!(keyboard is Internals.CustomKeyboard))
+ {
+ if (model.IsSet(InputView.IsSpellCheckEnabledProperty))
+ {
+ if ((_inputType & InputTypes.TextFlagNoSuggestions) != InputTypes.TextFlagNoSuggestions)
+ {
+ if (!model.IsSpellCheckEnabled)
+ _inputType = _inputType | InputTypes.TextFlagNoSuggestions;
+ }
+ }
+ }
+ Control.SetInputType(_inputType);
+
+ if (keyboard == Keyboard.Numeric)
+ {
+ _editText = _editText ?? Control.GetChildrenOfType<EditText>().FirstOrDefault();
+ if(_editText != null)
+ _editText.KeyListener = GetDigitsKeyListener(_inputType);
+ }
+ }
+
+ protected virtual NumberKeyListener GetDigitsKeyListener(InputTypes inputTypes)
+ {
+ // Override this in a custom renderer to use a different NumberKeyListener
+ // or to filter out input types you don't want to allow
+ // (e.g., inputTypes &= ~InputTypes.NumberFlagSigned to disallow the sign)
+ return LocalizedDigitsKeyListener.Create(inputTypes);
+ }
}
}
\ No newline at end of file
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
+using Xamarin.Forms.Internals;
using Xamarin.Forms.PlatformConfiguration.WindowsSpecific;
using Specifics = Xamarin.Forms.PlatformConfiguration.WindowsSpecific.SearchBar;
UpdateAlignment();
else if (e.PropertyName == Specifics.IsSpellCheckEnabledProperty.PropertyName)
UpdateIsSpellCheckEnabled();
+ else if(e.PropertyName == InputView.MaxLengthProperty.PropertyName)
+ UpdateMaxLength();
+ else if(e.PropertyName == InputView.IsSpellCheckEnabledProperty.PropertyName)
+ UpdateInputScope();
}
void OnControlLoaded(object sender, RoutedEventArgs routedEventArgs)
UpdatePlaceholderColor();
UpdateBackgroundColor();
UpdateIsSpellCheckEnabled();
+ UpdateInputScope();
+ UpdateMaxLength();
// If the Forms VisualStateManager is in play or the user wants to disable the Forms legacy
// color stuff, then the underlying textbox should just use the Forms VSM states
_queryTextBox.IsSpellCheckEnabled = Element.OnThisPlatform().GetIsSpellCheckEnabled();
}
+ void UpdateMaxLength()
+ {
+ if (_queryTextBox == null)
+ return;
+
+ _queryTextBox.MaxLength = Element.MaxLength;
+
+ var currentControlText = Control.Text;
+
+ if (currentControlText.Length > Element.MaxLength)
+ Control.Text = currentControlText.Substring(0, Element.MaxLength);
+ }
+
+ void UpdateInputScope()
+ {
+ if(_queryTextBox == null)
+ return;
+
+ InputView model = Element;
+
+ if (model.Keyboard is CustomKeyboard custom)
+ {
+ _queryTextBox.IsTextPredictionEnabled = (custom.Flags & KeyboardFlags.Suggestions) != 0;
+ _queryTextBox.IsSpellCheckEnabled = (custom.Flags & KeyboardFlags.Spellcheck) != 0;
+ }
+ else
+ {
+ _queryTextBox.ClearValue(TextBox.IsTextPredictionEnabledProperty);
+
+ if (model.IsSet(InputView.IsSpellCheckEnabledProperty))
+ _queryTextBox.IsSpellCheckEnabled = model.IsSpellCheckEnabled;
+ else
+ _queryTextBox.ClearValue(TextBox.IsSpellCheckEnabledProperty);
+ }
+
+ _queryTextBox.InputScope = model.Keyboard.ToInputScope();
+ }
+
protected override void UpdateBackgroundColor()
{
if (_queryTextBox == null)
{
public static class Extensions
{
- public static void ApplyKeyboard(this IUITextInput textInput, Keyboard keyboard)
+ public static void ApplyKeyboard(this IUITextInputTraits textInput, Keyboard keyboard)
{
textInput.AutocapitalizationType = UITextAutocapitalizationType.None;
textInput.AutocorrectionType = UITextAutocorrectionType.No;
using System;
using System.ComponentModel;
using System.Drawing;
+using CoreGraphics;
+using Foundation;
using UIKit;
namespace Xamarin.Forms.Platform.iOS
string _typedText;
bool _useLegacyColorManagement;
+ UIToolbar _numericAccessoryView;
+
IElementController ElementController => Element as IElementController;
protected override void Dispose(bool disposing)
Control.CancelButtonClicked -= OnCancelClicked;
Control.SearchButtonClicked -= OnSearchButtonClicked;
Control.TextChanged -= OnTextChanged;
+ Control.ShouldChangeTextInRange -= ShouldChangeText;
Control.OnEditingStarted -= OnEditingEnded;
Control.OnEditingStopped -= OnEditingStarted;
Control.CancelButtonClicked += OnCancelClicked;
Control.SearchButtonClicked += OnSearchButtonClicked;
Control.TextChanged += OnTextChanged;
+ Control.ShouldChangeTextInRange += ShouldChangeText;
Control.OnEditingStarted += OnEditingStarted;
Control.OnEditingStopped += OnEditingEnded;
UpdateCancelButton();
UpdateAlignment();
UpdateTextColor();
+ UpdateMaxLength();
+ UpdateKeyboard();
}
base.OnElementChanged(e);
UpdateAlignment();
else if (e.PropertyName == VisualElement.FlowDirectionProperty.PropertyName)
UpdateAlignment();
+ else if(e.PropertyName == Xamarin.Forms.InputView.MaxLengthProperty.PropertyName)
+ UpdateMaxLength();
+ else if(e.PropertyName == Xamarin.Forms.InputView.KeyboardProperty.PropertyName)
+ UpdateKeyboard();
+ else if(e.PropertyName == Xamarin.Forms.InputView.IsSpellCheckEnabledProperty.PropertyName)
+ UpdateKeyboard();
}
protected override void SetBackgroundColor(Color color)
_textField.TextColor = targetColor.IsDefault ? _defaultTextColor : targetColor.ToUIColor();
}
}
+
+ void UpdateMaxLength()
+ {
+ var currentControlText = Control.Text;
+
+ if (currentControlText.Length > Element.MaxLength)
+ Control.Text = currentControlText.Substring(0, Element.MaxLength);
+ }
+
+ bool ShouldChangeText(UISearchBar searchBar, NSRange range, string text)
+ {
+ var newLength = searchBar?.Text?.Length + text.Length - range.Length;
+ return newLength <= Element?.MaxLength;
+ }
+
+ void UpdateKeyboard()
+ {
+ var keyboard = Element.Keyboard;
+ Control.ApplyKeyboard(keyboard);
+ if (!(keyboard is Internals.CustomKeyboard))
+ {
+ if (Element.IsSet(Xamarin.Forms.InputView.IsSpellCheckEnabledProperty))
+ {
+ if (!Element.IsSpellCheckEnabled)
+ {
+ Control.SpellCheckingType = UITextSpellCheckingType.No;
+ }
+ }
+ }
+
+ // iPhone does not have an enter key on numeric keyboards
+ if (Device.Idiom == TargetIdiom.Phone && (keyboard == Keyboard.Numeric || keyboard == Keyboard.Telephone))
+ {
+ _numericAccessoryView = _numericAccessoryView ?? CreateNumericKeyboardAccessoryView();
+ Control.InputAccessoryView = _numericAccessoryView;
+ }
+ else
+ {
+ Control.InputAccessoryView = null;
+ }
+
+ Control.ReloadInputViews();
+ }
+
+ UIToolbar CreateNumericKeyboardAccessoryView()
+ {
+ var keyboardWidth = UIScreen.MainScreen.Bounds.Width;
+ var accessoryView = new UIToolbar(new CGRect(0, 0, keyboardWidth, 44)) { BarStyle = UIBarStyle.Default, Translucent = true };
+
+ var spacer = new UIBarButtonItem(UIBarButtonSystemItem.FlexibleSpace);
+ var searchButton = new UIBarButtonItem(UIBarButtonSystemItem.Search, OnSearchButtonClicked);
+ accessoryView.SetItems(new[] { spacer, searchButton }, false);
+
+ return accessoryView;
+ }
}
}
\ No newline at end of file