Exibições nativos em XAML
As exibições nativas do iOS, Android e da Plataforma Universal do Windows podem ser referenciadas diretamente de Xamarin.Forms arquivos XAML. Propriedades e manipuladores de eventos podem ser definidos em exibições nativas e podem interagir com Xamarin.Forms exibições. Este artigo demonstra como consumir exibições nativas de Xamarin.Forms arquivos XAML.
Para inserir uma exibição nativa em um Xamarin.Forms arquivo XAML:
- Adicione uma declaração de
xmlns
namespace no arquivo XAML para o namespace que contém o modo de exibição nativo. - Crie uma instância do modo de exibição nativo no arquivo XAML.
Importante
O XAML compilado deve ser desabilitado para todas as páginas XAML que usam exibições nativas. Isso pode ser feito decorando a classe code-behind para sua página XAML com o [XamlCompilation(XamlCompilationOptions.Skip)]
atributo. Para obter mais informações sobre a compilação XAML, consulte Compilação XAML no Xamarin.Forms.
Para fazer referência a uma exibição nativa de um arquivo code-behind, você deve usar um Projeto de Ativo Compartilhado (SAP) e encapsular o código específico da plataforma com diretivas de compilação condicional. Para obter mais informações, consulte Consultar exibições nativas do código.
Consumir exibições nativas
O exemplo de código a seguir demonstra o consumo de exibições nativas para cada plataforma para um Xamarin.FormsContentPage
:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:ios="clr-namespace:UIKit;assembly=Xamarin.iOS;targetPlatform=iOS"
xmlns:androidWidget="clr-namespace:Android.Widget;assembly=Mono.Android;targetPlatform=Android"
xmlns:androidLocal="clr-namespace:SimpleColorPicker.Droid;assembly=SimpleColorPicker.Droid;targetPlatform=Android"
xmlns:win="clr-namespace:Windows.UI.Xaml.Controls;assembly=Windows, Version=255.255.255.255,
Culture=neutral, PublicKeyToken=null, ContentType=WindowsRuntime;targetPlatform=Windows"
x:Class="NativeViews.NativeViewDemo">
<StackLayout Margin="20">
<ios:UILabel Text="Hello World" TextColor="{x:Static ios:UIColor.Red}" View.HorizontalOptions="Start" />
<androidWidget:TextView Text="Hello World" x:Arguments="{x:Static androidLocal:MainActivity.Instance}" />
<win:TextBlock Text="Hello World" />
</StackLayout>
</ContentPage>
Além de especificar o clr-namespace
e assembly
para um namespace de exibição nativo, um targetPlatform
também deve ser especificado. Isso deve ser definido como iOS
, Android
, UWP
, Windows
(que é equivalente a UWP
), macOS
, GTK
, Tizen
, ou WPF
. Em runtime, o analisador XAML ignorará todos os prefixos de namespace XML que tenham um targetPlatform
que não corresponda à plataforma na qual o aplicativo está sendo executado.
Cada declaração de namespace pode ser usada para fazer referência a qualquer classe ou estrutura do namespace especificado. Por exemplo, a declaração de ios
namespace pode ser usada para fazer referência a qualquer classe ou estrutura do namespace do iOS UIKit
. As propriedades do modo de exibição nativo podem ser definidas por meio de XAML, mas os tipos de propriedade e objeto devem corresponder. Por exemplo, a UILabel.TextColor
propriedade é definida como UIColor.Red
usando a extensão de x:Static
marcação e o ios
namespace.
As propriedades associáveis e as propriedades associáveis anexadas também podem ser definidas em exibições nativas usando a Class.BindableProperty="value"
sintaxe. Cada exibição nativa é encapsulada em uma instância específica NativeViewWrapper
da plataforma, que deriva da Xamarin.Forms.View
classe. Definir uma propriedade associável ou uma propriedade associável anexada em uma exibição nativa transfere o valor da propriedade para o wrapper. Por exemplo, um layout horizontal centralizado pode ser especificado configurando View.HorizontalOptions="Center"
a visualização nativa.
Observação
Observe que os estilos não podem ser usados com exibições nativas, pois os estilos só podem direcionar propriedades que são apoiadas por BindableProperty
objetos.
Os construtores de widget do Android geralmente exigem o objeto Android Context
como um argumento, e isso pode ser disponibilizado MainActivity
por meio de uma propriedade estática na classe. Portanto, ao criar um widget do Android em XAML, o Context
objeto geralmente deve ser passado para o construtor do widget usando o x:Arguments
atributo com uma x:Static
extensão de marcação. Para obter mais informações, consulte Passar argumentos para exibições nativas.
Observação
Observe que nomear uma exibição nativa não x:Name
é possível em um projeto de biblioteca .NET Standard ou em um Projeto de Ativo Compartilhado (SAP). Isso gerará uma variável do tipo nativo, o que causará um erro de compilação. No entanto, as exibições nativas podem ser encapsuladas em ContentView
instâncias e recuperadas no arquivo code-behind, desde que um SAP esteja sendo usado. Para obter mais informações, consulte Consulte a exibição nativa do código.
Associações nativas
A associação de dados é usada para sincronizar uma interface do usuário com sua fonte de dados e simplifica a forma como um Xamarin.Forms aplicativo exibe e interage com seus dados. Desde que o objeto de origem implemente a INotifyPropertyChanged
interface, as alterações no objeto de origem são automaticamente enviadas por push para o objeto de destino pela estrutura de associação e as alterações no objeto de destino podem, opcionalmente, ser enviadas por push para o objeto de origem .
As propriedades de exibições nativas também podem usar a vinculação de dados. O exemplo de código a seguir demonstra a vinculação de dados usando propriedades de exibições nativas:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:ios="clr-namespace:UIKit;assembly=Xamarin.iOS;targetPlatform=iOS"
xmlns:androidWidget="clr-namespace:Android.Widget;assembly=Mono.Android;targetPlatform=Android"
xmlns:androidLocal="clr-namespace:SimpleColorPicker.Droid;assembly=SimpleColorPicker.Droid;targetPlatform=Android"
xmlns:win="clr-namespace:Windows.UI.Xaml.Controls;assembly=Windows, Version=255.255.255.255,
Culture=neutral, PublicKeyToken=null, ContentType=WindowsRuntime;targetPlatform=Windows"
xmlns:local="clr-namespace:NativeSwitch"
x:Class="NativeSwitch.NativeSwitchPage">
<StackLayout Margin="20">
<Label Text="Native Views Demo" FontAttributes="Bold" HorizontalOptions="Center" />
<Entry Placeholder="This Entry is bound to the native switch" IsEnabled="{Binding IsSwitchOn}" />
<ios:UISwitch On="{Binding Path=IsSwitchOn, Mode=TwoWay, UpdateSourceEventName=ValueChanged}"
OnTintColor="{x:Static ios:UIColor.Red}"
ThumbTintColor="{x:Static ios:UIColor.Blue}" />
<androidWidget:Switch x:Arguments="{x:Static androidLocal:MainActivity.Instance}"
Checked="{Binding Path=IsSwitchOn, Mode=TwoWay, UpdateSourceEventName=CheckedChange}"
Text="Enable Entry?" />
<win:ToggleSwitch Header="Enable Entry?"
OffContent="No"
OnContent="Yes"
IsOn="{Binding IsSwitchOn, Mode=TwoWay, UpdateSourceEventName=Toggled}" />
</StackLayout>
</ContentPage>
A página contém uma Entry
propriedade whose IsEnabled
se associa à NativeSwitchPageViewModel.IsSwitchOn
propriedade. A BindingContext
página é definida como uma nova instância da NativeSwitchPageViewModel
classe no arquivo code-behind, com a classe ViewModel implementando a INotifyPropertyChanged
interface.
A página também contém uma opção nativa para cada plataforma. Cada opção nativa usa uma TwoWay
associação para atualizar o valor da NativeSwitchPageViewModel.IsSwitchOn
propriedade. Portanto, quando a chave está desligada, a é desabilitada Entry
e, quando a chave está ligada, a Entry
é habilitada. As capturas de tela a seguir mostram essa funcionalidade em cada plataforma:
As associações bidirecionais têm suporte automático, desde que a propriedade nativa implemente INotifyPropertyChanged
, ou dê suporte à Observação de Chave-Valor (KVO) no iOS ou seja uma DependencyProperty
na UWP. No entanto, muitas exibições nativas não dão suporte à notificação de alteração de propriedade. Para essas exibições, você pode especificar um UpdateSourceEventName
valor de propriedade como parte da expressão de associação. Essa propriedade deve ser definida como o nome de um evento na exibição nativa que sinaliza quando a propriedade de destino foi alterada. Em seguida, quando o valor do switch nativo é alterado, a classe é notificada Binding
de que o usuário alterou o valor do switch e o valor da NativeSwitchPageViewModel.IsSwitchOn
propriedade é atualizado.
Passar argumentos para visualizações nativas
Os argumentos do construtor podem ser passados para exibições nativas usando o x:Arguments
atributo com uma extensão de x:Static
marcação. Além disso, os métodos de fábrica de exibição nativos (public static
métodos que retornam objetos ou valores do mesmo tipo que a classe ou estrutura que define os métodos) podem ser chamados especificando o nome do método usando o x:FactoryMethod
atributo e seus argumentos usando o x:Arguments
atributo.
O exemplo de código a seguir demonstra ambas as técnicas:
<ContentPage ...
xmlns:ios="clr-namespace:UIKit;assembly=Xamarin.iOS;targetPlatform=iOS"
xmlns:androidWidget="clr-namespace:Android.Widget;assembly=Mono.Android;targetPlatform=Android"
xmlns:androidGraphics="clr-namespace:Android.Graphics;assembly=Mono.Android;targetPlatform=Android"
xmlns:androidLocal="clr-namespace:SimpleColorPicker.Droid;assembly=SimpleColorPicker.Droid;targetPlatform=Android"
xmlns:winControls="clr-namespace:Windows.UI.Xaml.Controls;assembly=Windows, Version=255.255.255.255, Culture=neutral, PublicKeyToken=null, ContentType=WindowsRuntime;targetPlatform=Windows"
xmlns:winMedia="clr-namespace:Windows.UI.Xaml.Media;assembly=Windows, Version=255.255.255.255, Culture=neutral, PublicKeyToken=null, ContentType=WindowsRuntime;targetPlatform=Windows"
xmlns:winText="clr-namespace:Windows.UI.Text;assembly=Windows, Version=255.255.255.255, Culture=neutral, PublicKeyToken=null, ContentType=WindowsRuntime;targetPlatform=Windows"
xmlns:winui="clr-namespace:Windows.UI;assembly=Windows, Version=255.255.255.255, Culture=neutral, PublicKeyToken=null, ContentType=WindowsRuntime;targetPlatform=Windows">
...
<ios:UILabel Text="Simple Native Color Picker" View.HorizontalOptions="Center">
<ios:UILabel.Font>
<ios:UIFont x:FactoryMethod="FromName">
<x:Arguments>
<x:String>Papyrus</x:String>
<x:Single>24</x:Single>
</x:Arguments>
</ios:UIFont>
</ios:UILabel.Font>
</ios:UILabel>
<androidWidget:TextView x:Arguments="{x:Static androidLocal:MainActivity.Instance}"
Text="Simple Native Color Picker"
TextSize="24"
View.HorizontalOptions="Center">
<androidWidget:TextView.Typeface>
<androidGraphics:Typeface x:FactoryMethod="Create">
<x:Arguments>
<x:String>cursive</x:String>
<androidGraphics:TypefaceStyle>Normal</androidGraphics:TypefaceStyle>
</x:Arguments>
</androidGraphics:Typeface>
</androidWidget:TextView.Typeface>
</androidWidget:TextView>
<winControls:TextBlock Text="Simple Native Color Picker"
FontSize="20"
FontStyle="{x:Static winText:FontStyle.Italic}"
View.HorizontalOptions="Center">
<winControls:TextBlock.FontFamily>
<winMedia:FontFamily>
<x:Arguments>
<x:String>Georgia</x:String>
</x:Arguments>
</winMedia:FontFamily>
</winControls:TextBlock.FontFamily>
</winControls:TextBlock>
...
</ContentPage>
O UIFont.FromName
método de fábrica é usado para definir a UILabel.Font
propriedade como new UIFont
no iOS. O UIFont
nome e o tamanho são especificados pelos argumentos de método que são filhos do x:Arguments
atributo.
O Typeface.Create
método de fábrica é usado para definir a TextView.Typeface
propriedade como new Typeface
no Android. O Typeface
nome e o estilo da família são especificados pelos argumentos do método que são filhos do x:Arguments
atributo.
O FontFamily
construtor é usado para definir a TextBlock.FontFamily
propriedade como um novo FontFamily
na Plataforma Universal do Windows (UWP). O FontFamily
nome é especificado pelo argumento de método que é filho do x:Arguments
atributo.
Observação
Os argumentos devem corresponder aos tipos exigidos pelo construtor ou método de fábrica.
As capturas de tela a seguir mostram o resultado da especificação de argumentos de método de fábrica e construtor para definir a fonte em diferentes exibições nativas:
Para obter mais informações sobre como passar argumentos em XAML, consulte Passando argumentos em XAML.
Consulte as exibições nativas do código
Embora não seja possível nomear uma exibição nativa com o x:Name
atributo, é possível recuperar uma instância de exibição nativa declarada em um arquivo XAML de seu arquivo code-behind em um Projeto de Acesso Compartilhado, desde que a exibição nativa seja um filho de um ContentView
que especifica um x:Name
valor de atributo. Em seguida, dentro das diretivas de compilação condicional no arquivo code-behind, você deve:
- Recupere o valor da
ContentView.Content
propriedade e converta-o em um tipo específicoNativeViewWrapper
da plataforma. - Recupere a
NativeViewWrapper.NativeElement
propriedade e converta-a no tipo de exibição nativo.
A API nativa pode então ser invocada na visualização nativa para executar as operações desejadas. Essa abordagem também oferece o benefício de que várias exibições nativas XAML para diferentes plataformas podem ser filhas do mesmo ContentView
. O exemplo de código a seguir demonstra essa técnica:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:ios="clr-namespace:UIKit;assembly=Xamarin.iOS;targetPlatform=iOS"
xmlns:androidWidget="clr-namespace:Android.Widget;assembly=Mono.Android;targetPlatform=Android"
xmlns:androidLocal="clr-namespace:SimpleColorPicker.Droid;assembly=SimpleColorPicker.Droid;targetPlatform=Android"
xmlns:winControls="clr-namespace:Windows.UI.Xaml.Controls;assembly=Windows, Version=255.255.255.255,
Culture=neutral, PublicKeyToken=null, ContentType=WindowsRuntime;targetPlatform=Windows"
xmlns:local="clr-namespace:NativeViewInsideContentView"
x:Class="NativeViewInsideContentView.NativeViewInsideContentViewPage">
<StackLayout Margin="20">
<ContentView x:Name="contentViewTextParent" HorizontalOptions="Center" VerticalOptions="CenterAndExpand">
<ios:UILabel Text="Text in a UILabel" TextColor="{x:Static ios:UIColor.Red}" />
<androidWidget:TextView x:Arguments="{x:Static androidLocal:MainActivity.Instance}"
Text="Text in a TextView" />
<winControls:TextBlock Text="Text in a TextBlock" />
</ContentView>
<ContentView x:Name="contentViewButtonParent" HorizontalOptions="Center" VerticalOptions="EndAndExpand">
<ios:UIButton TouchUpInside="OnButtonTap" View.HorizontalOptions="Center" View.VerticalOptions="Center" />
<androidWidget:Button x:Arguments="{x:Static androidLocal:MainActivity.Instance}"
Text="Scale and Rotate Text"
Click="OnButtonTap" />
<winControls:Button Content="Scale and Rotate Text" />
</ContentView>
</StackLayout>
</ContentPage>
No exemplo acima, as exibições nativas de cada plataforma são filhos de controles, com o valor do ContentView
x:Name
atributo sendo usado para recuperar o ContentView
no code-behind:
public partial class NativeViewInsideContentViewPage : ContentPage
{
public NativeViewInsideContentViewPage()
{
InitializeComponent();
#if __IOS__
var wrapper = (Xamarin.Forms.Platform.iOS.NativeViewWrapper)contentViewButtonParent.Content;
var button = (UIKit.UIButton)wrapper.NativeView;
button.SetTitle("Scale and Rotate Text", UIKit.UIControlState.Normal);
button.SetTitleColor(UIKit.UIColor.Black, UIKit.UIControlState.Normal);
#endif
#if __ANDROID__
var wrapper = (Xamarin.Forms.Platform.Android.NativeViewWrapper)contentViewTextParent.Content;
var textView = (Android.Widget.TextView)wrapper.NativeView;
textView.SetTextColor(Android.Graphics.Color.Red);
#endif
#if WINDOWS_UWP
var textWrapper = (Xamarin.Forms.Platform.UWP.NativeViewWrapper)contentViewTextParent.Content;
var textBlock = (Windows.UI.Xaml.Controls.TextBlock)textWrapper.NativeElement;
textBlock.Foreground = new Windows.UI.Xaml.Media.SolidColorBrush(Windows.UI.Colors.Red);
var buttonWrapper = (Xamarin.Forms.Platform.UWP.NativeViewWrapper)contentViewButtonParent.Content;
var button = (Windows.UI.Xaml.Controls.Button)buttonWrapper.NativeElement;
button.Click += (sender, args) => OnButtonTap(sender, EventArgs.Empty);
#endif
}
async void OnButtonTap(object sender, EventArgs e)
{
contentViewButtonParent.Content.IsEnabled = false;
contentViewTextParent.Content.ScaleTo(2, 2000);
await contentViewTextParent.Content.RotateTo(360, 2000);
contentViewTextParent.Content.ScaleTo(1, 2000);
await contentViewTextParent.Content.RelRotateTo(360, 2000);
contentViewButtonParent.Content.IsEnabled = true;
}
}
A ContentView.Content
propriedade é acessada para recuperar a exibição nativa encapsulada como uma instância específica NativeViewWrapper
da plataforma. Em seguida, a NativeViewWrapper.NativeElement
propriedade é acessada para recuperar a exibição nativa como seu tipo nativo. A API da visualização nativa é então invocada para executar as operações desejadas.
Os botões nativos do iOS e do Android compartilham o mesmo OnButtonTap
manipulador de eventos, pois cada botão nativo consome um EventHandler
delegado em resposta a um evento de toque. No entanto, a Plataforma Universal do Windows (UWP) usa um RoutedEventHandler
, que, por sua vez, consome o OnButtonTap
manipulador de eventos neste exemplo. Portanto, quando um botão nativo é clicado, o OnButtonTap
manipulador de eventos é executado, o que dimensiona e gira o controle nativo contido no ContentView
.contentViewTextParent
As capturas de tela a seguir demonstram que isso ocorre em cada plataforma:
Visualizações nativas de subclasse
Muitas exibições nativas do iOS e do Android não são adequadas para instanciação em XAML porque usam métodos, em vez de propriedades, para configurar o controle. A solução para esse problema é criar uma subclasse de exibições nativas em wrappers que definem uma API mais amigável para XAML que usa propriedades para configurar o controle e que usa eventos independentes de plataforma. As exibições nativas encapsuladas podem ser colocadas em um SAP (Projeto de Ativo Compartilhado) e cercadas por diretivas de compilação condicional ou colocadas em projetos específicos da plataforma e referenciadas do XAML em um projeto de biblioteca do .NET Standard.
O exemplo de código a seguir demonstra uma Xamarin.Forms página que consome exibições nativas de subclasse:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:ios="clr-namespace:UIKit;assembly=Xamarin.iOS;targetPlatform=iOS"
xmlns:iosLocal="clr-namespace:SubclassedNativeControls.iOS;assembly=SubclassedNativeControls.iOS;targetPlatform=iOS"
xmlns:android="clr-namespace:Android.Widget;assembly=Mono.Android;targetPlatform=Android"
xmlns:androidLocal="clr-namespace:SimpleColorPicker.Droid;assembly=SimpleColorPicker.Droid;targetPlatform=Android"
xmlns:androidLocal="clr-namespace:SubclassedNativeControls.Droid;assembly=SubclassedNativeControls.Droid;targetPlatform=Android"
xmlns:winControls="clr-namespace:Windows.UI.Xaml.Controls;assembly=Windows, Version=255.255.255.255,
Culture=neutral, PublicKeyToken=null, ContentType=WindowsRuntime;targetPlatform=Windows"
xmlns:local="clr-namespace:SubclassedNativeControls"
x:Class="SubclassedNativeControls.SubclassedNativeControlsPage">
<StackLayout Margin="20">
<Label Text="Subclassed Native Views Demo" FontAttributes="Bold" HorizontalOptions="Center" />
<StackLayout Orientation="Horizontal">
<Label Text="You have chosen:" />
<Label Text="{Binding SelectedFruit}" />
</StackLayout>
<iosLocal:MyUIPickerView ItemsSource="{Binding Fruits}"
SelectedItem="{Binding SelectedFruit, Mode=TwoWay, UpdateSourceEventName=SelectedItemChanged}" />
<androidLocal:MySpinner x:Arguments="{x:Static androidLocal:MainActivity.Instance}"
ItemsSource="{Binding Fruits}"
SelectedObject="{Binding SelectedFruit, Mode=TwoWay, UpdateSourceEventName=ItemSelected}" />
<winControls:ComboBox ItemsSource="{Binding Fruits}"
SelectedItem="{Binding SelectedFruit, Mode=TwoWay, UpdateSourceEventName=SelectionChanged}" />
</StackLayout>
</ContentPage>
A página contém um Label
que exibe a fruta escolhida pelo usuário de um controle nativo. O Label
vincula-se SubclassedNativeControlsPageViewModel.SelectedFruit
à propriedade. A BindingContext
página é definida como uma nova instância da SubclassedNativeControlsPageViewModel
classe no arquivo code-behind, com a classe ViewModel implementando a INotifyPropertyChanged
interface.
A página também contém uma visualização de seletor nativa para cada plataforma. Cada exibição nativa exibe a coleção de frutas vinculando sua ItemSource
propriedade à SubclassedNativeControlsPageViewModel.Fruits
coleção. Isso permite que o usuário colha uma fruta, conforme mostrado nas capturas de tela a seguir:
No iOS e no Android, os seletores nativos usam métodos para configurar os controles. Portanto, esses seletores devem ser subclassificados para expor propriedades para torná-los compatíveis com XAML. Na Plataforma Universal do Windows (UWP), o ComboBox
já é compatível com XAML e, portanto, não requer subclasse.
iOS
A implementação do iOS subclasse a UIPickerView
exibição e expõe propriedades e um evento que pode ser facilmente consumido do XAML:
public class MyUIPickerView : UIPickerView
{
public event EventHandler<EventArgs> SelectedItemChanged;
public MyUIPickerView()
{
var model = new PickerModel();
model.ItemChanged += (sender, e) =>
{
if (SelectedItemChanged != null)
{
SelectedItemChanged.Invoke(this, e);
}
};
Model = model;
}
public IList<string> ItemsSource
{
get
{
var pickerModel = Model as PickerModel;
return (pickerModel != null) ? pickerModel.Items : null;
}
set
{
var model = Model as PickerModel;
if (model != null)
{
model.Items = value;
}
}
}
public string SelectedItem
{
get { return (Model as PickerModel).SelectedItem; }
set { }
}
}
A MyUIPickerView
classe expõe ItemsSource
e SelectedItem
propriedades e um SelectedItemChanged
evento. A UIPickerView
requer um modelo de dados subjacente UIPickerViewModel
, que é acessado pelas propriedades e pelo MyUIPickerView
evento. O UIPickerViewModel
modelo de dados é fornecido pela PickerModel
classe:
class PickerModel : UIPickerViewModel
{
int selectedIndex = 0;
public event EventHandler<EventArgs> ItemChanged;
public IList<string> Items { get; set; }
public string SelectedItem
{
get
{
return Items != null && selectedIndex >= 0 && selectedIndex < Items.Count ? Items[selectedIndex] : null;
}
}
public override nint GetRowsInComponent(UIPickerView pickerView, nint component)
{
return Items != null ? Items.Count : 0;
}
public override string GetTitle(UIPickerView pickerView, nint row, nint component)
{
return Items != null && Items.Count > row ? Items[(int)row] : null;
}
public override nint GetComponentCount(UIPickerView pickerView)
{
return 1;
}
public override void Selected(UIPickerView pickerView, nint row, nint component)
{
selectedIndex = (int)row;
if (ItemChanged != null)
{
ItemChanged.Invoke(this, new EventArgs());
}
}
}
A PickerModel
classe fornece o armazenamento subjacente para a MyUIPickerView
classe, por meio da Items
propriedade. Sempre que o item selecionado nas MyUIPickerView
alterações, o Selected
método é executado, o que atualiza o índice selecionado e dispara o ItemChanged
evento. Isso garante que a SelectedItem
propriedade sempre retornará o último item selecionado pelo usuário. Além disso, a PickerModel
classe substitui os métodos usados para configurar a MyUIPickerView
instância.
Android
A implementação do Android subclasse a Spinner
exibição e expõe propriedades e um evento que pode ser facilmente consumido do XAML:
class MySpinner : Spinner
{
ArrayAdapter adapter;
IList<string> items;
public IList<string> ItemsSource
{
get { return items; }
set
{
if (items != value)
{
items = value;
adapter.Clear();
foreach (string str in items)
{
adapter.Add(str);
}
}
}
}
public string SelectedObject
{
get { return (string)GetItemAtPosition(SelectedItemPosition); }
set
{
if (items != null)
{
int index = items.IndexOf(value);
if (index != -1)
{
SetSelection(index);
}
}
}
}
public MySpinner(Context context) : base(context)
{
ItemSelected += OnBindableSpinnerItemSelected;
adapter = new ArrayAdapter(context, Android.Resource.Layout.SimpleSpinnerItem);
adapter.SetDropDownViewResource(Android.Resource.Layout.SimpleSpinnerDropDownItem);
Adapter = adapter;
}
void OnBindableSpinnerItemSelected(object sender, ItemSelectedEventArgs args)
{
SelectedObject = (string)GetItemAtPosition(args.Position);
}
}
A MySpinner
classe expõe ItemsSource
e SelectedObject
propriedades e um ItemSelected
evento. Os itens exibidos pela MySpinner
classe são fornecidos pelo Adapter
associado à exibição e os itens são preenchidos Adapter
no quando a ItemsSource
propriedade é definida pela primeira vez. Sempre que o item selecionado na MySpinner
classe é alterado, o manipulador de OnBindableSpinnerItemSelected
eventos atualiza a SelectedObject
propriedade.