Partager via


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:

StackLayout contenant des vues spécifiques à la plateforme

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 à la Children 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 StackLayoutContentView:

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 StackLayoutContentView:

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 StackLayoutContentView:

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 :

Implémentation d’iOS CustomControl avec une implémentation Bad SizeThatFits

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 :

CustomControl iOS avec GetDesiredSize Override

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 :

Implémentation d’Android CustomControl avec Bad OnMeasure

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 :

Android CustomControl avec délégué GetDesiredSize personnalisé

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 :

UWP CustomControl avec implémentation Bad ArrangeOverride

Une solution à ce problème consiste à fournir une ArrangeOverrideDelegate implémentation, lors de l’ajout de la vue à l’exemple StackLayoutde 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 :

UWP CustomControl avec le délégué ArrangeOverride

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.