Xamarin表格在TabbedPage

时间:2020-09-30 18:17:40

标签: xaml xamarin xamarin.forms xamarin.android xamarin.ios

我有一个问题。我创建了以下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中的所有选项卡?

请让我知道我该怎么做!

3 个答案:

答案 0 :(得分:3)

免责声明

我想出了一种仅使用纯Xamarin.Forms即可创建所需效果的方法。阅读并注意解决方案的 棘手 部分。

摘要

此解决方案是通过实现AbsoluteLayoutCarouselViewIndicatorViewDataTemplateSelector来实现的。 Xamarin.Forms 4.8 如下所示。如果使用的是较低版本,请考虑到CarouselViewIndicatorView之类的功能可能处于 预览 状态。

DataTemplateSelectorCarouselViewIndicatorView用于模拟TabbedPage,而AbsoluteLayout用于提供 Overlay < / strong>

所以,现在有了解决方案:

创建视图

您在这里为所需的每个页面创建一个视图。在此示例中,我希望我的应用程序由两个页面组成,因此我创建了两个视图(后面的代码保持不变):

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

最终结果如下: enter image description here

答案 1 :(得分:1)

作为解决方法,您可以为每个 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>

答案 2 :(得分:0)

我建议创建一个包含BaseContentPage的{​​{1}}。这样,每个页面都可以从static FloatingButton继承并使用相同的BaseContentPage

代码

BaseContentPage

FloatingButton

示例LabelPage

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

示例ButtonPage

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

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

                Button
            }
        }
    }
}

示例应用

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

        Content = Button;
    }
}

示例应用

以下是用于创建附件GIF的示例应用程序: https://github.com/brminnick/TabbedPageButton/