entry cell renderer
This commit is contained in:
parent
1085808867
commit
8c79c42b28
@ -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" />
|
||||
|
328
src/Android/Renderers/BoxedView/Cells/EntryCellRenderer.cs
Normal file
328
src/Android/Renderers/BoxedView/Cells/EntryCellRenderer.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,7 @@ namespace Bit.App
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
ThemeManager.SetTheme("dark");
|
||||
ThemeManager.SetTheme("light");
|
||||
MainPage = new TabsPage();
|
||||
}
|
||||
|
||||
|
102
src/App/Controls/BoxedView/Cells/EntryCell.cs
Normal file
102
src/App/Controls/BoxedView/Cells/EntryCell.cs
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
@ -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>
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user