TabbedPage의 Xamarin 양식 추가 단추

Sep 30 2020

질문이 있습니다. 다음 TabbedPage를 만들었습니다.

<?xml version="1.0" encoding="utf-8" ?>
<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
            xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
            xmlns:d="http://xamarin.com/schemas/2014/forms/design"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:views="clr-namespace:MyApp.Views"
            mc:Ignorable="d"
            x:Class="MyApp.Views.MainPage"
            xmlns:android="clr-namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core"
            android:TabbedPage.ToolbarPlacement="Bottom"
            BarBackgroundColor="White"
            BarTextColor="Black"
            android:TabbedPage.BarItemColor="#B2B2B2"
            android:TabbedPage.BarSelectedItemColor="#56D7A5"
            android:TabbedPage.IsSwipePagingEnabled="False">    

    <TabbedPage.Children>
        <NavigationPage Title="page1" IconImageSource="navbar_page1">
            <x:Arguments>
                <views:page1 NavigationPage.HasNavigationBar="False" />
            </x:Arguments>
        </NavigationPage>

        <NavigationPage Title="page2" IconImageSource="navbar_page2">
            <x:Arguments>
                <views:page2 NavigationPage.HasNavigationBar="False" />
            </x:Arguments>
        </NavigationPage>

        <NavigationPage Title="page3" IconImageSource="navbar_page3">
            <x:Arguments>
                <views:page3 NavigationPage.HasNavigationBar="False" />
            </x:Arguments>
        </NavigationPage>
    
</TabbedPage>

이제 모든 페이지에서이 사용자 정의 FabMenu를 다음과 같이 추가했습니다.

<c:FloatingMenu Margin="0, 0, 10, 10" BGColor="#56D7A5" OpenIcon="openFab_icon" CloseIcon="closeFab_icon"
                AbsoluteLayout.LayoutBounds=".95,.95" AbsoluteLayout.LayoutFlags="PositionProportional">
    <c:FloatingButton x:Name="btnAddHomework" BGColor="#59E1FF" IconSrc="add_homework_icon" OnClickCommand="{Binding btnAddHomeworkCommand}" />
    <c:FloatingButton x:Name="btnAddDeadline" BGColor="#0FF1A0" IconSrc="add_deadline_icon"/>
    <c:FloatingButton x:Name="btnAddTest" BGColor="#5988FF" IconSrc="add_test_icon"/>
</c:FloatingMenu>

문제는 모든 페이지에 자체 FabMenu가 있으므로 모든 페이지에 사라졌다가 다시 나타나는 것을 볼 수 있다는 것입니다. 그래서 내 질문은 다음과 같습니다. TabbedPage의 모든 탭을 오버레이하는 일종의 루트 뷰가 있습니까?

어떻게하는지 알려주세요!

답변

2 Deczaloth Oct 07 2020 at 10:29

부인 성명

순수한 Xamarin.Forms 만 사용하여 원하는 효과를 만드는 방법을 생각해 냈습니다. 함께 읽고 솔루션 의 까다로운 부분에 주의를 기울이십시오 .

요약

이 솔루션은 구현 달성 AbsoluteLayout, CarouselView, IndicatorView와 DataTemplateSelector. Xamarin.Forms 4.8 은 다음과 같습니다. 더 낮은 버전을 사용하는 경우 미리보기 상태 와 같 CarouselView거나 IndicatorView있을 수있는 기능을 고려하세요 .

DataTemplateSelector, CarouselView및 IndicatorView을 시뮬레이션하기 위해 사용되는 TabbedPage, 그리고 AbsoluteLayout제공하는데 사용된다 오버레이 .

이제 솔루션으로 :

보기 만들기

여기에서 원하는 각 페이지에 대한보기를 만듭니다. 이 예에서는 애플리케이션이 두 페이지로 구성되기를 원하므로 두 개의 뷰를 생성합니다 (코드 숨김은 그대로 유지됨).

View1.xaml

<ContentView xmlns="http://xamarin.com/schemas/2014/forms" 
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="overlayTest.View1"
             BackgroundColor="Black">
  <ContentView.Content>
      <StackLayout>
            <Label Text="Welcome to Xamarin.Forms 1!"
                   TextColor="White"
                VerticalOptions="CenterAndExpand" 
                HorizontalOptions="CenterAndExpand" />
        </StackLayout>
  </ContentView.Content>
</ContentView>

View2.xaml

<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms" 
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="overlayTest.View2">
  <ContentView.Content>
      <StackLayout>
            <Label Text="Welcome to Xamarin.Forms 2!"
                VerticalOptions="CenterAndExpand" 
                HorizontalOptions="CenterAndExpand" />
        </StackLayout>
  </ContentView.Content>
</ContentView>

만들기 DataTemplateSelector

CarouselView현재에 따라 하나 또는 다른보기를 선택하기 위해에서 사용됩니다 Position.

using System;
using Xamarin.Forms;

namespace overlayTest
{
    class MyTemplateSelector : DataTemplateSelector
    {

        readonly DataTemplate view1, view2;

        public MyTemplateSelector()
        {
            view1 = new DataTemplate(typeof(View1));
            view2 = new DataTemplate(typeof(View2));
        }

        protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
        {
            String s = item.ToString();
            if(s == "1")
            {
                return view1;
            }
            
            return view2;
        }
    }
}

메인 페이지 만들기

Page1.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:t="clr-namespace:overlayTest"
             x:Class="overlayTest.Page1">
    <ContentPage.Resources>
        <ResourceDictionary>
            <t:MyTemplateSelector x:Key="templateSelector"/>
        </ResourceDictionary>
    </ContentPage.Resources>
    <ContentPage.Content>
        <AbsoluteLayout>
            <StackLayout AbsoluteLayout.LayoutBounds="0,0,1,1"
                     AbsoluteLayout.LayoutFlags="All"
                     Padding="0"
                     Spacing="0">
                <CarouselView ItemTemplate="{StaticResource templateSelector}"
                          IndicatorView="indicatorView">
                    <CarouselView.ItemsSource>
                        <x:Array Type="{x:Type x:String}">
                            <x:String>1</x:String>
                            <x:String>2</x:String>
                        </x:Array>
                    </CarouselView.ItemsSource>
                </CarouselView>

                <IndicatorView x:Name="indicatorView">
                    <IndicatorView.IndicatorTemplate>
                        <DataTemplate>
                            <StackLayout HorizontalOptions="FillAndExpand">
                                <Frame Margin="10">
                                    <Label/>
                                </Frame>
                            </StackLayout>
                        </DataTemplate>
                    </IndicatorView.IndicatorTemplate>
                </IndicatorView>

            </StackLayout>

            <ContentView 
                     IsVisible="True" VerticalOptions="Start"
                     AbsoluteLayout.LayoutBounds="0,0,1,1"
                     AbsoluteLayout.LayoutFlags="All"
                     BackgroundColor="Transparent">
                <Frame CornerRadius="10"
                   Margin="20"
                   VerticalOptions="StartAndExpand"
                   HorizontalOptions="CenterAndExpand" InputTransparent="False">
                    <StackLayout Padding="0">
                        <Label 
                           FontSize="Medium"
                           TextColor="Black"/>

                        <StackLayout Orientation="Horizontal"
                                 HorizontalOptions="CenterAndExpand">
                            <Label Text="I am floating here"/>
                            <Switch IsToggled="True" />
                        </StackLayout>


                        <Button Text="Save"
                               BackgroundColor="Accent"/>
                    </StackLayout>
                </Frame>
            </ContentView>
        </AbsoluteLayout>
    </ContentPage.Content>
</ContentPage>

그리고 뒤에있는 코드에서 탭의 이름을 설정했습니다. 여기에 내가 StackLayout-> Frame-> 의 요소 트리를 가정하고 있다는 사실에 주목하십시오 Label. 를 변경 IndicatorTemplate하면 코드의이 부분도 수정해야합니다!

Page1.xaml.cs

using System.Linq;

using Xamarin.Forms;
using Xamarin.Forms.Xaml;

namespace overlayTest
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class Page1 : ContentPage
    {
        public Page1()
        {
            
            InitializeComponent();

            indicatorView.PropertyChanged += (s, a) =>
            {
                if (a.PropertyName == IndicatorView.HeightProperty.PropertyName)
                {
                    var indicators = indicatorView.IndicatorLayout.Children.ToList();

                    int counter = 0;

                    foreach(var indicator in indicators)
                    {
                        var indicatorBaseStack = (StackLayout)indicator;
                        var indicatorFrame = (Frame)indicatorBaseStack.Children[0];
                        var indicatorFrameLabel = (Label)indicatorFrame.Content;

                        indicatorFrameLabel.Text = counter == 0 ? "View1" : "View2";
                        counter++;
                    }
                }
            };

        }
    }

}

마지막으로 해당 페이지를 App의 MainPage 속성으로 설정합니다.

public App()
{
    InitializeComponent();

    MainPage = new Page1();
}

최종 결과는 다음과 같습니다.

LucasZhang-MSFT Oct 01 2020 at 02:05

해결 방법 으로 각 ContentPage의 ToolbarItem 을 설정할 수 있습니다 (또는 기본 ContentPage를 정의 할 수 있음).

<ContentPage.ToolbarItems>
    <ToolbarItem Text="Example Item"
             IconImageSource="xxx.png"
             Order="Secondary"
             Clicked="{Binding xx}"
             Priority="0" />

    <ToolbarItem Text="Example Item"
             IconImageSource="xxx.png"
             Order="Secondary"
             Priority="1" />

    <ToolbarItem Text="Example Item"
             IconImageSource="xxx.png"
             Order="Secondary"
             Priority="2" />

</ContentPage.ToolbarItems>
BrandonMinnick Oct 06 2020 at 17:24

내가 만드는 것이 좋습니다 BaseContentPage를 포함를 static FloatingButton. 이렇게하면 모든 페이지가 BaseContentPage동일한 FloatingButton.

암호

BaseContentPage

abstract class BaseContentPage : ContentPage
{
    protected static Button Button { get; } = new Button { Text = $"This button was created at {DateTimeOffset.UtcNow}" }.Invoke(button => button.Clicked += HandleButtonClicked);

    static async void HandleButtonClicked(object sender, EventArgs e) =>
        await Application.Current.MainPage.DisplayAlert("Button Clicked", "This is the same button on both pages", "OK");
}

LabelPage 예

class LabelPage : BaseButtonPage
{
    public LabelPage()
    {
        Title = "LabelPage";

        Content = new StackLayout
        {
            Children =
            {
                new Label { Text = "Label Page" }.TextCenter().Center(),

                Button
            }
        }
    }
}

ButtonPage 예

class ButtonPage : BaseButtonPage
{
    public ButtonPage()
    {
        Title = "ButtonPage";

        Content = Button;
    }
}

예제 앱

public class App : Application
{
    public App()
    {
        Device.SetFlags(new[] { "Markup_Experimental" });

        MainPage = new TabbedPage
        {
            Children =
            {
                new ButtonPage(),
                new LabelPage()
            }
        };
    }
}

샘플 앱

다음은 첨부 된 GIF를 만드는 데 사용되는 샘플 앱입니다. https://github.com/brminnick/TabbedPageButton/