Vues natives en C#
Les vues natives iOS, Android et UWP peuvent être directement référencées à partir de pages créées à l’aide de Xamarin.Forms C#. Cet article montre comment ajouter des vues natives à une Xamarin.Forms disposition créée à l’aide de C#, et comment remplacer la disposition des vues personnalisées pour corriger leur utilisation de l’API de mesure.
Vue d’ensemble
Tout Xamarin.Forms contrôle qui permet Content
d’être défini, ou qui a une collection, peut ajouter des vues spécifiques à la Children
plateforme. Par exemple, un iOS UILabel
peut être directement ajouté à la ContentView.Content
propriété ou à la StackLayout.Children
collection. Toutefois, notez que cette fonctionnalité nécessite l’utilisation de #if
définitions dans Xamarin.Forms les solutions de projet partagé et n’est pas disponible à partir de solutions de Xamarin.Forms bibliothèque .NET Standard.
Les captures d’écran suivantes illustrent les vues spécifiques à la plateforme qui ont été ajoutées à un Xamarin.FormsStackLayout
:
La possibilité d’ajouter des vues spécifiques à une plateforme à une Xamarin.Forms disposition est activée par deux méthodes d’extension sur chaque plateforme :
Add
: ajoute une vue spécifique à la plateforme à laChildren
collection d’une disposition.ToView
: prend une vue spécifique à la plateforme et l’encapsule en tant Xamarin.FormsView
que propriétéContent
d’un contrôle.
L’utilisation de ces méthodes dans un Xamarin.Forms projet partagé nécessite l’importation de l’espace de noms spécifique à Xamarin.Forms la plateforme approprié :
- iOS - Xamarin.Forms. Platform.iOS
- Android - Xamarin.Forms. Platform.Android
- plateforme Windows universelle (UWP) – Xamarin.Forms. Platform.UWP
Ajout d’affichages spécifiques à la plateforme sur chaque plateforme
Les sections suivantes montrent comment ajouter des vues spécifiques à la plateforme à une Xamarin.Forms disposition sur chaque plateforme.
iOS
L’exemple de code suivant montre comment ajouter un UILabel
à un et un StackLayout
ContentView
:
var uiLabel = new UILabel {
MinimumFontSize = 14f,
Lines = 0,
LineBreakMode = UILineBreakMode.WordWrap,
Text = originalText,
};
stackLayout.Children.Add (uiLabel);
contentView.Content = uiLabel.ToView();
L’exemple suppose que les instances et contentView
les stackLayout
instances ont déjà été créées en XAML ou C#.
Android
L’exemple de code suivant montre comment ajouter un TextView
à un et un StackLayout
ContentView
:
var textView = new TextView (MainActivity.Instance) { Text = originalText, TextSize = 14 };
stackLayout.Children.Add (textView);
contentView.Content = textView.ToView();
L’exemple suppose que les instances et contentView
les stackLayout
instances ont déjà été créées en XAML ou C#.
Plateforme Windows universelle
L’exemple de code suivant montre comment ajouter un TextBlock
à un et un StackLayout
ContentView
:
var textBlock = new TextBlock
{
Text = originalText,
FontSize = 14,
FontFamily = new FontFamily("HelveticaNeue"),
TextWrapping = TextWrapping.Wrap
};
stackLayout.Children.Add(textBlock);
contentView.Content = textBlock.ToView();
L’exemple suppose que les instances et contentView
les stackLayout
instances ont déjà été créées en XAML ou C#.
Substitution de mesures de plateforme pour les vues personnalisées
Les vues personnalisées sur chaque plateforme implémentent souvent uniquement correctement la mesure pour le scénario de disposition pour lequel elles ont été conçues. Par exemple, une vue personnalisée peut avoir été conçue pour occuper uniquement la moitié de la largeur disponible de l’appareil. Toutefois, après avoir été partagé avec d’autres utilisateurs, la vue personnalisée peut être nécessaire pour occuper toute la largeur disponible de l’appareil. Par conséquent, il peut être nécessaire de remplacer une implémentation de mesure de vues personnalisées lors de la réutilisation dans une Xamarin.Forms disposition. Pour cette raison, les Add
méthodes d’extension fournissent ToView
des remplacements qui permettent aux délégués de mesure d’être spécifiés, ce qui peut remplacer la disposition d’affichage personnalisé lorsqu’elle est ajoutée à une Xamarin.Forms disposition.
Les sections suivantes montrent comment remplacer la disposition des vues personnalisées pour corriger leur utilisation de l’API de mesure.
iOS
L’exemple de code suivant montre la CustomControl
classe, qui hérite de UILabel
:
public class CustomControl : UILabel
{
public override string Text {
get { return base.Text; }
set { base.Text = value.ToUpper (); }
}
public override CGSize SizeThatFits (CGSize size)
{
return new CGSize (size.Width, 150);
}
}
Une instance de cette vue est ajoutée à un StackLayout
, comme illustré dans l’exemple de code suivant :
var customControl = new CustomControl {
MinimumFontSize = 14,
Lines = 0,
LineBreakMode = UILineBreakMode.WordWrap,
Text = "This control has incorrect sizing - there's empty space above and below it."
};
stackLayout.Children.Add (customControl);
Toutefois, étant donné que le CustomControl.SizeThatFits
remplacement retourne toujours une hauteur de 150, la vue s’affiche avec un espace vide au-dessus et en dessous, comme illustré dans la capture d’écran suivante :
Une solution à ce problème consiste à fournir une GetDesiredSizeDelegate
implémentation, comme illustré dans l’exemple de code suivant :
SizeRequest? FixSize (NativeViewWrapperRenderer renderer, double width, double height)
{
var uiView = renderer.Control;
if (uiView == null) {
return null;
}
var constraint = new CGSize (width, height);
// Let the CustomControl determine its size (which will be wrong)
var badRect = uiView.SizeThatFits (constraint);
// Use the width and substitute the height
return new SizeRequest (new Size (badRect.Width, 70));
}
Cette méthode utilise la largeur fournie par la CustomControl.SizeThatFits
méthode, mais remplace la hauteur de 150 par une hauteur de 70. Lorsque l’instance CustomControl
est ajoutée au StackLayout
, la FixSize
méthode peut être spécifiée en tant que GetDesiredSizeDelegate
pour corriger la mesure incorrecte fournie par la CustomControl
classe :
stackLayout.Children.Add (customControl, FixSize);
Cela entraîne l’affichage personnalisé correctement, sans espace vide ci-dessus et en dessous, comme illustré dans la capture d’écran suivante :
Android
L’exemple de code suivant montre la CustomControl
classe, qui hérite de TextView
:
public class CustomControl : TextView
{
public CustomControl (Context context) : base (context)
{
}
protected override void OnMeasure (int widthMeasureSpec, int heightMeasureSpec)
{
int width = MeasureSpec.GetSize (widthMeasureSpec);
// Force the width to half of what's been requested.
// This is deliberately wrong to demonstrate providing an override to fix it with.
int widthSpec = MeasureSpec.MakeMeasureSpec (width / 2, MeasureSpec.GetMode (widthMeasureSpec));
base.OnMeasure (widthSpec, heightMeasureSpec);
}
}
Une instance de cette vue est ajoutée à un StackLayout
, comme illustré dans l’exemple de code suivant :
var customControl = new CustomControl (MainActivity.Instance) {
Text = "This control has incorrect sizing - it doesn't occupy the available width of the device.",
TextSize = 14
};
stackLayout.Children.Add (customControl);
Toutefois, étant donné que le CustomControl.OnMeasure
remplacement retourne toujours la moitié de la largeur demandée, la vue s’affiche en occupant seulement la moitié de la largeur disponible de l’appareil, comme illustré dans la capture d’écran suivante :
Une solution à ce problème consiste à fournir une GetDesiredSizeDelegate
implémentation, comme illustré dans l’exemple de code suivant :
SizeRequest? FixSize (NativeViewWrapperRenderer renderer, int widthConstraint, int heightConstraint)
{
var nativeView = renderer.Control;
if ((widthConstraint == 0 && heightConstraint == 0) || nativeView == null) {
return null;
}
int width = Android.Views.View.MeasureSpec.GetSize (widthConstraint);
int widthSpec = Android.Views.View.MeasureSpec.MakeMeasureSpec (
width * 2, Android.Views.View.MeasureSpec.GetMode (widthConstraint));
nativeView.Measure (widthSpec, heightConstraint);
return new SizeRequest (new Size (nativeView.MeasuredWidth, nativeView.MeasuredHeight));
}
Cette méthode utilise la largeur fournie par la CustomControl.OnMeasure
méthode, mais la multiplie par deux. Lorsque l’instance CustomControl
est ajoutée au StackLayout
, la FixSize
méthode peut être spécifiée en tant que GetDesiredSizeDelegate
pour corriger la mesure incorrecte fournie par la CustomControl
classe :
stackLayout.Children.Add (customControl, FixSize);
Cela entraîne l’affichage personnalisé affiché correctement, occupant la largeur de l’appareil, comme illustré dans la capture d’écran suivante :
Plateforme Windows universelle
L’exemple de code suivant montre la CustomControl
classe, qui hérite de Panel
:
public class CustomControl : Panel
{
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register(
"Text", typeof(string), typeof(CustomControl), new PropertyMetadata(default(string), OnTextPropertyChanged));
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value.ToUpper()); }
}
readonly TextBlock textBlock;
public CustomControl()
{
textBlock = new TextBlock
{
MinHeight = 0,
MaxHeight = double.PositiveInfinity,
MinWidth = 0,
MaxWidth = double.PositiveInfinity,
FontSize = 14,
TextWrapping = TextWrapping.Wrap,
VerticalAlignment = VerticalAlignment.Center
};
Children.Add(textBlock);
}
static void OnTextPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
{
((CustomControl)dependencyObject).textBlock.Text = (string)args.NewValue;
}
protected override Size ArrangeOverride(Size finalSize)
{
// This is deliberately wrong to demonstrate providing an override to fix it with.
textBlock.Arrange(new Rect(0, 0, finalSize.Width/2, finalSize.Height));
return finalSize;
}
protected override Size MeasureOverride(Size availableSize)
{
textBlock.Measure(availableSize);
return new Size(textBlock.DesiredSize.Width, textBlock.DesiredSize.Height);
}
}
Une instance de cette vue est ajoutée à un StackLayout
, comme illustré dans l’exemple de code suivant :
var brokenControl = new CustomControl {
Text = "This control has incorrect sizing - it doesn't occupy the available width of the device."
};
stackLayout.Children.Add(brokenControl);
Toutefois, étant donné que le CustomControl.ArrangeOverride
remplacement retourne toujours la moitié de la largeur demandée, la vue est clippée à la moitié de la largeur disponible de l’appareil, comme illustré dans la capture d’écran suivante :
Une solution à ce problème consiste à fournir une ArrangeOverrideDelegate
implémentation, lors de l’ajout de la vue à l’exemple StackLayout
de code suivant :
stackLayout.Children.Add(fixedControl, arrangeOverrideDelegate: (renderer, finalSize) =>
{
if (finalSize.Width <= 0 || double.IsInfinity(finalSize.Width))
{
return null;
}
var frameworkElement = renderer.Control;
frameworkElement.Arrange(new Rect(0, 0, finalSize.Width * 2, finalSize.Height));
return finalSize;
});
Cette méthode utilise la largeur fournie par la CustomControl.ArrangeOverride
méthode, mais la multiplie par deux. Cela entraîne l’affichage personnalisé affiché correctement, occupant la largeur de l’appareil, comme illustré dans la capture d’écran suivante :
Résumé
Cet article explique comment ajouter des vues natives à une Xamarin.Forms disposition créée à l’aide de C#, et comment remplacer la disposition des vues personnalisées pour corriger leur utilisation de l’API de mesure.