Last active
April 29, 2019 21:41
-
-
Save felipeslongo/b240c61f3a73b8d272fcc4fe200cd1ed to your computer and use it in GitHub Desktop.
AppAutoCompleteTextView customizado pra um comportamento especifico.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Linq; | |
using System.Threading.Tasks; | |
using Android.Widget; | |
namespace App.Droid.Extensions | |
{ | |
public static class AutoCompleteTextView_MostrarSugestoes | |
{ | |
public static void MostrarSugestoesAoInteragir(this AutoCompleteTextView @this) | |
{ | |
@this.MostrarSugestoesOnFocus(); | |
@this.MostrarSugestoesOnClick(); | |
@this.MostrarSugestoesQuantoTextoVazio(); | |
} | |
public static void MostrarSugestoesOnFocus(this AutoCompleteTextView @this) | |
{ | |
@this.FocusChange += (sender, args) => | |
{ | |
if (args.HasFocus) | |
@this.ShowDropDown(); | |
}; | |
} | |
public static void MostrarSugestoesOnClick(this AutoCompleteTextView @this) | |
=> @this.Click += (sender, args) => @this.ShowDropDown(); | |
public static void MostrarSugestoesQuantoTextoVazio(this AutoCompleteTextView @this) | |
{ | |
@this.TextChanged += async (sender, args) => | |
{ | |
if (!string.IsNullOrEmpty(@this.Text)) | |
return; | |
await Task.Delay(TimeSpan.FromMilliseconds(300)); | |
@this.ShowDropDown(); | |
}; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Diagnostics.Tracing; | |
using System.Reactive; | |
using System.Reactive.Subjects; | |
using Android.Widget; | |
using Core.ValueTypes; | |
namespace App.Droid.Extensions | |
{ | |
public static class AutoCompleteTextView_NotificarQuandoTextoDigitadoForIgualASugestaoUnica | |
{ | |
public static IObservable<Java.Lang.Object> NotificarQuandoTextoDigitadoForIgualASugestaoUnica( | |
this AutoCompleteTextView @this, | |
Func<string, string, bool> compararTestoComASugestaoUnica) | |
{ | |
var observable = new Subject<Java.Lang.Object>(); | |
@this.FocusChange += (sender, e) => | |
{ | |
if (e.HasFocus) | |
return; | |
var view = (AutoCompleteTextView) sender; | |
if (view.Adapter.Count != 1) | |
return; | |
var itemDaSugestaoUnica = view.Adapter.GetItem(0); | |
if (!compararTestoComASugestaoUnica(itemDaSugestaoUnica.ToString(), view.Text)) | |
return; | |
observable.OnNext(itemDaSugestaoUnica); | |
}; | |
return observable; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using Android.Text; | |
using Android.Views; | |
using Android.Widget; | |
using App.Droid.Utils; | |
namespace App.Droid.Extensions | |
{ | |
public static class EditText_ConfigurarBotaoDeLimpar | |
{ | |
public static void ConfigurarBotaoDeLimpar(this EditText @this, Action clearAction) | |
{ | |
@this.AfterTextChanged += DefinirIconeSeBaseandoNaPresencaDeTexto; | |
@this.FocusChange += DefinirIconeSeBaseandoNaPresencaDeTexto; | |
ConfigurarAcaoDeLimparAoClicarNoIcone(@this, clearAction); | |
} | |
private static void DefinirIconeSeBaseandoNaPresencaDeTexto(object sender, View.FocusChangeEventArgs e) => | |
DefinirIconeSeBaseandoNaPresencaDeTexto((EditText)sender, !string.IsNullOrEmpty((sender as EditText).Text)); | |
private static void DefinirIconeSeBaseandoNaPresencaDeTexto(object sender, AfterTextChangedEventArgs args) => | |
DefinirIconeSeBaseandoNaPresencaDeTexto((EditText)sender,args.Editable.Length() > 0); | |
private static void DefinirIconeSeBaseandoNaPresencaDeTexto(EditText @this, bool textoPreenchido) | |
{ | |
var iconeDeLimpar = textoPreenchido && @this.HasFocus ? Resource.Drawable.ic_content_clear : 0; | |
@this.SetCompoundDrawablesWithIntrinsicBounds(0, 0, iconeDeLimpar, 0); | |
} | |
private static void ConfigurarAcaoDeLimparAoClicarNoIcone(EditText view, Action clearAction) => | |
TextViewDrawableTouchEventHandler.ConfigurarClickNoDrawableDaDireita(view, clearAction); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
namespace Core.ViewModels | |
{ | |
public class SelectItemViewModel | |
{ | |
internal const int IdDeOpcaoVazia = 0; | |
public SelectItemViewModel(int id, string texto, int ordem, bool selecionado) | |
{ | |
if (string.IsNullOrWhiteSpace(texto)) | |
throw new ArgumentNullException(nameof(texto), NãoFoiInformadoOTextoDoItem); | |
Id = id; | |
Texto = texto; | |
Ordem = ordem; | |
SelecionadoDefault = selecionado; | |
Selecionado = SelecionadoDefault; | |
} | |
protected SelectItemViewModel(SelectItemViewModel viewModelOrigem) : this( | |
viewModelOrigem.Id, | |
viewModelOrigem.Texto, | |
viewModelOrigem.Ordem, | |
viewModelOrigem.Selecionado) | |
{} | |
protected virtual string NãoFoiInformadoOTextoDoItem => "Não foi informado o texto de apresentação do item"; | |
public int Id { get; } | |
public string Texto { get; } | |
public int Ordem { get; } | |
public bool SelecionadoDefault { get; } | |
public bool OpcaoVazia => Id == IdDeOpcaoVazia; | |
public bool Selecionado { get; internal set; } | |
public static SelectItemViewModel MakeOpcaoVazia() | |
=> new SelectItemViewModel(IdDeOpcaoVazia, "---------", int.MinValue, false); | |
public override string ToString() => Texto; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using NUnit.Framework; | |
using Core.ViewModels; | |
namespace Shared.Tests.ViewModels | |
{ | |
[TestFixture] | |
public class SelectItemViewModelTests | |
{ | |
[Test] | |
public void DeveConstruirUmaOpcaoQueRepresentaVazio() | |
{ | |
var retorno = SelectItemViewModel.MakeOpcaoVazia(); | |
Assert.IsTrue(retorno.OpcaoVazia); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Linq; | |
using Android.Support.V7.Widget; | |
using Android.Views; | |
using Android.Widget; | |
using App.Droid.Resources; | |
using Core.ValueTypes; | |
using Core.ViewModels; | |
using App.Droid.Extensions; | |
namespace App.Droid.Views | |
{ | |
public class SelectView : SelectView<SelectViewModel> | |
{ | |
public SelectView(SelectViewModel listaViewModel, AppCompatAutoCompleteTextView view, Action<int, string> actionSelecionarRow = null) | |
: base(listaViewModel, view, actionSelecionarRow) | |
{ | |
} | |
} | |
public class SelectView<TViewModel> where TViewModel : SelectViewModel | |
{ | |
public SelectView(TViewModel listaViewModel, AppCompatAutoCompleteTextView view, Action<int, string> actionSelecionarRow = null) | |
{ | |
View = view; | |
ViewModel = listaViewModel; | |
ActionSelecionarRow = actionSelecionarRow; | |
InicializarAutoComplete(); | |
} | |
protected TViewModel ViewModel { get; } | |
protected Action<int, string> ActionSelecionarRow { get; } | |
protected AppCompatAutoCompleteTextView View { get; } | |
private void InicializarAutoComplete() | |
{ | |
var adapter = new ArrayAdapter<SelectItemViewModel>( | |
View.Context, | |
Resource.Layout.select_dialog_item_material, | |
ViewModel.Itens.ToList()); | |
View.Threshold = 1; | |
View.MostrarSugestoesAoInteragir(); | |
View.Adapter = adapter; | |
View.ItemClick += ViewOnItemClickSelecionarItemNaViewModel; | |
View.NotificarQuandoTextoDigitadoForIgualASugestaoUnica(StringInsensivelESemAcentos.Compare) | |
.Subscribe(SelecionarItemNaViewModelSeTiverUmaUnicaSugestaoQueBateComOTextoDigitado); | |
View.FocusChange += ViewOnFocusChangeAtribuirAViewTextoDaViewModel; | |
View.ConfigurarBotaoDeLimpar(() => AtribuirTexto(string.Empty)); | |
} | |
private void ViewOnItemClickSelecionarItemNaViewModel(object sender, AdapterView.ItemClickEventArgs e) | |
{ | |
var itemSelecionado = e.GetItem().Cast<SelectItemViewModel>(); | |
ViewModel.SelecionarItem(itemSelecionado); | |
ActionSelecionarRow?.Invoke(itemSelecionado.Id, itemSelecionado.Texto); | |
} | |
private void ViewOnFocusChangeAtribuirAViewTextoDaViewModel(object sender, View.FocusChangeEventArgs e) | |
{ | |
if (!e.HasFocus) | |
AtribuirTexto(); | |
} | |
private void SelecionarItemNaViewModelSeTiverUmaUnicaSugestaoQueBateComOTextoDigitado(Java.Lang.Object itemSugeridoUnico) | |
=> ViewModel.SelecionarItem(itemSugeridoUnico.Cast<SelectItemViewModel>()); | |
protected void AtribuirTexto() => AtribuirTexto(ViewModel.Selecionado.Texto); | |
private void AtribuirTexto(string valor) => View.SetText(valor, false); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using Core.Entities; | |
using Core.Enums; | |
namespace Core.ViewModels | |
{ | |
public class SelectViewModel | |
{ | |
private readonly List<SelectItemViewModel> _itens = new List<SelectItemViewModel>(); | |
public SelectViewModel(int id, string nome, bool makeOpcaoVazia = true) | |
{ | |
if (string.IsNullOrWhiteSpace(nome)) | |
throw new ArgumentNullException(nameof(nome), NãoFoiInformadoONome); | |
Id = id; | |
Nome = nome; | |
if (makeOpcaoVazia) | |
_itens.Add(MakeOpcaoVazia()); | |
} | |
protected virtual string NãoFoiInformadoONome => "Não foi informado o nome"; | |
public int Id { get; } | |
public string Nome { get; } | |
public IReadOnlyList<SelectItemViewModel> Itens => _itens; | |
public SelectItemViewModel Default => | |
Itens.FirstOrDefault(i => i.SelecionadoDefault) ?? Itens.First(); | |
public SelectItemViewModel Selecionado => _itens.FirstOrDefault(i => i.Selecionado) ?? Default; | |
public virtual SelectItemViewModel MakeOpcaoVazia() => SelectItemViewModel.MakeOpcaoVazia(); | |
public void AdicionarItem(SelectItemViewModel item) => AdicionarItens(item); | |
public void AdicionarItens(IEnumerable<SelectItemViewModel> itens) => AdicionarItens(itens.ToArray()); | |
public void AdicionarItens(params SelectItemViewModel[] itens) | |
{ | |
_itens.AddRange(itens); | |
InicializarItens(); | |
} | |
protected void InicializarItens() | |
{ | |
_itens.Sort(CompararItems); | |
RemoverSelecaoDosNaoSelecionados(); | |
} | |
private void RemoverSelecaoDosNaoSelecionados() | |
{ | |
foreach (var itemNaoSelecionado in ObterItensComIdDiferenteDoSelecionado()) | |
itemNaoSelecionado.Selecionado = false; | |
} | |
private IEnumerable<SelectItemViewModel> ObterItensComIdDiferenteDoSelecionado() | |
{ | |
var selecionado = Selecionado; | |
return _itens.Where(i => i.Id != selecionado.Id); | |
} | |
public void SelecionarItem(SelectItemViewModel item) => SelecionarItem(item.Id); | |
public void SelecionarItem(int id) | |
{ | |
Selecionado.Selecionado = false; | |
_itens.First(i => i.Id == id).Selecionado = true; | |
} | |
private static int CompararItems(SelectItemViewModel x, SelectItemViewModel y) | |
{ | |
if (x == y) return (int) Comparacao.Igual; | |
if (x.Ordem == y.Ordem) return x.Id.CompareTo(y.Id); | |
return x.Ordem.CompareTo(y.Ordem); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Linq; | |
using NUnit.Framework; | |
using Core.ViewModels; | |
namespace Core.Tests.ViewModels | |
{ | |
[TestFixture] | |
public class SelectViewModelTests | |
{ | |
public const int IdPadrao = 1; | |
public const int IdAlternativo = 2; | |
[TestFixture] | |
public class SelecionarItemTests : SelectViewModelTests | |
{ | |
[Test] | |
public void RetornarOpcaoSelecionadaDepoisDeInvocarSelecionarItem() | |
{ | |
var viewModel = new SelectViewModel(IdPadrao, "selectView"); | |
var itemSelecionado = new SelectItemViewModel(2, "item2", 0, false); | |
viewModel.AdicionarItem(new SelectItemViewModel(1, "item1", 0, false)); | |
viewModel.AdicionarItem(itemSelecionado); | |
viewModel.AdicionarItem(new SelectItemViewModel(3, "item3", 0, false)); | |
viewModel.SelecionarItem(itemSelecionado.Id); | |
Assert.AreEqual(itemSelecionado.Id, viewModel.Selecionado.Id); | |
Assert.IsTrue(itemSelecionado.Selecionado); | |
} | |
[Test] | |
public void RemoverSelecaoDeUmaOpcaoAoSelecionarOutraOpcao() | |
{ | |
var viewModel = new SelectViewModel(IdPadrao, "selectView"); | |
var itemSelecionadoAnterior = new SelectItemViewModel(1, "item1", 0, true); | |
var itemSelecionadoNovo = new SelectItemViewModel(2, "item1", 0, false); | |
viewModel.AdicionarItem(itemSelecionadoAnterior); | |
viewModel.AdicionarItem(itemSelecionadoNovo); | |
viewModel.SelecionarItem(itemSelecionadoNovo.Id); | |
Assert.AreEqual(itemSelecionadoNovo.Id, viewModel.Selecionado.Id); | |
Assert.IsFalse(itemSelecionadoAnterior.Selecionado); | |
} | |
[Test] | |
public void DispararExcecaoAoSelecionarItemNaoExistente() | |
{ | |
var viewModel = new SelectViewModel(IdPadrao, "selectView"); | |
Assert.Throws<InvalidOperationException>(() => viewModel.SelecionarItem(1)); | |
} | |
} | |
[TestFixture] | |
public class Ordenacao : SelectViewModelTests | |
{ | |
[Test] | |
public void ItensDevemSerOrdenadosPelaOrdem() | |
{ | |
var viewModel = new SelectViewModel(IdPadrao, "selectView"); | |
var item1 = new SelectItemViewModel(1, "item", 3, false); | |
var item2 = new SelectItemViewModel(2, "item", 2, false); | |
var item3 = new SelectItemViewModel(3, "item", 1, false); | |
viewModel.AdicionarItens(item1, item2, item3); | |
var idsEsperadosOrdenados = new []{3, 2, 1}; | |
var idsRetornadosOrdenados = viewModel.Itens.SkipWhile(i => i.OpcaoVazia).Select(i => i.Id); | |
CollectionAssert.AreEqual(idsEsperadosOrdenados, idsRetornadosOrdenados); | |
} | |
[Test] | |
public void ItensDevemSerOrdenadosPeloIdSeOrdemEmpatar() | |
{ | |
var listaViewModel = new SelectViewModel(IdPadrao, "selectView"); | |
var item3 = new SelectItemViewModel(3, "item", 1, false); | |
var item2 = new SelectItemViewModel(2, "item", 1, false); | |
var item1 = new SelectItemViewModel(1, "item", 1, false); | |
listaViewModel.AdicionarItens(item3, item2, item1); | |
var idsEsperadosOrdenados = new []{1,2,3}; | |
var idsRetornadosOrdenados = listaViewModel.Itens.SkipWhile(i => i.OpcaoVazia).Select(i => i.Id); | |
CollectionAssert.AreEqual(idsEsperadosOrdenados, idsRetornadosOrdenados); | |
} | |
} | |
[TestFixture] | |
public class SelecionadoEhUnico : SelectViewModelTests | |
{ | |
[Test] | |
public void SomenteUmaOpcaoDeveTerEstadoSelecionadoQuandoMultiplosSelecionados() | |
{ | |
var viewModel = new SelectViewModel(IdPadrao, "selectView"); | |
var unicoQueDevePermanecerSelecionado = new SelectItemViewModel(1, "item2", 0, true); | |
viewModel.AdicionarItem(unicoQueDevePermanecerSelecionado); | |
viewModel.AdicionarItem(new SelectItemViewModel(2, "item1", 0, true)); | |
viewModel.AdicionarItem(new SelectItemViewModel(3, "item1", 0, true)); | |
Assert.IsTrue(unicoQueDevePermanecerSelecionado.Selecionado); | |
var itensQueNaoDevemEstarSelecionados = | |
viewModel.Itens.Where(i => i != unicoQueDevePermanecerSelecionado); | |
Assert.IsTrue(itensQueNaoDevemEstarSelecionados.All(i => !i.Selecionado)); | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using Android.Graphics.Drawables; | |
using Android.Views; | |
using Android.Widget; | |
namespace App.Droid.Utils | |
{ | |
public static class TextViewDrawableTouchEventHandler | |
{ | |
const int DrawableDaEsquerda = 0; | |
const int DrawableDeCima = 1; | |
const int DrawableDaDireita = 2; | |
const int DrawableDeBaixo = 3; | |
public static void ConfigurarClickNoDrawableDaDireita(EditText view, Action action) => | |
view.Touch += (sender, args) => DispararAcaoAoClicarNoDrawableDaDireita(sender, args, action); | |
private static void DispararAcaoAoClicarNoDrawableDaDireita(object sender, View.TouchEventArgs e, Action action) | |
{ | |
var view = (EditText) sender; | |
e.Handled = false; | |
if (!EventoDeClique(e)) | |
return; | |
var drawable = view.GetCompoundDrawables()[DrawableDaDireita]; | |
if (drawable == null) | |
return; | |
if (!ZonaClicavelDoDrawableDaDireita(e, view, drawable)) | |
return; | |
action(); | |
e.Handled = true; | |
} | |
private static bool ZonaClicavelDoDrawableDaDireita(View.TouchEventArgs e, EditText view, Drawable drawable) | |
{ | |
var pontoNoEixoXClicadoPeloUsuario = e.Event.RawX; | |
var pontoNoEixoXQueSeparaAViewDoSeuDrawableDaDireita = view.Right - drawable.Bounds.Width(); | |
return pontoNoEixoXClicadoPeloUsuario >= pontoNoEixoXQueSeparaAViewDoSeuDrawableDaDireita; | |
} | |
private static bool EventoDeClique(View.TouchEventArgs e) => | |
e.Event.Action == MotionEventActions.Up; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment