C#의 네이티브 뷰
iOS, Android 및 UWP의 네이티브 뷰는 C#을 사용하여 만든 페이지에서 직접 참조 Xamarin.Forms 할 수 있습니다. 이 문서에서는 C#을 사용하여 만든 레이아웃에 네이티브 뷰를 Xamarin.Forms 추가하는 방법과 측정 API 사용량을 수정하기 위해 사용자 지정 보기의 레이아웃을 재정의하는 방법을 보여 줍니다.
개요
설정할 수 Content
있거나 컬렉션이 있는 컨트롤 Xamarin.Forms 은 Children
플랫폼별 보기를 추가할 수 있습니다. 예를 들어 iOS UILabel
를 속성 또는 StackLayout.Children
컬렉션에 ContentView.Content
직접 추가할 수 있습니다. 그러나 이 기능을 사용하려면 공유 프로젝트 솔루션에서 Xamarin.Forms 정의를 사용해야 #if
하며 .NET Standard 라이브러리 솔루션에서는 Xamarin.Forms 사용할 수 없습니다.
다음 스크린샷은 플랫폼별 보기가 다음에 추가된 것을 보여 줍니다 Xamarin.FormsStackLayout
.
레이아웃에 플랫폼별 보기를 Xamarin.Forms 추가하는 기능은 각 플랫폼의 두 확장 메서드에 의해 활성화됩니다.
Add
– 레이아웃 컬렉션에Children
플랫폼별 보기를 추가합니다.ToView
– 플랫폼별 보기를 사용하여 컨트롤의 속성으로 Xamarin.FormsView
설정할 수 있는 뷰로Content
래핑합니다.
공유 프로젝트에서 이러한 메서드를 Xamarin.Forms 사용하려면 적절한 플랫폼별 Xamarin.Forms 네임스페이스를 가져와야 합니다.
- iOS – Xamarin.Forms.Platform.iOS
- Android – Xamarin.Forms.Platform.Android
- UWP(유니버설 Windows 플랫폼) – Xamarin.Forms.Platform.UWP
각 플랫폼에 플랫폼별 보기 추가
다음 섹션에서는 각 플랫폼의 레이아웃에 Xamarin.Forms 플랫폼별 보기를 추가하는 방법을 보여 줍니다.
iOS
다음 코드 예제에서는 a 및 ContentView
a UILabel
StackLayout
에 추가하는 방법을 보여 줍니다.
var uiLabel = new UILabel {
MinimumFontSize = 14f,
Lines = 0,
LineBreakMode = UILineBreakMode.WordWrap,
Text = originalText,
};
stackLayout.Children.Add (uiLabel);
contentView.Content = uiLabel.ToView();
이 예제에서는 인스턴스와 contentView
인스턴스가 stackLayout
이전에 XAML 또는 C#에서 만들어졌다고 가정합니다.
Android
다음 코드 예제에서는 a 및 ContentView
a TextView
StackLayout
에 추가하는 방법을 보여 줍니다.
var textView = new TextView (MainActivity.Instance) { Text = originalText, TextSize = 14 };
stackLayout.Children.Add (textView);
contentView.Content = textView.ToView();
이 예제에서는 인스턴스와 contentView
인스턴스가 stackLayout
이전에 XAML 또는 C#에서 만들어졌다고 가정합니다.
유니버설 Windows 플랫폼
다음 코드 예제에서는 a 및 ContentView
a TextBlock
StackLayout
에 추가하는 방법을 보여 줍니다.
var textBlock = new TextBlock
{
Text = originalText,
FontSize = 14,
FontFamily = new FontFamily("HelveticaNeue"),
TextWrapping = TextWrapping.Wrap
};
stackLayout.Children.Add(textBlock);
contentView.Content = textBlock.ToView();
이 예제에서는 인스턴스와 contentView
인스턴스가 stackLayout
이전에 XAML 또는 C#에서 만들어졌다고 가정합니다.
사용자 지정 보기에 대한 플랫폼 측정 재정의
각 플랫폼의 사용자 지정 보기는 디자인된 레이아웃 시나리오에 대한 측정값만 올바르게 구현하는 경우가 많습니다. 예를 들어 사용자 지정 보기는 디바이스의 사용 가능한 너비의 절반만 차지하도록 디자인되었을 수 있습니다. 그러나 다른 사용자와 공유된 후 사용자 지정 보기는 디바이스의 사용 가능한 전체 너비를 차지해야 할 수 있습니다. 따라서 레이아웃에서 다시 사용할 Xamarin.Forms 때 사용자 지정 뷰 측정 구현을 재정의해야 할 수 있습니다. 이러한 이유로 Add
확장 메서드는 ToView
측정 대리자를 지정할 수 있는 재정의를 제공하므로 레이아웃에 추가될 때 사용자 지정 보기 레이아웃을 재정의할 Xamarin.Forms 수 있습니다.
다음 섹션에서는 사용자 지정 보기의 레이아웃을 재정의하여 측정 API 사용량을 수정하는 방법을 보여 줍니다.
iOS
다음 코드 예제에서는 상속되는 클래스를 보여 CustomControl
줍니다.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
됩니다.
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을 반환하므로 다음 스크린샷과 같이 보기는 위와 아래에 빈 공간으로 표시됩니다.
이 문제에 대한 해결 방법은 다음 코드 예제에 설명된 대로 구현을 제공하는 GetDesiredSizeDelegate
것입니다.
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의 높이를 대체합니다. 인스턴스가 CustomControl
추가StackLayout
되면 메서드를 FixSize
클래스에서 제공하는 CustomControl
잘못된 측정값을 수정하기 위한 메서드로 GetDesiredSizeDelegate
지정할 수 있습니다.
stackLayout.Children.Add (customControl, FixSize);
이렇게 하면 다음 스크린샷과 같이 사용자 지정 보기가 위와 아래에 빈 공간 없이 올바르게 표시됩니다.
Android
다음 코드 예제에서는 상속되는 클래스를 보여 CustomControl
줍니다.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
됩니다.
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
항상 요청된 너비의 절반을 반환하므로 다음 스크린샷과 같이 디바이스의 사용 가능한 너비의 절반만 차지하는 보기가 표시됩니다.
이 문제에 대한 해결 방법은 다음 코드 예제에 설명된 대로 구현을 제공하는 GetDesiredSizeDelegate
것입니다.
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
사용하지만 2를 곱합니다. 인스턴스가 CustomControl
추가StackLayout
되면 메서드를 FixSize
클래스에서 제공하는 CustomControl
잘못된 측정값을 수정하기 위한 메서드로 GetDesiredSizeDelegate
지정할 수 있습니다.
stackLayout.Children.Add (customControl, FixSize);
그러면 다음 스크린샷과 같이 사용자 지정 보기가 디바이스 너비를 차지하여 올바르게 표시됩니다.
유니버설 Windows 플랫폼
다음 코드 예제에서는 상속되는 클래스를 보여 CustomControl
줍니다.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
됩니다.
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
항상 요청된 너비의 절반을 반환하므로 다음 스크린샷과 같이 보기가 디바이스의 사용 가능한 너비의 절반으로 잘립니다.
이 문제에 대한 해결 방법은 다음 코드 예제에 설명된 대로 뷰를 StackLayout
추가할 때 구현을 제공하는 ArrangeOverrideDelegate
것입니다.
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
사용하지만 2를 곱합니다. 그러면 다음 스크린샷과 같이 사용자 지정 보기가 디바이스 너비를 차지하여 올바르게 표시됩니다.
요약
이 문서에서는 C#을 사용하여 만든 레이아웃에 네이티브 뷰를 Xamarin.Forms 추가하는 방법과 사용자 지정 보기의 레이아웃을 재정의하여 측정 API 사용량을 수정하는 방법을 설명했습니다.