Native Ansichten in C#
Native Ansichten aus iOS, Android und UWP können direkt von Xamarin.Forms Seiten verwiesen werden, die mit C# erstellt wurden. In diesem Artikel wird veranschaulicht, wie Sie einem Xamarin.Forms layout, das mit C# erstellt wurde, systemeigene Ansichten hinzufügen und das Layout von benutzerdefinierten Ansichten außer Kraft setzen, um die Verwendung der Maß-API zu korrigieren.
Übersicht
Jedes Xamarin.Forms Steuerelement, das das Festlegen oder eine Children
Sammlung ermöglichtContent
, kann plattformspezifische Ansichten hinzufügen. Beispielsweise kann ein iOS UILabel
direkt der ContentView.Content
Eigenschaft oder der StackLayout.Children
Auflistung hinzugefügt werden. Beachten Sie jedoch, dass diese Funktionalität die Verwendung von #if
Definierten in Xamarin.Forms Freigegebenen Projektlösungen erfordert und nicht über Xamarin.Forms .NET Standard-Bibliothekslösungen verfügbar ist.
Die folgenden Screenshots veranschaulichen plattformspezifische Ansichten, die zu einer Xamarin.FormsStackLayout
hinzugefügt wurden:
Die Möglichkeit, plattformspezifische Ansichten zu einem Xamarin.Forms Layout hinzuzufügen, wird durch zwei Erweiterungsmethoden auf jeder Plattform aktiviert:
Add
– fügt derChildren
Sammlung eines Layouts eine plattformspezifische Ansicht hinzu.ToView
– verwendet eine plattformspezifische Ansicht und umschließt sie als Xamarin.FormsView
Content
Eigenschaft eines Steuerelements.
Wenn Sie diese Methoden in einem Xamarin.Forms freigegebenen Projekt verwenden, müssen Sie den entsprechenden plattformspezifischen Xamarin.Forms Namespace importieren:
- iOS: Xamarin.Forms.Platform.iOS
- Android: Xamarin.Forms.Platform.Android
- Universelle Windows-Plattform (UWP): Xamarin.Forms.Platform.UWP
Hinzufügen plattformspezifischer Ansichten auf jeder Plattform
In den folgenden Abschnitten wird veranschaulicht, wie Plattformspezifische Ansichten zu einem Xamarin.Forms Layout auf jeder Plattform hinzugefügt werden.
iOS
Im folgenden Codebeispiel wird veranschaulicht, wie Sie einem UILabel
StackLayout
und einem :ContentView
var uiLabel = new UILabel {
MinimumFontSize = 14f,
Lines = 0,
LineBreakMode = UILineBreakMode.WordWrap,
Text = originalText,
};
stackLayout.Children.Add (uiLabel);
contentView.Content = uiLabel.ToView();
Im Beispiel wird davon ausgegangen, dass die stackLayout
Instanzen und contentView
Instanzen zuvor in XAML oder C# erstellt wurden.
Android
Im folgenden Codebeispiel wird veranschaulicht, wie Sie einem TextView
StackLayout
und einem :ContentView
var textView = new TextView (MainActivity.Instance) { Text = originalText, TextSize = 14 };
stackLayout.Children.Add (textView);
contentView.Content = textView.ToView();
Im Beispiel wird davon ausgegangen, dass die stackLayout
Instanzen und contentView
Instanzen zuvor in XAML oder C# erstellt wurden.
Universelle Windows-Plattform
Im folgenden Codebeispiel wird veranschaulicht, wie Sie einem TextBlock
StackLayout
und einem :ContentView
var textBlock = new TextBlock
{
Text = originalText,
FontSize = 14,
FontFamily = new FontFamily("HelveticaNeue"),
TextWrapping = TextWrapping.Wrap
};
stackLayout.Children.Add(textBlock);
contentView.Content = textBlock.ToView();
Im Beispiel wird davon ausgegangen, dass die stackLayout
Instanzen und contentView
Instanzen zuvor in XAML oder C# erstellt wurden.
Überschreiben von Plattformmaßen für benutzerdefinierte Ansichten
Benutzerdefinierte Ansichten auf jeder Plattform implementieren häufig nur die richtige Messung für das Layoutszenario, für das sie entworfen wurden. Beispielsweise wurde möglicherweise eine benutzerdefinierte Ansicht so konzipiert, dass nur die Hälfte der verfügbaren Breite des Geräts belegt wird. Nach der Freigabe für andere Benutzer muss die benutzerdefinierte Ansicht jedoch möglicherweise die volle verfügbare Breite des Geräts belegen. Daher kann es erforderlich sein, eine benutzerdefinierte Ansichtsmessimplementierung außer Kraft zu setzen, wenn sie in einem Xamarin.Forms Layout wiederverwendet wird. Aus diesem Grund stellen die Add
Methoden und ToView
Erweiterungsmethoden Außerkraftsetzungen bereit, mit denen Maßdelegatten angegeben werden können, die das benutzerdefinierte Ansichtslayout überschreiben können, wenn es einem Xamarin.Forms Layout hinzugefügt wird.
In den folgenden Abschnitten wird veranschaulicht, wie sie das Layout von benutzerdefinierten Ansichten außer Kraft setzen, um die Verwendung der Maß-API zu korrigieren.
iOS
Das folgende Codebeispiel zeigt die CustomControl
Klasse, die von 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);
}
}
Eine Instanz dieser Ansicht wird einem StackLayout
, wie im folgenden Codebeispiel gezeigt, hinzugefügt:
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);
Da die CustomControl.SizeThatFits
Außerkraftsetzung jedoch immer eine Höhe von 150 zurückgibt, wird die Ansicht mit leerem Platz darüber und darunter angezeigt, wie im folgenden Screenshot gezeigt:
Eine Lösung für dieses Problem besteht darin, eine GetDesiredSizeDelegate
Implementierung bereitzustellen, wie im folgenden Codebeispiel gezeigt:
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));
}
Diese Methode verwendet die von der CustomControl.SizeThatFits
Methode bereitgestellte Breite, ersetzt jedoch die Höhe von 150 für eine Höhe von 70. Wenn die CustomControl
Instanz der StackLayout
Klasse hinzugefügt wird, kann die FixSize
Methode angegeben GetDesiredSizeDelegate
werden, um die von der CustomControl
Klasse bereitgestellte schlechte Messung zu beheben:
stackLayout.Children.Add (customControl, FixSize);
Dies führt dazu, dass die benutzerdefinierte Ansicht ordnungsgemäß angezeigt wird, ohne leerer Platz darüber und darunter, wie im folgenden Screenshot gezeigt:
Android
Das folgende Codebeispiel zeigt die CustomControl
Klasse, die von 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);
}
}
Eine Instanz dieser Ansicht wird einem StackLayout
, wie im folgenden Codebeispiel gezeigt, hinzugefügt:
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);
Da die CustomControl.OnMeasure
Außerkraftsetzung jedoch immer die Hälfte der angeforderten Breite zurückgibt, wird die Ansicht nur die Hälfte der verfügbaren Breite des Geräts angezeigt, wie im folgenden Screenshot gezeigt:
Eine Lösung für dieses Problem besteht darin, eine GetDesiredSizeDelegate
Implementierung bereitzustellen, wie im folgenden Codebeispiel gezeigt:
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));
}
Diese Methode verwendet die von der CustomControl.OnMeasure
Methode bereitgestellte Breite, multipliziert sie jedoch mit zwei. Wenn die CustomControl
Instanz der StackLayout
Klasse hinzugefügt wird, kann die FixSize
Methode angegeben GetDesiredSizeDelegate
werden, um die von der CustomControl
Klasse bereitgestellte schlechte Messung zu beheben:
stackLayout.Children.Add (customControl, FixSize);
Dies führt dazu, dass die benutzerdefinierte Ansicht richtig angezeigt wird, wobei die Breite des Geräts belegt wird, wie im folgenden Screenshot gezeigt:
Universelle Windows-Plattform
Das folgende Codebeispiel zeigt die CustomControl
Klasse, die von 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);
}
}
Eine Instanz dieser Ansicht wird einem StackLayout
, wie im folgenden Codebeispiel gezeigt, hinzugefügt:
var brokenControl = new CustomControl {
Text = "This control has incorrect sizing - it doesn't occupy the available width of the device."
};
stackLayout.Children.Add(brokenControl);
Da die CustomControl.ArrangeOverride
Außerkraftsetzung jedoch immer die Hälfte der angeforderten Breite zurückgibt, wird die Ansicht auf die Hälfte der verfügbaren Breite des Geräts zugeschnitten, wie im folgenden Screenshot gezeigt:
Eine Lösung für dieses Problem besteht darin, eine ArrangeOverrideDelegate
Implementierung bereitzustellen, wenn sie der Ansicht StackLayout
hinzugefügt wird, wie im folgenden Codebeispiel gezeigt:
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;
});
Diese Methode verwendet die von der CustomControl.ArrangeOverride
Methode bereitgestellte Breite, multipliziert sie jedoch mit zwei. Dies führt dazu, dass die benutzerdefinierte Ansicht richtig angezeigt wird, wobei die Breite des Geräts belegt wird, wie im folgenden Screenshot gezeigt:
Zusammenfassung
In diesem Artikel wird erläutert, wie Sie einem Xamarin.Forms layout, das mit C# erstellt wurde, systemeigene Ansichten hinzufügen und das Layout von benutzerdefinierten Ansichten außer Kraft setzen, um die Verwendung der Maß-API zu korrigieren.