简体   繁体   English

如何在xamarin表单中设置MasterDetailPage的宽度

[英]How to set width for MasterDetailPage in xamarin forms

I am using the MasterDetailPage for app on Xamarin forms for ios and android. 我在ios和android的Xamarin表单上使用MasterDetailPage for app。

however the width in MasterDetailPage menu is too large and i would like to adjust it. 但MasterDetailPage菜单中的宽度太大,我想调整它。

How i can Set custom width for MasterDetailPage on android and iOS? 我如何在Android和iOS上为MasterDetailPage设置自定义宽度?

My MasterDetailPage init code: 我的MasterDetailPage初始化代码:

            MyChatsMasterView _myChatsMasterView;
            MyChatsView _myChatsView;

            public MyChatsMasterDetailView(MyChatsMasterView myChatsMasterView, MyChatsView myChatsView)
            {
                NavigationPage.SetHasNavigationBar(this, false);

                InitializeComponent();
                this.MasterBehavior = MasterBehavior.Popover;

                _myChatsMasterView = myChatsMasterView;
                _myChatsView = myChatsView;

                Master = _myChatsMasterView;
                Detail = _myChatsView;

                _myChatsMasterView.SetDetailView(this);
            }

I solved the problem by copying the renderers from the Xamarin.Forms sources. 我通过从Xamarin.Forms源复制渲染器来解决问题。 Basically I needed a master with a width of 400 dp in order to display a calendar properly inside of it. 基本上我需要一个宽度为400 dp的母版,以便在其内部正确显示日历。

Here is what I did: 这是我做的:

Shared Library 共享库


I created a SplitViewPage, deriving from the MasterDetail Page: 我创建了一个SplitViewPage,派生自MasterDetail页面:

<?xml version="1.0" encoding="utf-8" ?>
<MasterDetailPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="CompApp.Views.SplitViewPage">
    <MasterDetailPage.Master>
        <ContentPage Title=" "/>
    </MasterDetailPage.Master>
    <MasterDetailPage.Detail>
        <ContentPage Title=" "/>
    </MasterDetailPage.Detail>
</MasterDetailPage>

Android Android的


Since the master width is a constant within the internal class 'MasterDetailContainer', I copied the code from the base class (see here ) to a new class named 'DroidMasterDetailContainer.cs' while changing the class visibility from internal to public. 由于主宽度是内部类'MasterDetailContainer'中的常量,因此我将代码从基类(参见此处 )复制到名为'DroidMasterDetailContainer.cs'的新类,同时将类可见性从内部更改为公共。

I made two changes to the code: 我对代码进行了两处更改:

  1. I changed const int DefaultMasterSize = 320 to const int DefaultMasterSize = 400 我将const int DefaultMasterSize = 320更改为const int DefaultMasterSize = 400
  2. I commented out the line _childView.ClearValue(Platform.RendererProperty); 我注释掉了_childView.ClearValue(Platform.RendererProperty); (line 116, which lies in void DisposeChildRenderers() since the Platform.RendererProperty is inaccessible (第116行,它位于void DisposeChildRenderers()因为Platform.RendererProperty无法访问

The next thing to do is to copy the Code of the MasterDetailRenderer (see here ) to a new class (in my case 'SplitViewPageRenderer.cs') 接下来要做的是将MasterDetailRenderer的代码(见这里 )复制到一个新类(在我的例子中是'SplitViewPageRenderer.cs')

using System;
using System.ComponentModel;
using System.Linq;
using System.Threading.Tasks;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Support.V4.Widget;
using Android.Views;
using MyApp.Droid.Renderer;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using Xamarin.Forms.Platform.Android.AppCompat;
using AColor = Android.Graphics.Drawables.ColorDrawable;

using AView = Android.Views.View;

[assembly: ExportRenderer(typeof(SplitViewPage), typeof(SplitViewPageRenderer))]
namespace MyApp.Droid.Renderer
{
public class SplitViewPageRenderer : DrawerLayout, IVisualElementRenderer, DrawerLayout.IDrawerListener
{
    public SplitViewPageRenderer(Context context) : base(context)
    {

    }

    //from Android source code
    const uint DefaultScrimColor = 0x99000000;
    int _currentLockMode = -1;
    DroidMasterDetailContainer _detailLayout;
    bool _isPresentingFromCore;
    DroidMasterDetailContainer _masterLayout;
    MasterDetailPage _page;
    bool _presented;

    [Obsolete("This constructor is obsolete as of version 2.5. Please use MasterDetailRenderer(Context) instead.")]
    public SplitViewPageRenderer() : base(Forms.Context)
    {
    }

    IMasterDetailPageController MasterDetailPageController => _page as IMasterDetailPageController;

    public bool Presented
    {
        get { return _presented; }
        set
        {
            if (value == _presented)
                return;
            UpdateSplitViewLayout();
            _presented = value;
            if (_page.MasterBehavior == MasterBehavior.Default && MasterDetailPageController.ShouldShowSplitMode)
                return;
            if (_presented)
                OpenDrawer(_masterLayout);
            else
                CloseDrawer(_masterLayout);
        }
    }

    IPageController MasterPageController => _page.Master as IPageController;
    IPageController DetailPageController => _page.Detail as IPageController;
    IPageController PageController => Element as IPageController;

    public void OnDrawerClosed(AView drawerView)
    {
    }

    public void OnDrawerOpened(AView drawerView)
    {
    }

    public void OnDrawerSlide(AView drawerView, float slideOffset)
    {
    }

    public void OnDrawerStateChanged(int newState)
    {
        _presented = IsDrawerVisible(_masterLayout);
        UpdateIsPresented();
    }

    public VisualElement Element
    {
        get { return _page; }
    }

    public event EventHandler<VisualElementChangedEventArgs> ElementChanged;

    event EventHandler<PropertyChangedEventArgs> ElementPropertyChanged;
    event EventHandler<PropertyChangedEventArgs> IVisualElementRenderer.ElementPropertyChanged
    {
        add { ElementPropertyChanged += value; }
        remove { ElementPropertyChanged -= value; }
    }

    public SizeRequest GetDesiredSize(int widthConstraint, int heightConstraint)
    {
        Measure(widthConstraint, heightConstraint);
        return new SizeRequest(new Size(MeasuredWidth, MeasuredHeight));
    }

    public void SetElement(VisualElement element)
    {
        MasterDetailPage oldElement = _page;
        _page = element as MasterDetailPage;

        _detailLayout = new DroidMasterDetailContainer(_page, false, Context) { LayoutParameters = new LayoutParams(ViewGroup.LayoutParams.WrapContent, ViewGroup.LayoutParams.WrapContent) };

        _masterLayout = new DroidMasterDetailContainer(_page, true, Context)
        {
            LayoutParameters = new LayoutParams(ViewGroup.LayoutParams.WrapContent, ViewGroup.LayoutParams.WrapContent) { Gravity = (int)GravityFlags.Start }
        };

        AddView(_detailLayout);

        AddView(_masterLayout);

        var activity = Context as Activity;
        activity.ActionBar.SetDisplayShowHomeEnabled(true);
        activity.ActionBar.SetHomeButtonEnabled(true);

        UpdateBackgroundColor(_page);
        UpdateBackgroundImage(_page);

        OnElementChanged(oldElement, element);

        if (oldElement != null)
            ((IMasterDetailPageController)oldElement).BackButtonPressed -= OnBackButtonPressed;

        if (_page != null)
            MasterDetailPageController.BackButtonPressed += OnBackButtonPressed;

        if (Tracker == null)
            Tracker = new VisualElementTracker(this);

        _page.PropertyChanged += HandlePropertyChanged;
        _page.Appearing += MasterDetailPageAppearing;
        _page.Disappearing += MasterDetailPageDisappearing;

        UpdateMaster();
        UpdateDetail();

        Device.Info.PropertyChanged += DeviceInfoPropertyChanged;
        SetGestureState();

        Presented = _page.IsPresented;

        AddDrawerListener(this);

        //if (element != null)
        //  element.SendViewInitialized(this);

        if (element != null && !string.IsNullOrEmpty(element.AutomationId))
            ContentDescription = element.AutomationId;
    }

    public VisualElementTracker Tracker { get; private set; }

    public void UpdateLayout()
    {
        if (Tracker != null)
            Tracker.UpdateLayout();
    }

    public ViewGroup ViewGroup => this;
    AView IVisualElementRenderer.View => this;

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            if (Tracker != null)
            {
                Tracker.Dispose();
                Tracker = null;
            }

            if (_detailLayout != null)
            {
                _detailLayout.Dispose();
                _detailLayout = null;
            }

            if (_masterLayout != null)
            {
                _masterLayout.Dispose();
                _masterLayout = null;
            }

            Device.Info.PropertyChanged -= DeviceInfoPropertyChanged;

            if (_page != null)
            {
                MasterDetailPageController.BackButtonPressed -= OnBackButtonPressed;
                _page.PropertyChanged -= HandlePropertyChanged;
                _page.Appearing -= MasterDetailPageAppearing;
                _page.Disappearing -= MasterDetailPageDisappearing;
                //_page.ClearValue(Platform.RendererProperty);
                _page = null;
            }
        }

        base.Dispose(disposing);
    }

    protected override void OnAttachedToWindow()
    {
        base.OnAttachedToWindow();
        PageController.SendAppearing();
    }

    protected override void OnDetachedFromWindow()
    {
        base.OnDetachedFromWindow();
        PageController.SendDisappearing();
    }

    protected virtual void OnElementChanged(VisualElement oldElement, VisualElement newElement)
    {
        EventHandler<VisualElementChangedEventArgs> changed = ElementChanged;
        if (changed != null)
            changed(this, new VisualElementChangedEventArgs(oldElement, newElement));
    }

    protected override void OnLayout(bool changed, int l, int t, int r, int b)
    {
        base.OnLayout(changed, l, t, r, b);
        //hack to make the split layout handle touches the full width
        if (MasterDetailPageController.ShouldShowSplitMode && _masterLayout != null)
            _masterLayout.Right = r;
    }

    async void DeviceInfoPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName == "CurrentOrientation")
        {
            if (!MasterDetailPageController.ShouldShowSplitMode && Presented)
            {
                MasterDetailPageController.CanChangeIsPresented = true;
                //hack : when the orientation changes and we try to close the Master on Android     
                //sometimes Android picks the width of the screen previous to the rotation      
                //this leaves a little of the master visible, the hack is to delay for 50ms closing the drawer
                await Task.Delay(50);
                CloseDrawer(_masterLayout);
            }
            UpdateSplitViewLayout();
        }
    }

    void HandleMasterPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        //if (e.PropertyName == Page.TitleProperty.PropertyName || e.PropertyName == Page.IconProperty.PropertyName)
            //((Platform)_page.Platform).UpdateMasterDetailToggle(true);
    }

    void HandlePropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        ElementPropertyChanged?.Invoke(this, e);
        if (e.PropertyName == "Master")
            UpdateMaster();
        else if (e.PropertyName == "Detail")
        {
            UpdateDetail();
            //((Platform)_page.Platform).UpdateActionBar();
        }
        else if (e.PropertyName == MasterDetailPage.IsPresentedProperty.PropertyName)
        {
            _isPresentingFromCore = true;
            Presented = _page.IsPresented;
            _isPresentingFromCore = false;
        }
        else if (e.PropertyName == "IsGestureEnabled")
            SetGestureState();
        else if (e.PropertyName == Page.BackgroundImageProperty.PropertyName)
            UpdateBackgroundImage(_page);
        if (e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName)
            UpdateBackgroundColor(_page);
    }

    void MasterDetailPageAppearing(object sender, EventArgs e)
    {
        MasterPageController?.SendAppearing();
        DetailPageController?.SendAppearing();
    }

    void MasterDetailPageDisappearing(object sender, EventArgs e)
    {
        MasterPageController?.SendDisappearing();
        DetailPageController?.SendDisappearing();
    }

    void OnBackButtonPressed(object sender, BackButtonPressedEventArgs backButtonPressedEventArgs)
    {
        if (IsDrawerOpen((int)GravityFlags.Start))
        {
            if (_currentLockMode != LockModeLockedOpen)
            {
                CloseDrawer((int)GravityFlags.Start);
                backButtonPressedEventArgs.Handled = true;
            }
        }
    }

    void SetGestureState()
    {
        SetDrawerLockMode(_page.IsGestureEnabled ? LockModeUnlocked : LockModeLockedClosed);
    }

    void IVisualElementRenderer.SetLabelFor(int? id)
    {
    }

    void SetLockMode(int lockMode)
    {
        if (_currentLockMode != lockMode)
        {
            SetDrawerLockMode(lockMode);
            _currentLockMode = lockMode;
        }
    }

    void UpdateBackgroundColor(Page view)
    {
        if (view.BackgroundColor != Color.Default)
            SetBackgroundColor(view.BackgroundColor.ToAndroid());
    }

    void UpdateBackgroundImage(Page view)
    {
        if (!string.IsNullOrEmpty(view.BackgroundImage))
            this.SetBackground(Context.GetDrawable(view.BackgroundImage));
    }

    void UpdateDetail()
    {
        Context.HideKeyboard(this);
        _detailLayout.ChildView = _page.Detail;
    }

    void UpdateIsPresented()
    {
        if (_isPresentingFromCore)
            return;
        if (Presented != _page.IsPresented)
            ((IElementController)_page).SetValueFromRenderer(MasterDetailPage.IsPresentedProperty, Presented);
    }

    void UpdateMaster()
    {
        if (_masterLayout != null && _masterLayout.ChildView != null)
            _masterLayout.ChildView.PropertyChanged -= HandleMasterPropertyChanged;
        _masterLayout.ChildView = _page.Master;
        if (_page.Master != null)
            _page.Master.PropertyChanged += HandleMasterPropertyChanged;
    }

    void UpdateSplitViewLayout()
    {
        if (Device.Idiom == TargetIdiom.Tablet)
        {
            bool isShowingSplit = MasterDetailPageController.ShouldShowSplitMode
                || (MasterDetailPageController.ShouldShowSplitMode && _page.MasterBehavior != MasterBehavior.Default && _page.IsPresented);
            SetLockMode(isShowingSplit ? LockModeLockedOpen : LockModeUnlocked);
            unchecked
            {
                SetScrimColor(isShowingSplit ? Color.Transparent.ToAndroid() : (int)DefaultScrimColor);
            }
            //((Platform)_page.Platform).UpdateMasterDetailToggle();
        }
    }
}
}

Notice, that instead of using the internal class 'MasterDetailContainer' for the variables _masterLayout and _detailLayout, we are using the 'DroidMasterDetailContainer' created earlier. 请注意,我们使用之前创建的'DroidMasterDetailContainer',而不是使用内部类'MasterDetailContainer'作为变量_masterLayout和_detailLayout。

iOS iOS版


Basically the same story: Take the MasterDetailRenderer Code (see here ), create your own class, paste the code and some adaptions later we have: 基本相同的故事:使用MasterDetailRenderer代码(请参阅此处 ),创建自己的类,粘贴代码以及稍后我们拥有的一些调整:

using CompApp.Customs;
using MyApp.iOS.Renderer;
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using System.ComponentModel;
using CoreGraphics;
using MyApp.Views;
using UIKit;
using Xamarin.Forms.Internals;
using System.Reflection;

[assembly: ExportRenderer(typeof(SplitViewPage), typeof(SplitViewPageRenderer))]
namespace MyApp.iOS.Renderer
{
public class SplitViewPageRenderer : UISplitViewController, IVisualElementRenderer, IEffectControlProvider
{
    UIViewController _detailController;

    bool _disposed;
    EventTracker _events;
    InnerDelegate _innerDelegate;
    public static nfloat MasterWidth = 400;
    EventedViewController _masterController;

    SplitViewPage _masterDetailPage;

    bool _masterVisible;

    VisualElementTracker _tracker;

    Page PageController => Element as Page;
    Element ElementController => Element as Element;

    protected SplitViewPage MasterDetailPage => _masterDetailPage ?? (_masterDetailPage = (SplitViewPage)Element);

    public VisualElement Element { get; private set; }

    public event EventHandler<VisualElementChangedEventArgs> ElementChanged;

    UIBarButtonItem PresentButton
    {
        get { return _innerDelegate == null ? null : _innerDelegate.PresentButton; }
    }

    public UIView NativeView
    {
        get { return View; }
    }

    protected virtual void OnElementChanged(VisualElementChangedEventArgs e)
    {
        if (e.OldElement != null)
            e.OldElement.PropertyChanged -= HandlePropertyChanged;

        if (e.NewElement != null)
        {
            e.NewElement.PropertyChanged += HandlePropertyChanged;
        }

        if (UIDevice.CurrentDevice.Orientation == UIDeviceOrientation.LandscapeLeft || UIDevice.CurrentDevice.Orientation == UIDeviceOrientation.LandscapeRight)
        {
            PreferredDisplayMode = UISplitViewControllerDisplayMode.AllVisible;
        }
        else if (UIDevice.CurrentDevice.Orientation == UIDeviceOrientation.Portrait || UIDevice.CurrentDevice.Orientation == UIDeviceOrientation.PortraitUpsideDown)
        {
            PreferredDisplayMode = UISplitViewControllerDisplayMode.PrimaryOverlay;
        }

        MasterWidth = 400;
        MasterDetailPage.Master.WidthRequest = 400;

        MasterDetailPage.UpdateMasterBehavior();

        var changed = ElementChanged;
        if (changed != null)
            changed(this, e);

        UpdateControllers();
    }

    public SizeRequest GetDesiredSize(double widthConstraint, double heightConstraint)
    {
        return NativeView.GetSizeRequest(widthConstraint, heightConstraint);
    }

    public void SetElement(VisualElement element)
    {
        var oldElement = Element;
        Element = element;

        ViewControllers = new[] { _masterController = new EventedViewController(), _detailController = new ChildViewController() };

        Delegate = _innerDelegate = new InnerDelegate(MasterDetailPage.MasterBehavior);
        Element.BackgroundColor = Color.Transparent;
        UpdateControllers();

        _masterController.WillAppear += MasterControllerWillAppear;
        _masterController.WillDisappear += MasterControllerWillDisappear;

        PresentsWithGesture = MasterDetailPage.IsGestureEnabled;

        OnElementChanged(new VisualElementChangedEventArgs(oldElement, element));

        EffectUtilities.RegisterEffectControlProvider(this, oldElement, element);

        if (element != null)
        {
            MethodInfo sendViewInitialized = typeof(Xamarin.Forms.Forms).GetMethod("SendViewInitialized", BindingFlags.Static | BindingFlags.NonPublic);
            sendViewInitialized?.Invoke(element, new object[] { element, NativeView });
        }
    }

    public void SetElementSize(Size size)
    {
        Element.Layout(new Rectangle(Element.X, Element.Width, size.Width, size.Height));
    }

    public UIViewController ViewController
    {
        get { return this; }
    }

    public override void ViewDidAppear(bool animated)
    {
        PageController.SendAppearing();
        base.ViewDidAppear(animated);
        ToggleMaster();
    }

    public override void ViewDidDisappear(bool animated)
    {
        base.ViewDidDisappear(animated);
        PageController?.SendDisappearing();
    }

    public override void ViewDidLayoutSubviews()
    {
        if (View.Subviews.Length < 2)
            return;

        var frameBounds = View.Bounds;
        var masterBounds = _masterController.View.Frame;
        var detailsBounds = _detailController.View.Frame;

        nfloat statusBarHeight = UIApplication.SharedApplication.StatusBarFrame.Height;
        masterBounds.Width = 400;
        MasterWidth = (nfloat)Math.Max(MasterWidth, masterBounds.Width);
        if (Xamarin.Forms.Device.Idiom == TargetIdiom.Tablet)
        {
            bool interfaceInLandscape = UIApplication.SharedApplication.StatusBarOrientation == UIInterfaceOrientation.LandscapeLeft || UIApplication.SharedApplication.StatusBarOrientation == UIInterfaceOrientation.LandscapeRight;
            if (UIDevice.CurrentDevice.Orientation == UIDeviceOrientation.LandscapeLeft || UIDevice.CurrentDevice.Orientation == UIDeviceOrientation.LandscapeRight || interfaceInLandscape)
            {
                detailsBounds.X = 400;
                detailsBounds.Width = frameBounds.Width - 400;
            }
            else
            {
                detailsBounds.X = 0;
                detailsBounds.Width = frameBounds.Width;
            }
            _detailController.View.Frame = detailsBounds;
            _masterController.View.Frame = new CGRect(masterBounds.X, masterBounds.Y, masterBounds.Width, masterBounds.Height);
            if (!masterBounds.IsEmpty)
            {
                MasterDetailPage.MasterBounds = new Rectangle(masterBounds.X, masterBounds.Y, masterBounds.Width, masterBounds.Height);
            }

            if (!detailsBounds.IsEmpty)
            {
                MasterDetailPage.DetailBounds = new Rectangle(detailsBounds.X, detailsBounds.Y, detailsBounds.Width, detailsBounds.Height);
            }
            _masterController.View.SetNeedsLayout();
            _detailController.View.SetNeedsLayout();

        }
        else
        {
            if (!masterBounds.IsEmpty)
            {
                MasterDetailPage.MasterBounds = new Rectangle(MasterWidth, 0, MasterWidth, masterBounds.Height);
            }

            if (!detailsBounds.IsEmpty)
            {
                MasterDetailPage.DetailBounds = new Rectangle(0, 0, detailsBounds.Width, detailsBounds.Height);
            }
        }


    }

    public override void ViewDidLoad()
    {
        base.ViewDidLoad();
        UpdateBackground();
        UpdateFlowDirection();
        _tracker = new VisualElementTracker(this);
        _events = new EventTracker(this);
        _events.LoadEvents(NativeView);
    }

    public override void ViewWillDisappear(bool animated)
    {
        if (_masterVisible)
            PerformButtonSelector();

        base.ViewWillDisappear(animated);
    }

    public override void ViewWillLayoutSubviews()
    {
        base.ViewWillLayoutSubviews();
        _masterController.View.BackgroundColor = UIColor.White;
        CGRect bounds = _masterController.View.Bounds;
        CGRect frame = _masterController.View.Frame;
        (this.ViewController as UISplitViewController).MinimumPrimaryColumnWidth = 400;
        (this.ViewController as UISplitViewController).MaximumPrimaryColumnWidth = 400;
    }

    public override void WillRotate(UIInterfaceOrientation toInterfaceOrientation, double duration)
    {
        // On IOS8 the MasterViewController ViewAppear/Disappear weren't being called correctly after rotation 
        // We now close the Master by using the new SplitView API, basicly we set it to hidden and right back to the Normal/AutomaticMode
        if (!MasterDetailPage.ShouldShowSplitMode && _masterVisible)
        {
            MasterDetailPage.CanChangeIsPresented = true;
            PreferredDisplayMode = UISplitViewControllerDisplayMode.PrimaryHidden;
            PreferredDisplayMode = UISplitViewControllerDisplayMode.Automatic;
        }

        var masterBounds = _masterController.View.Frame;
        MessagingCenter.Send<IVisualElementRenderer>(this,  "Xamarin.UpdateToolbarButtons");

        MasterDetailPage.UpdateMasterBehavior();
        base.WillRotate(toInterfaceOrientation, duration);
    }

    public override void DidRotate(UIInterfaceOrientation fromInterfaceOrientation)
    {
        base.DidRotate(fromInterfaceOrientation);
        var masterBounds = _masterController.View.Frame;

        MasterWidth = (nfloat)Math.Max(MasterWidth, masterBounds.Width);

        if (!masterBounds.IsEmpty)
        {
            MasterDetailPage.MasterBounds = new Rectangle(MasterWidth, 0, MasterWidth, masterBounds.Height);
        }
    }

    public override UIViewController ChildViewControllerForStatusBarHidden()
    {
        if (((MasterDetailPage)Element).Detail != null)
            return (UIViewController)Platform.GetRenderer(((MasterDetailPage)Element).Detail);
        else
            return base.ChildViewControllerForStatusBarHidden();
    }

    void ClearControllers()
    {
        foreach (var controller in _masterController.ChildViewControllers)
        {
            controller.View.RemoveFromSuperview();
            controller.RemoveFromParentViewController();
        }

        foreach (var controller in _detailController.ChildViewControllers)
        {
            controller.View.RemoveFromSuperview();
            controller.RemoveFromParentViewController();
        }
    }

    void HandleMasterPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName == Page.IconProperty.PropertyName || e.PropertyName == Page.TitleProperty.PropertyName)
            MessagingCenter.Send<IVisualElementRenderer>(this, "Xamarin.UpdateToolbarButtons");
    }

    void HandlePropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (_tracker == null)
            return;

        if (e.PropertyName == "Master" || e.PropertyName == "Detail")
            UpdateControllers();
        else if (e.PropertyName == Xamarin.Forms.MasterDetailPage.IsPresentedProperty.PropertyName)
            ToggleMaster();
        else if (e.PropertyName == Xamarin.Forms.MasterDetailPage.IsGestureEnabledProperty.PropertyName)
            base.PresentsWithGesture = this.MasterDetailPage.IsGestureEnabled;
        else if (e.PropertyName == "FlowDirection")
            UpdateFlowDirection();
        MessagingCenter.Send<IVisualElementRenderer>(this, "Xamarin.UpdateToolbarButtons");
    }

    void MasterControllerWillAppear(object sender, EventArgs e)
    {
        _masterVisible = true;
        if (MasterDetailPage.CanChangeIsPresented)
            ElementController.SetValueFromRenderer(Xamarin.Forms.MasterDetailPage.IsPresentedProperty, true);
    }

    void MasterControllerWillDisappear(object sender, EventArgs e)
    {
        _masterVisible = false;
        if (MasterDetailPage.CanChangeIsPresented)
            ElementController.SetValueFromRenderer(Xamarin.Forms.MasterDetailPage.IsPresentedProperty, false);
    }

    void PerformButtonSelector()
    {
        DisplayModeButtonItem.Target.PerformSelector(DisplayModeButtonItem.Action, DisplayModeButtonItem, 0);
    }

    void ToggleMaster()
    {
        if (_masterVisible == MasterDetailPage.IsPresented || MasterDetailPage.ShouldShowSplitMode)
            return;

        PerformButtonSelector();
    }

    void UpdateBackground()
    {
        if (!string.IsNullOrEmpty(((Page)Element).BackgroundImage))
            View.BackgroundColor = UIColor.FromPatternImage(UIImage.FromBundle(((Page)Element).BackgroundImage));
        else if (Element.BackgroundColor == Color.Default)
            View.BackgroundColor = UIColor.White;
        else
            View.BackgroundColor = Element.BackgroundColor.ToUIColor();
    }

    void UpdateControllers()
    {
        MasterDetailPage.Master.PropertyChanged -= HandleMasterPropertyChanged;

        if (Platform.GetRenderer(MasterDetailPage.Master) == null)
            Platform.SetRenderer(MasterDetailPage.Master, Platform.CreateRenderer(MasterDetailPage.Master));
        if (Platform.GetRenderer(MasterDetailPage.Detail) == null)
            Platform.SetRenderer(MasterDetailPage.Detail, Platform.CreateRenderer(MasterDetailPage.Detail));

        ClearControllers();

        MasterDetailPage.Master.PropertyChanged += HandleMasterPropertyChanged;

        var master = Platform.GetRenderer(MasterDetailPage.Master).ViewController;
        var detail = Platform.GetRenderer(MasterDetailPage.Detail).ViewController;

        _masterController.View.AddSubview(master.View);
        _masterController.AddChildViewController(master);

        _detailController.View.AddSubview(detail.View);
        _detailController.AddChildViewController(detail);
    }

    void UpdateFlowDirection()
    {
        bool ios9orLater = UIDevice.CurrentDevice.CheckSystemVersion(9, 0);

        if (NativeView == null || View == null || !ios9orLater)
            return;
        View.SemanticContentAttribute = UISemanticContentAttribute.ForceLeftToRight;
    }

    class InnerDelegate : UISplitViewControllerDelegate
    {
        readonly MasterBehavior _masterPresentedDefaultState;

        public InnerDelegate(MasterBehavior masterPresentedDefaultState)
        {
            _masterPresentedDefaultState = masterPresentedDefaultState;
        }

        public UIBarButtonItem PresentButton { get; set; }

        public override bool ShouldHideViewController(UISplitViewController svc, UIViewController viewController, UIInterfaceOrientation inOrientation)
        {
            bool willHideViewController;
            switch (_masterPresentedDefaultState)
            {
                case MasterBehavior.Split:
                    willHideViewController = false;
                    break;
                case MasterBehavior.Popover:
                    willHideViewController = true;
                    break;
                case MasterBehavior.SplitOnPortrait:
                    willHideViewController = !(inOrientation == UIInterfaceOrientation.Portrait || inOrientation == UIInterfaceOrientation.PortraitUpsideDown);
                    break;
                default:
                    willHideViewController = inOrientation == UIInterfaceOrientation.Portrait || inOrientation == UIInterfaceOrientation.PortraitUpsideDown;
                    break;
            }
            return willHideViewController;
        }

        public override void WillHideViewController(UISplitViewController svc, UIViewController aViewController, UIBarButtonItem barButtonItem, UIPopoverController pc)
        {
            PresentButton = barButtonItem;
        }
    }

    void IEffectControlProvider.RegisterEffect(Effect effect)
    {
        VisualElementRenderer<VisualElement>.RegisterEffect(effect, View);
    }

    protected override void Dispose(bool disposing)
    {
        if (_disposed)
        {
            return;
        }

        _disposed = true;

        if (disposing)
        {
            if (Element != null)
            {
                PageController.SendDisappearing();
                Element.PropertyChanged -= HandlePropertyChanged;

                if (MasterDetailPage?.Master != null)
                {
                    MasterDetailPage.Master.PropertyChanged -= HandleMasterPropertyChanged;
                }

                Element = null;
            }

            if (_tracker != null)
            {
                _tracker.Dispose();
                _tracker = null;
            }

            if (_events != null)
            {
                _events.Dispose();
                _events = null;
            }

            if (_masterController != null)
            {
                _masterController.WillAppear -= MasterControllerWillAppear;
                _masterController.WillDisappear -= MasterControllerWillDisappear;
            }

            ClearControllers();
        }

        base.Dispose(disposing);
    }
}

internal class ChildViewController : UIViewController
{
    public override void ViewDidLayoutSubviews()
    {
        foreach (var vc in ChildViewControllers)
        {
            CGRect rect = View.Bounds;
            vc.View.Frame = rect;
        }
    }
}

internal class EventedViewController : ChildViewController
{
    public override void ViewWillAppear(bool animated)
    {
        base.ViewWillAppear(animated);

        var eh = WillAppear;
        if (eh != null)
            eh(this, EventArgs.Empty);
    }

    public override void ViewWillDisappear(bool animated)
    {
        base.ViewWillDisappear(animated);

        var eh = WillDisappear;
        if (eh != null)
            eh(this, EventArgs.Empty);
    }

    public override void ViewDidLayoutSubviews()
    {
        CGRect rect = View.Bounds;
        View.Bounds = rect;

        foreach (var vc in ChildViewControllers)
        {
            rect = vc.View.Frame;
            vc.View.Frame = rect;

            rect = vc.View.Bounds;
            vc.View.Bounds = rect;

        }
    }

    public event EventHandler WillAppear;

    public event EventHandler WillDisappear;
}
}

I only used the TabletMasterDetailRenderer, since I used the MasterDetailView to create a particular View for tablet devices containing a calendar view inside the master and displaying the details of the selected entry inside the detail view. 我只使用了TabletMasterDetailRenderer,因为我使用MasterDetailView为包含主控内部日历视图的平板电脑设备创建特定视图,并在详细视图中显示所选条目的详细信息。

If you need it for phones, the same changes made using the PhoneMasterDetailRenderer should work as well. 如果您需要它用于手机,使用PhoneMasterDetailRenderer进行的相同更改也应该有效。

我们目前无法调整MasterDetailPage 详细信息的宽度

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM