如何在 android 布局视图中添加或替换页面

How to add or replace page in android layout view

我正在尝试使用 andoid 的 BottomNavigationView 在 Xamarin Forms 跨平台应用程序中制作类似 iOS 的选项卡式页面,方法是在 android 项目中制作平台特定的渲染器。基本上我在其中添加了一个带有 bottomnavigationview 的布局,并在渲染器中将此视图添加到根 activity,并根据表单选项卡式页面创建菜单项。现在的问题是如何将表单选项卡页面的当前页面 add/show 设置为 android 布局,并在单击栏项目时替换它。我发现即使我在渲染器中调用RemoveAllViews,标签页中的内容页也会占据整个屏幕,甚至会覆盖底栏。因此,如果选项卡页面的任何一个内容页面可见,它将占据整个屏幕。另外 android 的 AddView 方法只接受 android 视图,不接受表单视图。

BottomNav 布局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="@+id/rootLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorAccent"
android:layout_above="@+id/bottom_navigation"
android:orientation="vertical">
</FrameLayout>

<android.support.design.widget.BottomNavigationView
  android:id="@+id/bottom_navigation"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:layout_alignParentBottom="true"
  app:itemBackground="@color/colorPrimary"
  android:background="@color/colorPrimary"
  app:itemIconTint="@color/white"
  app:itemTextColor="@color/white"
  app:menu="@menu/bottom_navigation_main" />

</RelativeLayout>

渲染器 OnElementChanged:

        base.OnElementChanged(e);
        TabbedPage oe = e.OldElement;
        TabbedPage ne = e.NewElement;
        int id = 1000;
        foreach(Page p in ne.Children)
        {
            items.Add(new Item
            {
                text = p.Title,
                icon = p.Icon,
                page = p,
                id = id++,
            });
            p.IsVisible = false; // without this, page show full screen and covers the bottom bar
        }

        RemoveAllViews();
        Activity activity = this.Context as Activity;
        view = activity.LayoutInflater.Inflate(Resource.Layout.BottomNav, this, false);
        AddView(view);
        layout = view.FindViewById<FrameLayout>(Resource.Id.rootLayout);
        // add current page to layout, or replace layout with page? and How?
        //
        //

        BottomNavigationView bottomNavigationView = (BottomNavigationView)
            FindViewById(Resource.Id.bottom_navigation);
        bottomNavigationView.NavigationItemSelected += BottomNavigationView_NavigationItemSelected;

        Android.Support.V7.View.Menu.MenuBuilder menu = bottomNavigationView.Menu as Android.Support.V7.View.Menu.MenuBuilder;
        menu.Clear();

        foreach(Item i in items)
        {
            IMenuItem mi = menu.Add(0, i.id, 0, i.text);
            mi.SetIcon(Resource.Drawable.icon);
        }

编辑:添加更多代码和屏幕截图

我的预期布局是这样的,不显示来自XF tabbedpage的页面,红色的主要部分是id rootLayoutFrameLayout,目标是添加当前页面的tabbedpage 到 Framelayout 并显示它,而当单击 BottomNavigationView 中的项目时,切换 FrameLayout 以显示其他页面。但是这个屏幕只有通过以下方式使所有页面不可见才能实现:

        foreach (Page p in e.NewElement.Children)
        {
            p.IsVisible = false;
        }

如果不设置visible为false,子页面会占满整个屏幕:

我的测试 XF 标签页:

<?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:local="clr-namespace:BottomTabbed"
        x:Class="BottomTabbed.TabbedPage1"
        NavigationPage.HasNavigationBar="False">
      <ContentPage Title="Tab 1" BackgroundColor="Green" />
      <ContentPage Title="Tab 2" BackgroundColor="Blue"/>
      <ContentPage Title="Tab 3" BackgroundColor="Red"/>
      <ContentPage Title="Tab 4" BackgroundColor="Gray" />
</TabbedPage>

根据您的描述,我认为您根本不需要 TabbedPage,您只需要一个包含 BottomNavigationViewFrameLayout 的片段视图即可。然后你可以为此自定义一个ViewRenderer

首先,在PCL中创建View的子类,例如:

public class BottomTabbedView:View
{
}

然后在android客户端项目中实现它的渲染器:

[assembly:ExportRenderer(typeof(BottomTabbedView),typeof(BottomTabbedViewRenderer))]
namespace PackageNameSpace.Droid
{
    public class BottomTabbedViewRenderer:ViewRenderer
    {
        protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.View> e)
        {
            base.OnElementChanged(e);
            if (Control == null)
            {
                // Instantiate the native control and assign it to the Control property with
                // the SetNativeControl method
                var context = Xamarin.Forms.Forms.Context;
                LayoutInflater inflater = context.GetSystemService(Context.LayoutInflaterService) as LayoutInflater;
                var bottomnav_view = inflater.Inflate(Resource.Layout.bottomnav_view, this, false);
                var frame = bottomnav_view.FindViewById<FrameLayout>(Resource.Id.rootLayout);
                var navi = bottomnav_view.FindViewById<BottomNavigationView>(Resource.Id.bottom_navigation);
                SetNativeControl(bottomnav_view);
            }

            if (e.OldElement != null)
            {
                // Unsubscribe from event handlers and cleanup any resources
            }

            if (e.NewElement != null)
            {
                // Configure the control and subscribe to event handlers
            }
        }
    }
}

BottomNavigationViewFrameLayout的逻辑我这里没有全部写完,你应该可以实现这个ViewRenderer里面的逻辑。该代码应与 Xamarin.Android.

的代码类似

然后你可以在XF的ContentPage中使用这个视图作为一个普通的视图控件,例如:

<local:BottomTabbedView/>