C의 네이티브 뷰#Native Views in C#

샘플 다운로드 샘플 다운로드Download Sample Download the sample

C#을 사용 하 여 만든 Xamarin.Forms 페이지에서 iOS, Android 및 UWP에서 네이티브 뷰를 직접 참조할 수 있습니다. 이 문서에는 C#을 사용 하 여 만든 Xamarin.Forms 레이아웃에 네이티브 뷰를 추가 하는 방법 및 해당 측정 API 사용을 수정 하려면 사용자 지정 보기 레이아웃을 재정의 하는 방법을 보여 줍니다.Native views from iOS, Android, and UWP can be directly referenced from Xamarin.Forms pages created using C#. This article demonstrates how to add native views to a Xamarin.Forms layout created using C#, and how to override the layout of custom views to correct their measurement API usage.

개요Overview

허용 하는 모든 Xamarin.Forms 컨트롤 Content 를 설정할 수 있는 또는 Children 컬렉션 플랫폼 특정 뷰를 추가할 수 있습니다.Any Xamarin.Forms control that allows Content to be set, or that has a Children collection, can add platform-specific views. 예를 들어, iOS UILabel 에 직접 추가할 수 있습니다 합니다 ContentView.Content 속성 또는 합니다 StackLayout.Children 컬렉션.For example, an iOS UILabel can be directly added to the ContentView.Content property, or to the StackLayout.Children collection. 그러나이 기능을 사용 해야는 #if Xamarin.Forms 공유 프로젝트 솔루션에서 정의 하 고 Xamarin.Forms.NET Standard 라이브러리 솔루션에서 사용할 수 없습니다.However, note that this functionality requires the use of #if defines in Xamarin.Forms Shared Project solutions, and isn't available from Xamarin.Forms .NET Standard library solutions.

다음 스크린샷은 플랫폼별 뷰는 Xamarin.Forms에 추가 된 것을 보여 줍니다 StackLayout :The following screenshots demonstrate platform-specific views having been added to a Xamarin.Forms StackLayout:

Xamarin.Forms 레이아웃에 플랫폼 전용 뷰를 추가할 수는 각 플랫폼에서 두 개의 확장 메서드로 사용 됩니다.The ability to add platform-specific views to a Xamarin.Forms layout is enabled by two extension methods on each platform:

  • Add – 플랫폼별 뷰를 추가 합니다 Children 레이아웃의 컬렉션입니다.Add – adds a platform-specific view to the Children collection of a layout.
  • ToView – 플랫폼별 뷰를 사용 하 고는 Xamarin.Forms로 래핑되어 View 으로 설정할 수는 Content 컨트롤의 속성입니다.ToView – takes a platform-specific view and wraps it as a Xamarin.Forms View that can be set as the Content property of a control.

이러한 메서드를 사용 하 여 Xamarin.Forms 공유 프로젝트에 적절 한 플랫폼별 Xamarin.Forms 네임 스페이스 가져오기에 필요 합니다.Using these methods in a Xamarin.Forms shared project requires importing the appropriate platform-specific Xamarin.Forms namespace:

  • iOS – Xamarin.Forms.Platform.iOSiOS – Xamarin.Forms.Platform.iOS
  • Android – Xamarin.Forms.Platform.AndroidAndroid – Xamarin.Forms.Platform.Android
  • 유니버설 Windows 플랫폼 (UWP) – Xamarin.Forms.Platform.UWPUniversal Windows Platform (UWP) – Xamarin.Forms.Platform.UWP

각 플랫폼에 플랫폼별 뷰 추가Adding Platform-Specific Views on Each Platform

다음 섹션에서는 각 플랫폼에서 Xamarin.Forms 레이아웃에 플랫폼 전용 뷰를 추가 하는 방법을 보여 줍니다.The following sections demonstrate how to add platform-specific views to a Xamarin.Forms layout on each platform.

iOSiOS

다음 코드 예제에 추가 하는 방법을 보여 줍니다.는 UILabel StackLayout ContentView :The following code example demonstrates how to add a UILabel to a StackLayout and a ContentView:

var uiLabel = new UILabel {
  MinimumFontSize = 14f,
  Lines = 0,
  LineBreakMode = UILineBreakMode.WordWrap,
  Text = originalText,
};
stackLayout.Children.Add (uiLabel);
contentView.Content = uiLabel.ToView();

가정 합니다 stackLayoutcontentView XAML 또는 C#에서 이전에 만든 된 인스턴스.The example assumes that the stackLayout and contentView instances have previously been created in XAML or C#.

AndroidAndroid

다음 코드 예제에 추가 하는 방법을 보여 줍니다.는 TextView StackLayout ContentView :The following code example demonstrates how to add a TextView to a StackLayout and a ContentView:

var textView = new TextView (MainActivity.Instance) { Text = originalText, TextSize = 14 };
stackLayout.Children.Add (textView);
contentView.Content = textView.ToView();

가정 합니다 stackLayoutcontentView XAML 또는 C#에서 이전에 만든 된 인스턴스.The example assumes that the stackLayout and contentView instances have previously been created in XAML or C#.

유니버설 Windows 플랫폼Universal Windows Platform

다음 코드 예제에 추가 하는 방법을 보여 줍니다.는 TextBlock StackLayout ContentView :The following code example demonstrates how to add a TextBlock to a StackLayout and 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();

가정 합니다 stackLayoutcontentView XAML 또는 C#에서 이전에 만든 된 인스턴스.The example assumes that the stackLayout and contentView instances have previously been created in XAML or C#.

사용자 지정 보기에 대 한 플랫폼 측정 값 재정의Overriding Platform Measurements for Custom Views

각 플랫폼에서 사용자 지정 보기는 종종만 올바르게으로 설계 된 레이아웃 시나리오에 대 한 측정을 구현 합니다.Custom views on each platform often only correctly implement measurement for the layout scenario for which they were designed. 예를 들어, 사용자 지정 보기를만 장치의 사용 가능한 너비의 절반을 차지 하도록 설계 되었습니다 수 있습니다.For example, a custom view may have been designed to only occupy half of the available width of the device. 그러나 다른 사용자와 공유 되 고 후 사용자 지정 보기 장치 전체 가용 공간을 차지 하는 데 필요한 수 있습니다.However, after being shared with other users, the custom view may be required to occupy the full available width of the device. 따라서 Xamarin.Forms 레이아웃으로 다시 사용할 때 사용자 지정 보기 측정 구현을 재정의 하는 데 필요한 수 있습니다.Therefore, it can be necessary to override a custom views measurement implementation when being reused in a Xamarin.Forms layout. 이런 이유로 합니다 AddToView 확장 메서드는 Xamarin.Forms 레이아웃에 추가 될 때 사용자 지정 보기 레이아웃을 재정의할 수를 지정 해야 측정 대리자를 허용 하는 재정의 제공 합니다.For that reason, the Add and ToView extension methods provide overrides that allow measurement delegates to be specified, which can override the custom view layout when it's added to a Xamarin.Forms layout.

다음 섹션에서는 해당 측정 API 사용을 수정 하려면 사용자 지정 보기 레이아웃을 재정의 하는 방법을 보여 줍니다.The following sections demonstrate how to override the layout of custom views, to correct their measurement API usage.

iOSiOS

다음 코드 예제는 CustomControl 클래스에서 상속 되는 UILabel:The following code example shows the CustomControl class, which inherits from 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);
  }
}

이 보기의 인스턴스에 추가할를 StackLayout 다음 코드 예제에서 설명한 것 처럼:An instance of this view is added to a StackLayout, as demonstrated in the following code example:

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);

그러나 때문에 CustomControl.SizeThatFits 150 높이 항상 반환 하는 재정의 다음 스크린샷에 표시 된 것 처럼 뷰 위와 아래에 빈 공간을 사용 하 여 표시 됩니다.However, because the CustomControl.SizeThatFits override always returns a height of 150, the view will be displayed with empty space above and below it, as shown in the following screenshot:

이 문제에 솔루션을 제공 하는 것을 GetDesiredSizeDelegate 다음 코드 예제에 설명 된 대로 구현:A solution to this problem is to provide a GetDesiredSizeDelegate implementation, as demonstrated in the following code example:

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));
}

이 메서드는 제공한 너비는 CustomControl.SizeThatFits 70 높이 대 한 150의 높이 하지만 대체 하는 메서드.This method uses the width provided by the CustomControl.SizeThatFits method, but substitutes the height of 150 for a height of 70. 경우는 CustomControl 인스턴스를 추가할는 StackLayout FixSize 으로 메서드를 지정할 수 있습니다를 GetDesiredSizeDelegate 제공한 잘못 된 측정을 해결 하려면는 CustomControl 클래스:When the CustomControl instance is added to the StackLayout, the FixSize method can be specified as the GetDesiredSizeDelegate to fix the bad measurement provided by the CustomControl class:

stackLayout.Children.Add (customControl, FixSize);

따라서 위와 아래에 빈 공간 없이 올바르게 표시 되 고 사용자 지정 보기에서 다음 스크린샷에 표시 된 대로:This results in the custom view being displayed correctly, without empty space above and below it, as shown in the following screenshot:

AndroidAndroid

다음 코드 예제는 CustomControl 클래스에서 상속 되는 TextView:The following code example shows the CustomControl class, which inherits from 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);
  }
}

이 보기의 인스턴스에 추가할를 StackLayout 다음 코드 예제에서 설명한 것 처럼:An instance of this view is added to a StackLayout, as demonstrated in the following code example:

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);

그러나 때문에 CustomControl.OnMeasure 재정의 요청 된 너비의 절반 항목을 항상 반환, 뷰에 표시할 장치의 사용 가능한 너비를 절반만 차지 다음 스크린샷에 표시 된 대로:However, because the CustomControl.OnMeasure override always returns half of the requested width, the view will be displayed occupying only half the available width of the device, as shown in the following screenshot:

이 문제에 솔루션을 제공 하는 것을 GetDesiredSizeDelegate 다음 코드 예제에 설명 된 대로 구현:A solution to this problem is to provide a GetDesiredSizeDelegate implementation, as demonstrated in the following code example:

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));
}

이 메서드는 제공한 너비는 CustomControl.OnMeasure 메서드 하지만 곱한 두 합니다.This method uses the width provided by the CustomControl.OnMeasure method, but multiplies it by two. 경우는 CustomControl 인스턴스를 추가할는 StackLayout FixSize 으로 메서드를 지정할 수 있습니다를 GetDesiredSizeDelegate 제공한 잘못 된 측정을 해결 하려면는 CustomControl 클래스:When the CustomControl instance is added to the StackLayout, the FixSize method can be specified as the GetDesiredSizeDelegate to fix the bad measurement provided by the CustomControl class:

stackLayout.Children.Add (customControl, FixSize);

이 인해 되는 사용자 지정 보기에 올바르게 표시, 장치의 너비를 차지 하는 다음 스크린샷에 표시 된 대로:This results in the custom view being displayed correctly, occupying the width of the device, as shown in the following screenshot:

유니버설 Windows 플랫폼Universal Windows Platform

다음 코드 예제는 CustomControl 클래스에서 상속 되는 Panel:The following code example shows the CustomControl class, which inherits from 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);
  }
}

이 보기의 인스턴스에 추가할를 StackLayout 다음 코드 예제에서 설명한 것 처럼:An instance of this view is added to a StackLayout, as demonstrated in the following code example:

var brokenControl = new CustomControl {
  Text = "This control has incorrect sizing - it doesn't occupy the available width of the device."
};
stackLayout.Children.Add(brokenControl);

그러나 때문에 CustomControl.ArrangeOverride 재정의 요청 된 너비의 절반 항목을 항상 반환, 다음 스크린샷에 표시 된 대로 장치는 사용 가능한 너비의 절반 클리핑됩니다 보기:However, because the CustomControl.ArrangeOverride override always returns half of the requested width, the view will be clipped to half the available width of the device, as shown in the following screenshot:

이 문제에 솔루션을 제공 하는 것을 ArrangeOverrideDelegate 뷰를 추가 하는 경우 구현 합니다 StackLayout 다음 코드 예제에서 설명한 것 처럼:A solution to this problem is to provide an ArrangeOverrideDelegate implementation, when adding the view to the StackLayout, as demonstrated in the following code example:

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;
});

이 메서드는 제공한 너비는 CustomControl.ArrangeOverride 메서드 하지만 곱한 두 합니다.This method uses the width provided by the CustomControl.ArrangeOverride method, but multiplies it by two. 이 인해 되는 사용자 지정 보기에 올바르게 표시, 장치의 너비를 차지 하는 다음 스크린샷에 표시 된 대로:This results in the custom view being displayed correctly, occupying the width of the device, as shown in the following screenshot:

요약Summary

이 문서에서는 C#을 사용 하 여 만든 Xamarin.Forms 레이아웃에 네이티브 뷰를 추가 하는 방법 및 해당 측정 API 사용을 수정 하려면 사용자 지정 보기 레이아웃을 재정의 하는 방법을 설명 합니다.This article explained how to add native views to a Xamarin.Forms layout created using C#, and how to override the layout of custom views to correct their measurement API usage.