Visualizzazioni native in C#
È possibile fare riferimento direttamente alle visualizzazioni native da iOS, Android e UWP dalle Xamarin.Forms pagine create con C#. Questo articolo illustra come aggiungere visualizzazioni native a un Xamarin.Forms layout creato con C# e come eseguire l'override del layout delle visualizzazioni personalizzate per correggere l'utilizzo dell'API di misurazione.
Panoramica
Qualsiasi Xamarin.Forms controllo che consente di Content
impostare o che dispone di una Children
raccolta può aggiungere visualizzazioni specifiche della piattaforma. Ad esempio, un iOS UILabel
può essere aggiunto direttamente alla ContentView.Content
proprietà o alla StackLayout.Children
raccolta. Si noti tuttavia che questa funzionalità richiede l'uso di #if
definisce nelle Xamarin.Forms soluzioni di progetto condiviso e non è disponibile dalle Xamarin.Forms soluzioni di libreria .NET Standard.
Gli screenshot seguenti illustrano le visualizzazioni specifiche della piattaforma aggiunte a un oggetto Xamarin.FormsStackLayout
:
La possibilità di aggiungere visualizzazioni specifiche della piattaforma a un Xamarin.Forms layout è abilitata da due metodi di estensione in ogni piattaforma:
Add
: aggiunge una visualizzazione specifica dellaChildren
piattaforma alla raccolta di un layout.ToView
: accetta una visualizzazione specifica della piattaforma e la esegue il wrapping come oggetto Xamarin.FormsView
che può essere impostato comeContent
proprietà di un controllo.
L'uso di questi metodi in un Xamarin.Forms progetto condiviso richiede l'importazione dello spazio dei nomi specifico Xamarin.Forms della piattaforma appropriato:
- iOS : Xamarin.Forms. Platform.iOS
- Android : Xamarin.Forms. Platform.Android
- piattaforma UWP (Universal Windows Platform) (UWP) - Xamarin.Forms. Platform.UWP
Aggiunta di viste specifiche della piattaforma in ogni piattaforma
Le sezioni seguenti illustrano come aggiungere visualizzazioni specifiche della piattaforma a un Xamarin.Forms layout in ogni piattaforma.
iOS
Nell'esempio di codice seguente viene illustrato come aggiungere un UILabel
oggetto a StackLayout
e a ContentView
:
var uiLabel = new UILabel {
MinimumFontSize = 14f,
Lines = 0,
LineBreakMode = UILineBreakMode.WordWrap,
Text = originalText,
};
stackLayout.Children.Add (uiLabel);
contentView.Content = uiLabel.ToView();
L'esempio presuppone che le stackLayout
istanze e contentView
siano state create in precedenza in XAML o C#.
Android
Nell'esempio di codice seguente viene illustrato come aggiungere un TextView
oggetto a StackLayout
e a ContentView
:
var textView = new TextView (MainActivity.Instance) { Text = originalText, TextSize = 14 };
stackLayout.Children.Add (textView);
contentView.Content = textView.ToView();
L'esempio presuppone che le stackLayout
istanze e contentView
siano state create in precedenza in XAML o C#.
Piattaforma UWP (Universal Windows Platform)
Nell'esempio di codice seguente viene illustrato come aggiungere un TextBlock
oggetto a StackLayout
e a 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'esempio presuppone che le stackLayout
istanze e contentView
siano state create in precedenza in XAML o C#.
Override delle misurazioni della piattaforma per le visualizzazioni personalizzate
Le visualizzazioni personalizzate in ogni piattaforma spesso implementano correttamente solo la misurazione per lo scenario di layout per il quale sono stati progettati. Ad esempio, una visualizzazione personalizzata può essere stata progettata per occupare solo la metà della larghezza disponibile del dispositivo. Tuttavia, dopo essere stato condiviso con altri utenti, la visualizzazione personalizzata potrebbe essere necessaria per occupare la larghezza completa disponibile del dispositivo. Pertanto, può essere necessario eseguire l'override di un'implementazione di misurazione delle visualizzazioni personalizzate quando viene riutilizzato in un Xamarin.Forms layout. Per questo motivo, i Add
metodi di estensione e ToView
forniscono sostituzioni che consentono di specificare delegati di misurazione, che possono eseguire l'override del layout di visualizzazione personalizzato quando viene aggiunto a un Xamarin.Forms layout.
Le sezioni seguenti illustrano come eseguire l'override del layout delle visualizzazioni personalizzate per correggere l'utilizzo dell'API di misurazione.
iOS
Nell'esempio di codice seguente viene illustrata la CustomControl
classe , che eredita da 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);
}
}
Un'istanza di questa vista viene aggiunta a un StackLayout
oggetto , come illustrato nell'esempio di codice seguente:
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);
Tuttavia, poiché l'override CustomControl.SizeThatFits
restituisce sempre un'altezza pari a 150, la visualizzazione verrà visualizzata con spazio vuoto sopra e sotto di esso, come illustrato nello screenshot seguente:
Una soluzione a questo problema consiste nel fornire un'implementazione GetDesiredSizeDelegate
, come illustrato nell'esempio di codice seguente:
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));
}
Questo metodo usa la larghezza fornita dal CustomControl.SizeThatFits
metodo , ma sostituisce l'altezza di 150 per un'altezza pari a 70. Quando l'istanza CustomControl
viene aggiunta a StackLayout
, il FixSize
metodo può essere specificato come per GetDesiredSizeDelegate
correggere la misurazione non valida fornita dalla CustomControl
classe :
stackLayout.Children.Add (customControl, FixSize);
Ciò comporta la visualizzazione personalizzata visualizzata correttamente, senza spazio vuoto sopra e sotto di esso, come illustrato nello screenshot seguente:
Android
Nell'esempio di codice seguente viene illustrata la CustomControl
classe , che eredita da 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);
}
}
Un'istanza di questa vista viene aggiunta a un StackLayout
oggetto , come illustrato nell'esempio di codice seguente:
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);
Tuttavia, poiché l'override CustomControl.OnMeasure
restituisce sempre metà della larghezza richiesta, la visualizzazione verrà visualizzata occupando solo la metà della larghezza disponibile del dispositivo, come illustrato nello screenshot seguente:
Una soluzione a questo problema consiste nel fornire un'implementazione GetDesiredSizeDelegate
, come illustrato nell'esempio di codice seguente:
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));
}
Questo metodo usa la larghezza fornita dal CustomControl.OnMeasure
metodo , ma la moltiplica per due. Quando l'istanza CustomControl
viene aggiunta a StackLayout
, il FixSize
metodo può essere specificato come per GetDesiredSizeDelegate
correggere la misurazione non valida fornita dalla CustomControl
classe :
stackLayout.Children.Add (customControl, FixSize);
Ciò comporta la visualizzazione personalizzata visualizzata correttamente, occupando la larghezza del dispositivo, come illustrato nello screenshot seguente:
Piattaforma UWP (Universal Windows Platform)
Nell'esempio di codice seguente viene illustrata la CustomControl
classe , che eredita da 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);
}
}
Un'istanza di questa vista viene aggiunta a un StackLayout
oggetto , come illustrato nell'esempio di codice seguente:
var brokenControl = new CustomControl {
Text = "This control has incorrect sizing - it doesn't occupy the available width of the device."
};
stackLayout.Children.Add(brokenControl);
Tuttavia, poiché l'override CustomControl.ArrangeOverride
restituisce sempre metà della larghezza richiesta, la visualizzazione verrà ritagliata a metà della larghezza disponibile del dispositivo, come illustrato nello screenshot seguente:
Una soluzione a questo problema consiste nel fornire un'implementazione ArrangeOverrideDelegate
quando si aggiunge la visualizzazione a StackLayout
, come illustrato nell'esempio di codice seguente:
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;
});
Questo metodo usa la larghezza fornita dal CustomControl.ArrangeOverride
metodo , ma la moltiplica per due. Ciò comporta la visualizzazione personalizzata visualizzata correttamente, occupando la larghezza del dispositivo, come illustrato nello screenshot seguente:
Riepilogo
Questo articolo ha illustrato come aggiungere visualizzazioni native a un Xamarin.Forms layout creato con C# e come eseguire l'override del layout delle visualizzazioni personalizzate per correggere l'utilizzo dell'API di misurazione.