entry cell renderer

This commit is contained in:
Kyle Spearrin 2019-04-05 13:35:19 -04:00
parent 1085808867
commit 8c79c42b28
7 changed files with 454 additions and 11 deletions

View File

@ -68,6 +68,7 @@
<Compile Include="Renderers\BoxedView\BoxedViewSimpleCallback.cs" />
<Compile Include="Renderers\BoxedView\Cells\BaseCellRenderer.cs" />
<Compile Include="Renderers\BoxedView\Cells\BaseCellView.cs" />
<Compile Include="Renderers\BoxedView\Cells\EntryCellRenderer.cs" />
<Compile Include="Renderers\BoxedView\Cells\LabelCellRenderer.cs" />
<Compile Include="MainApplication.cs" />
<Compile Include="MainActivity.cs" />

View File

@ -0,0 +1,328 @@
using Android.Content;
using Android.Content.Res;
using Android.OS;
using Android.Runtime;
using Android.Text;
using Android.Text.Method;
using Android.Views;
using Android.Views.InputMethods;
using Android.Widget;
using Java.Lang;
using System;
using System.ComponentModel;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(Bit.App.Controls.BoxedView.EntryCell),
typeof(Bit.Droid.Renderers.BoxedView.EntryCellRenderer))]
namespace Bit.Droid.Renderers.BoxedView
{
[Preserve(AllMembers = true)]
public class EntryCellRenderer : BaseCellRenderer<EntryCellView>
{ }
[Preserve(AllMembers = true)]
public class EntryCellView : BaseCellView, ITextWatcher, TextView.IOnFocusChangeListener,
TextView.IOnEditorActionListener
{
private CustomEditText _editText;
public EntryCellView(Context context, Cell cell)
: base(context, cell)
{
_editText = new CustomEditText(context);
_editText.Focusable = true;
_editText.ImeOptions = ImeAction.Done;
_editText.SetOnEditorActionListener(this);
_editText.OnFocusChangeListener = this;
_editText.SetSingleLine(true);
_editText.Ellipsize = TextUtils.TruncateAt.End;
_editText.InputType |= InputTypes.TextFlagNoSuggestions; // Disabled spell check
_editText.Background.Alpha = 0; // Hide underline
_editText.ClearFocusAction = DoneEdit;
Click += EntryCellView_Click;
using(var lParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MatchParent,
ViewGroup.LayoutParams.WrapContent))
{
CellContent.AddView(_editText, lParams);
}
}
App.Controls.BoxedView.EntryCell _EntryCell => Cell as App.Controls.BoxedView.EntryCell;
public override void UpdateCell()
{
UpdateValueText();
UpdateValueTextColor();
UpdateValueTextFontSize();
UpdateKeyboard();
UpdatePlaceholder();
UpdateAccentColor();
UpdateTextAlignment();
UpdateIsPassword();
base.UpdateCell();
}
public override void CellPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.CellPropertyChanged(sender, e);
if(e.PropertyName == App.Controls.BoxedView.EntryCell.ValueTextProperty.PropertyName)
{
UpdateValueText();
}
else if(e.PropertyName == App.Controls.BoxedView.EntryCell.ValueTextFontSizeProperty.PropertyName)
{
UpdateWithForceLayout(UpdateValueTextFontSize);
}
else if(e.PropertyName == App.Controls.BoxedView.EntryCell.ValueTextColorProperty.PropertyName)
{
UpdateWithForceLayout(UpdateValueTextColor);
}
else if(e.PropertyName == App.Controls.BoxedView.EntryCell.KeyboardProperty.PropertyName)
{
UpdateKeyboard();
}
else if(e.PropertyName == App.Controls.BoxedView.EntryCell.PlaceholderProperty.PropertyName)
{
UpdatePlaceholder();
}
else if(e.PropertyName == App.Controls.BoxedView.EntryCell.AccentColorProperty.PropertyName)
{
UpdateAccentColor();
}
else if(e.PropertyName == App.Controls.BoxedView.EntryCell.TextAlignmentProperty.PropertyName)
{
UpdateTextAlignment();
}
else if(e.PropertyName == App.Controls.BoxedView.EntryCell.IsPasswordProperty.PropertyName)
{
UpdateIsPassword();
}
}
public override void ParentPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.ParentPropertyChanged(sender, e);
if(e.PropertyName == App.Controls.BoxedView.BoxedView.CellValueTextColorProperty.PropertyName)
{
UpdateValueTextColor();
}
else if(e.PropertyName == App.Controls.BoxedView.BoxedView.CellValueTextFontSizeProperty.PropertyName)
{
UpdateWithForceLayout(UpdateValueTextFontSize);
}
else if(e.PropertyName == App.Controls.BoxedView.BoxedView.CellAccentColorProperty.PropertyName)
{
UpdateAccentColor();
}
}
protected override void Dispose(bool disposing)
{
if(disposing)
{
Click -= EntryCellView_Click;
_editText.RemoveFromParent();
_editText.SetOnEditorActionListener(null);
_editText.RemoveTextChangedListener(this);
_editText.OnFocusChangeListener = null;
_editText.ClearFocusAction = null;
_editText.Dispose();
_editText = null;
}
base.Dispose(disposing);
}
protected override void SetEnabledAppearance(bool isEnabled)
{
if(isEnabled)
{
_editText.Enabled = true;
_editText.Alpha = 1.0f;
}
else
{
_editText.Enabled = false;
_editText.Alpha = 0.3f;
}
base.SetEnabledAppearance(isEnabled);
}
private void EntryCellView_Click(object sender, EventArgs e)
{
_editText.RequestFocus();
ShowKeyboard(_editText);
}
private void UpdateValueText()
{
_editText.RemoveTextChangedListener(this);
if(_editText.Text != _EntryCell.ValueText)
{
_editText.Text = _EntryCell.ValueText;
}
_editText.AddTextChangedListener(this);
}
private void UpdateValueTextFontSize()
{
if(_EntryCell.ValueTextFontSize > 0)
{
_editText.SetTextSize(Android.Util.ComplexUnitType.Sp, (float)_EntryCell.ValueTextFontSize);
}
else if(CellParent != null)
{
_editText.SetTextSize(Android.Util.ComplexUnitType.Sp, (float)CellParent.CellValueTextFontSize);
}
}
private void UpdateValueTextColor()
{
if(_EntryCell.ValueTextColor != Color.Default)
{
_editText.SetTextColor(_EntryCell.ValueTextColor.ToAndroid());
}
else if(CellParent != null && CellParent.CellValueTextColor != Color.Default)
{
_editText.SetTextColor(CellParent.CellValueTextColor.ToAndroid());
}
}
private void UpdateKeyboard()
{
_editText.InputType = _EntryCell.Keyboard.ToInputType() | InputTypes.TextFlagNoSuggestions;
}
private void UpdateIsPassword()
{
_editText.TransformationMethod = _EntryCell.IsPassword ? new PasswordTransformationMethod() : null;
}
private void UpdatePlaceholder()
{
_editText.Hint = _EntryCell.Placeholder;
_editText.SetHintTextColor(Android.Graphics.Color.Rgb(210, 210, 210));
}
private void UpdateTextAlignment()
{
_editText.Gravity = _EntryCell.TextAlignment.ToAndroidHorizontal();
}
private void UpdateAccentColor()
{
if(_EntryCell.AccentColor != Color.Default)
{
ChangeTextViewBack(_EntryCell.AccentColor.ToAndroid());
}
else if(CellParent != null && CellParent.CellAccentColor != Color.Default)
{
ChangeTextViewBack(CellParent.CellAccentColor.ToAndroid());
}
}
private void ChangeTextViewBack(Android.Graphics.Color accent)
{
var colorlist = new ColorStateList(
new int[][]
{
new int[]{Android.Resource.Attribute.StateFocused},
new int[]{-Android.Resource.Attribute.StateFocused},
},
new int[] {
Android.Graphics.Color.Argb(255,accent.R,accent.G,accent.B),
Android.Graphics.Color.Argb(255, 200, 200, 200)
});
_editText.Background.SetTintList(colorlist);
}
private void DoneEdit()
{
var entryCell = (IEntryCellController)Cell;
entryCell.SendCompleted();
_editText.ClearFocus();
ClearFocus();
}
private void HideKeyboard(Android.Views.View inputView)
{
using(var inputMethodManager = (InputMethodManager)_Context.GetSystemService(Context.InputMethodService))
{
IBinder windowToken = inputView.WindowToken;
if(windowToken != null)
{
inputMethodManager.HideSoftInputFromWindow(windowToken, HideSoftInputFlags.None);
}
}
}
private void ShowKeyboard(Android.Views.View inputView)
{
using(var inputMethodManager = (InputMethodManager)_Context.GetSystemService(Context.InputMethodService))
{
inputMethodManager.ShowSoftInput(inputView, ShowFlags.Forced);
inputMethodManager.ToggleSoftInput(ShowFlags.Forced, HideSoftInputFlags.ImplicitOnly);
}
}
bool TextView.IOnEditorActionListener.OnEditorAction(TextView v, ImeAction actionId, KeyEvent e)
{
if(actionId == ImeAction.Done || (actionId == ImeAction.ImeNull && e.KeyCode == Keycode.Enter))
{
HideKeyboard(v);
DoneEdit();
}
return true;
}
void ITextWatcher.AfterTextChanged(IEditable s)
{ }
void ITextWatcher.BeforeTextChanged(ICharSequence s, int start, int count, int after)
{ }
void ITextWatcher.OnTextChanged(ICharSequence s, int start, int before, int count)
{
_EntryCell.ValueText = s?.ToString();
}
void IOnFocusChangeListener.OnFocusChange(Android.Views.View v, bool hasFocus)
{
if(hasFocus)
{
// Show underline when on focus.
_editText.Background.Alpha = 100;
}
else
{
// Hide underline
_editText.Background.Alpha = 0;
}
}
}
[Preserve(AllMembers = true)]
internal class CustomEditText : EditText
{
public CustomEditText(Context context)
: base(context)
{ }
public Action ClearFocusAction { get; set; }
public override bool OnKeyPreIme(Keycode keyCode, KeyEvent e)
{
if(keyCode == Keycode.Back && e.Action == KeyEventActions.Up)
{
ClearFocus();
ClearFocusAction?.Invoke();
}
return base.OnKeyPreIme(keyCode, e);
}
}
}

View File

@ -25,13 +25,12 @@ namespace Bit.Droid.Renderers.BoxedView
ValueLabel = new TextView(context);
ValueLabel.SetSingleLine(true);
ValueLabel.Ellipsize = TextUtils.TruncateAt.End;
ValueLabel.Gravity = GravityFlags.Right;
ValueLabel.Gravity = GravityFlags.Left;
var textParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WrapContent,
ViewGroup.LayoutParams.WrapContent);
using(textParams)
using(var lParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WrapContent,
ViewGroup.LayoutParams.WrapContent))
{
CellContent.AddView(ValueLabel, textParams);
CellContent.AddView(ValueLabel, lParams);
}
}

View File

@ -38,7 +38,7 @@ namespace Bit.Droid.Renderers
}
}
public static GravityFlags ToAndroidVertical(this Xamarin.Forms.TextAlignment formsAlignment)
public static GravityFlags ToAndroidHorizontal(this Xamarin.Forms.TextAlignment formsAlignment)
{
switch(formsAlignment)
{
@ -49,7 +49,7 @@ namespace Bit.Droid.Renderers
case Xamarin.Forms.TextAlignment.End:
return GravityFlags.Right | GravityFlags.CenterVertical;
default:
return GravityFlags.Right | GravityFlags.CenterVertical;
return GravityFlags.Left | GravityFlags.CenterVertical;
}
}

View File

@ -15,7 +15,7 @@ namespace Bit.App
{
InitializeComponent();
ThemeManager.SetTheme("dark");
ThemeManager.SetTheme("light");
MainPage = new TabsPage();
}

View File

@ -0,0 +1,102 @@
using System;
using Xamarin.Forms;
namespace Bit.App.Controls.BoxedView
{
public class EntryCell : BaseCell, IEntryCellController
{
public static BindableProperty ValueTextProperty = BindableProperty.Create(
nameof(ValueText), typeof(string), typeof(EntryCell), default(string),
defaultBindingMode: BindingMode.TwoWay);
// propertyChanging: ValueTextPropertyChanging);
public static BindableProperty ValueTextColorProperty = BindableProperty.Create(
nameof(ValueTextColor), typeof(Color), typeof(EntryCell), default(Color),
defaultBindingMode: BindingMode.OneWay);
public static BindableProperty ValueTextFontSizeProperty = BindableProperty.Create(
nameof(ValueTextFontSize), typeof(double), typeof(EntryCell), -1.0,
defaultBindingMode: BindingMode.OneWay);
public static BindableProperty KeyboardProperty = BindableProperty.Create(
nameof(Keyboard), typeof(Keyboard), typeof(EntryCell), Keyboard.Default,
defaultBindingMode: BindingMode.OneWay);
public static BindableProperty PlaceholderProperty = BindableProperty.Create(
nameof(Placeholder), typeof(string), typeof(EntryCell), default(string),
defaultBindingMode: BindingMode.OneWay);
public static BindableProperty TextAlignmentProperty = BindableProperty.Create(
nameof(TextAlignment), typeof(TextAlignment), typeof(EntryCell), TextAlignment.Start,
defaultBindingMode: BindingMode.OneWay);
public static BindableProperty AccentColorProperty = BindableProperty.Create(
nameof(AccentColor), typeof(Color), typeof(EntryCell), default(Color),
defaultBindingMode: BindingMode.OneWay);
public static BindableProperty IsPasswordProperty = BindableProperty.Create(
nameof(IsPassword), typeof(bool), typeof(EntryCell), default(bool),
defaultBindingMode: BindingMode.OneWay);
public string ValueText
{
get => (string)GetValue(ValueTextProperty);
set => SetValue(ValueTextProperty, value);
}
public Color ValueTextColor
{
get => (Color)GetValue(ValueTextColorProperty);
set => SetValue(ValueTextColorProperty, value);
}
[TypeConverter(typeof(FontSizeConverter))]
public double ValueTextFontSize
{
get => (double)GetValue(ValueTextFontSizeProperty);
set => SetValue(ValueTextFontSizeProperty, value);
}
public Keyboard Keyboard
{
get => (Keyboard)GetValue(KeyboardProperty);
set => SetValue(KeyboardProperty, value);
}
public string Placeholder
{
get => (string)GetValue(PlaceholderProperty);
set => SetValue(PlaceholderProperty, value);
}
public TextAlignment TextAlignment
{
get => (TextAlignment)GetValue(TextAlignmentProperty);
set => SetValue(TextAlignmentProperty, value);
}
public Color AccentColor
{
get => (Color)GetValue(AccentColorProperty);
set => SetValue(AccentColorProperty, value);
}
public bool IsPassword
{
get => (bool)GetValue(IsPasswordProperty);
set => SetValue(IsPasswordProperty, value);
}
public event EventHandler Completed;
public void SendCompleted()
{
Completed?.Invoke(this, EventArgs.Empty);
}
private static void ValueTextPropertyChanging(BindableObject bindable, object oldValue, object newValue)
{
// Check changes
}
}
}

View File

@ -11,9 +11,22 @@
<pages:SettingsPageViewModel />
</ContentPage.BindingContext>
<bv:BoxedView>
<bv:BoxedSection Title="The Title" FooterText="The Footer">
<bv:LabelCell Title="The title" ValueText="The value" />
<bv:BoxedView HasUnevenRows="True">
<bv:BoxedSection Title="The Title"
FooterText="The Footer"
UseDragSort="True">
<bv:EntryCell Title="The title"
ValueText="The value for entry" />
<bv:LabelCell Title="The title"
ValueText="The value" />
<bv:LabelCell Title="The title 2"
ValueText="The value" />
<bv:LabelCell Title="The title 3"
ValueText="The value" />
<bv:LabelCell Title="The title 4"
ValueText="The value" />
<bv:LabelCell Title="The title 5"
ValueText="The value" />
</bv:BoxedSection>
</bv:BoxedView>