View 안에 View 를 주입할 수 있는 View 를 작성해보자
View 안에 여러 View 를 주입하고 속성에 따라 교체하는 ContainerView 를 구현하거나, NavigationBar 의 크기와 모양만 잡아두고 Button 을 추가하는 등 활용하는 방법이 많으니 알아두시면 유용합니다.
예제 코드 ContainerView
// ContentView.Content 를 Views 속성으로 연결하는 Attribute
[ContentProperty(nameof(Views))]
public class ContainerView : ContentView
{
// 주입된 View 를 배치하는게 사용할 Layout
private StackLayout _layout;
// 외부에서 주입할 View 를 저장할 자료구조
public ObservableCollection<View> Views { get; set; }
public ContainerView()
{
_layout = new StackLayout();
Views = new ObservableCollection<View>();
Views.CollectionChanged += OnViewsCollectionChanged;
// ContentView.Contnet 에 할당한 View 만 화면에 표시된다.
Content = _layout;
}
// ContainerView 에 View 가 추가되거나 제거될 때 대응하기 위한 메서드
private void OnViewsCollectionChanged((object sender, NotifyCollectionChangedEventArgs e)
{
if (e.OldItems != null)
{
foreach(View view in e.OldItems)
_layuout.Children.Remove(view);
}
if (e.NewItems != null)
{
foreach(View view in e.NewItems)
_layuout.Children.Add(view);
}
}
}
ContainerView 활용하는 방법
ContainerView
를 XAML 에서 다음과 같이 활용할 수 있습니다.
<local:ContainerView>
<Label Text="A" />
<Label Text="B" />
<Label Text="C" />
<!-- Views -->
</local:ContainerView>
ContainerView
태그 안에 정의한 Label
들은 [ContentProperty(nameof(Views))]
로 인해서 ContainerView.Views
에 추가됩니다. 그리고 Views
에 Label
이 추가될 때마다 CollectionChanged
이벤트가 발생하게 되고, 이벤트를 구독한 OnViewsCollectionChanged
메서드가 실행되면서 ContainerView._layout
에 Label
을 추가하게 됩니다. 만약 [ContentProperty(nameof(Views))]
를 지정하지 않으면 ContentView.Content
에 Label
이 추가되니 주의바랍니다. 만약 [ContentProperty(nameof(Views))]
를 사용하지 않고 View 를 추가하려면 아래와 같이 바꿔주면 됩니다.
<local:ContainerView>
<local:ContainerView.Views>
<Label Text="A" />
<Label Text="B" />
<Label Text="C" />
<!-- Views -->
</local:ContainerView.Views>
</local:ContainerView>
ContainerView 확장
만약 ContainerView
를 다채롭게 사용하고 싶다면 다음과 같이 개선해서 사용할 수도 있습니다.
public class ContainerView : ContentView
{
private StackLayout _layout;
private StackLayout _aTypesLayout;
private StackLayout _bTypesLayout;
private Label _title;
public Label Title
{
get => _title;
set
{
_title = value;
_layout.Children.RemoveAt(0);
_layout.Children.Insert(0, _title);
}
}
public ObservableCollection<ViewA> ATypes { get; set; }
public ObservableCollection<ViewB> BTypes { get; set; }
public ContainerView()
{
_title = new Label { Text = "Title" };'
_aTypesLayout = new StackLayout();
ATypes = new ObservableCollection<View>();
ATypes.CollectionChanged += OnViewsCollectionChanged;
_bTypesLayout = new StackLayout();
BTypes = new ObservableCollection<View>();
BTypes.CollectionChanged += OnViewsCollectionChanged;
_layout = new StackLayout
{
Children = { _title, _aTypesLayout, _bTypesLayout },
}
Content = _layout;
}
private void OnViewsCollectionChanged((object sender, NotifyCollectionChangedEventArgs e)
{
if (e.OldItems != null)
{
foreach(View view in e.OldItems)
_layuout.Children.Remove(view);
}
if (e.NewItems != null)
{
foreach(View view in e.NewItems)
_layuout.Children.Add(view);
}
}
}
확장한 ContainerView
는 아래와 같이 사용할 수 있습니다.
<local:ContainerView>
<local:ContainerView.Title>
<Label Text="Custom" />
</local:ContainerView.Title>
<local:ContainerView.ATypes>
<ViewA Value="A1" />
<ViewA Value="A2" />
<ViewA Value="A3" />
</local:ContainerView.ATypes>
<local:ContainerView.BTypes>
<ViewB Value="B1" />
<ViewB Value="B2" />
<ViewB Value="B3" />
</local:ContainerView.BTypes>
</local:ContainerView>
주의해야 부분은
ContentView
를 상속받아서 확장했기 때문에local:ContainerView.Content
에 새로운 View 를 할당하게 되면 다른 View 들이 화면에 보이지 않게 됩니다. 따라서 Content 로 사용할 만큼 기본이 되는 View 를ContentProperty
로 지정해놓길 권장드립니다.
'Develop > MAUI 가이드' 카테고리의 다른 글
[Xamarin] iOS SafeArea 자연스럽게 반영해주는 CustomEffect (0) | 2021.03.26 |
---|---|
[Xamarin] Renderer 를 만들었더니 BackgroundColor 가 적용되지 않을 때 해결하는 방법 (0) | 2021.03.25 |
[Xamarin] BindableProperty 를 Override 해보자 (0) | 2020.12.24 |
[Xamarin] Item 이 Layout 에 따라 자동으로 배치되도록 해보자 (0) | 2020.12.24 |
[Xamarin] 화면 크기에 따라 변화하는 ResponsiveLayout 을 만들어 보자 (0) | 2020.12.23 |
꾸준히 노력하는 개발자 "김예건" 입니다.