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

时间:2016-11-03 11:09:21

标签: c# android ios xamarin xamarin.forms

我在ios和android的Xamarin表单上使用MasterDetailPage for app。

然而,MasterDetailPage菜单中的宽度太大,我想调整它。

我如何在Android和iOS上为MasterDetailPage设置自定义宽度?

我的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);
            }

2 个答案:

答案 0 :(得分:3)

我通过从Xamarin.Forms源复制渲染器来解决问题。 基本上我需要一个宽度为400 dp的母版才能在其内部正确显示日历。

这是我做的:

共享资料库

我创建了一个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

由于主宽度是内部类&#39; MasterDetailContainer&#39;中的常量,我从基类复制了代码(参见here) 到一个名为“DroidMasterDetailContainer.cs”的新班级。同时将班级可见性从内部更改为公开。

我对代码进行了两处更改:

  1. 我将const int DefaultMasterSize = 320更改为const int DefaultMasterSize = 400
  2. 我注释掉了行_childView.ClearValue(Platform.RendererProperty);(第116行,因为Platform.RendererProperty无法访问,所以位于void DisposeChildRenderers()
  3. 接下来要做的是将MasterDetailRenderer的代码(请参阅here)复制到一个新类(在我的情况下&#39; SplitViewPageRenderer.cs&#39;)

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

    请注意,不是使用内部类&#39; MasterDetailContainer&#39;对于变量_masterLayout和_detailLayout,我们正在使用&#39; DroidMasterDetailContainer&#39;早些时候创建。

    <强>的iOS

    基本相同的故事:采用MasterDetailRenderer代码(请参阅here),创建自己的类,粘贴代码以及稍后我们提供的一些调整:

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

    我只使用了TabletMasterDetailRenderer,因为我使用MasterDetailView为平板电脑设备创建一个特定视图,其中包含主设备内的日历视图,并在详细视图中显示所选条目的详细信息。

    如果手机需要它,使用PhoneMasterDetailRenderer进行的相同更改也应该有效。

答案 1 :(得分:1)

我们目前无法调整MasterDetailPage details

的宽度