ios - MonoTouch中的自定义UINavigationBar

原文 标签 ios uinavigationcontroller xamarin.ios uinavigationbar

Custom UINavigationBar in MonoTouch

I'm currently trying to create a custom navigation-bar for my navigation-controller in iOS using MonoTouch. The application I'm developing has the need to have a single string available on-screen no matter where you are on the application, and I wan't to achieve something like this (I know this is a little out off proportion, but you should be able to get the point):

+-----------------------------------------+
|  /---------|                     +---+  |
| /   Back   |     Controller Name |btn|  |
|  \---------|                     +---+  |
+-----------------------------------------+
|     Current building <- global string   |
+-----------------------------------------+

The bottom bar should be as small as possible (while not being hard to read), and the original navigation-bar might need to be a tiny bit smaller than normal.

Also, I've tried not to use the designer, but to write all the UI-code myself, but if that is impossible to achieve this, then I'll off cause have to use the designer. Currently I've found a project for creating a custom UINavigationBar in MonoTouch, but I have no idea of how to apply that to my NavigationController (see as the NavigationBar-property is read-only). The project I was talking about can be found here: https://github.com/mafis/Monotouch-Custom-Control/tree/master/CustomControls. Also, I would like the design of the actual navigationbar (the top part) to be standard iOS design, and work as a navigationbar normally would.

Any hints, or pointers at how to do this would be appreciated.

Answer

This is how I ended up solving this problem. I subclassed UIViewController like this:

using System;
using MonoTouch.UIKit;
using MonoTouch.CoreGraphics;
using System.Drawing;
using System.Collections.Generic;
using FdvWeb.Core;
namespace FdvWeb
{
    [MonoTouch.Foundation.Preserve(AllMembers=true)]
    public class MainNavigationController : UINavigationController
    {
        private const float NAV_BAR_HEIGHT = 44;
        private readonly float buildingBarTop = 44;
        private readonly float buildingBarHeight = 17;
        private readonly float viewOffset;

        private readonly HashSet<UIViewController> modifiedViewControllers = new HashSet<UIViewController>();

        UITextView buildingTextView;

        [MonoTouch.Foundation.Preserve]
        public MainNavigationController ()
        {
            viewOffset = buildingBarTop + buildingBarHeight - NAV_BAR_HEIGHT;

            var tt = new UITextView (new RectangleF (0, buildingBarTop, 320, buildingBarHeight));

            NavigationBarHidden = false;
            NavigationBar.AddSubview (tt);
            tt.Font = UIFont.BoldSystemFontOfSize (12);
            tt.TextAlignment = UITextAlignment.Center;
            tt.TextColor = UIColor.LightTextColor;
            tt.BackgroundColor = UIColor.ViewFlipsideBackgroundColor;
            tt.Editable = false;
            tt.ContentInset = new UIEdgeInsets (-9, 0, 0, 0);
            buildingTextView = tt;
        }

        public override void ViewDidLoad ()
        {
            base.ViewDidLoad ();


        }

        public override void ViewWillAppear (bool animated)
        {
            base.ViewWillAppear (animated);
        }

        public string BuildingText
        {
            get {
                return buildingTextView.Text;
            }
            set {
                container.Resolve<IUIThreadDispatcher> ().DispatchOnUIThread (delegate { // Run on UI thread
                    buildingTextView.Text = value;
                });
            }
        }

        public override void PushViewController (UIViewController viewController, bool animated)
        {
            if (!modifiedViewControllers.Contains (viewController))
            {
                viewController.View = new PaddedView (viewController.View, new InnsetF (0, viewOffset, 0, 0));
                modifiedViewControllers.Add (viewController);
            }

            viewController.NavigationItem.RightBarButtonItem = pickBuildingItem;
            base.PushViewController (viewController, animated);
        }

        private class PaddedView : UIView
        {
            private UIView view;
            private InnsetF innsets;

            public PaddedView (UIView view, InnsetF innsets)
                : base(view.Frame)
            {
                this.view = view;
                this.innsets = innsets;
                this.AutoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight;
                this.AddSubview (view);
            }

            public override void LayoutSubviews ()
            {
                //apply the insets to the subview
                view.Frame = new RectangleF (innsets.Left, innsets.Top,
                    Frame.Size.Width - innsets.Left - innsets.Right,
                    Frame.Size.Height - innsets.Top - innsets.Bottom);
            }
        }

        private class InnsetF
        {
            private float top, bottom, left, right;
            public InnsetF (float left, float top, float right, float bottom)
            {
                this.top = top;
                this.left = left;
                this.bottom = bottom;
                this.right = right;
            }

            public float Top
            {
                get { return top; }
                set { top = value; }
            }

            public float Bottom
            {
                get { return bottom; }
                set { bottom = value; }
            }

            public float Right
            {
                get { return right; }
                set { right = value; }
            }

            public float Left
            {
                get { return left; }
                set { left = value; }
            }
        }
    }
}

翻译

我目前正在尝试使用MonoTouch在iOS中为我的导航控制器创建一个自定义导航栏。无论您在应用程序中的哪个位置,我正在开发的应用程序都需要在屏幕上提供单个字符串,而且我也不会实现这样的目标(我知道这有点过分,但是您应该能够明白这一点):

+-----------------------------------------+
|  /---------|                     +---+  |
| /   Back   |     Controller Name |btn|  |
|  \---------|                     +---+  |
+-----------------------------------------+
|     Current building <- global string   |
+-----------------------------------------+


底部栏应尽可能小(不难阅读),并且原始导航栏可能需要比平时小一些。

另外,我尝试不使用设计器,而是自己编写所有UI代码,但是如果无法实现此目的,那么我将不得不使用设计器。当前,我已经找到一个用于在MonoTouch中创建自定义UINavigationBar的项目,但是我不知道如何将其应用于我的NavigationController(请参见NavigationBar属性是只读的)。我正在谈论的项目可以在这里找到:https://github.com/mafis/Monotouch-Custom-Control/tree/master/CustomControls。另外,我希望实际导航栏(顶部)的设计是标准的iOS设计,并且通常会像导航栏一样工作。

任何提示或有关如何执行此操作的指针将不胜感激。
最佳答案
这就是我最终解决此问题的方式。我将UIViewController分为以下子类:

using System;
using MonoTouch.UIKit;
using MonoTouch.CoreGraphics;
using System.Drawing;
using System.Collections.Generic;
using FdvWeb.Core;
namespace FdvWeb
{
    [MonoTouch.Foundation.Preserve(AllMembers=true)]
    public class MainNavigationController : UINavigationController
    {
        private const float NAV_BAR_HEIGHT = 44;
        private readonly float buildingBarTop = 44;
        private readonly float buildingBarHeight = 17;
        private readonly float viewOffset;

        private readonly HashSet<UIViewController> modifiedViewControllers = new HashSet<UIViewController>();

        UITextView buildingTextView;

        [MonoTouch.Foundation.Preserve]
        public MainNavigationController ()
        {
            viewOffset = buildingBarTop + buildingBarHeight - NAV_BAR_HEIGHT;

            var tt = new UITextView (new RectangleF (0, buildingBarTop, 320, buildingBarHeight));

            NavigationBarHidden = false;
            NavigationBar.AddSubview (tt);
            tt.Font = UIFont.BoldSystemFontOfSize (12);
            tt.TextAlignment = UITextAlignment.Center;
            tt.TextColor = UIColor.LightTextColor;
            tt.BackgroundColor = UIColor.ViewFlipsideBackgroundColor;
            tt.Editable = false;
            tt.ContentInset = new UIEdgeInsets (-9, 0, 0, 0);
            buildingTextView = tt;
        }

        public override void ViewDidLoad ()
        {
            base.ViewDidLoad ();


        }

        public override void ViewWillAppear (bool animated)
        {
            base.ViewWillAppear (animated);
        }

        public string BuildingText
        {
            get {
                return buildingTextView.Text;
            }
            set {
                container.Resolve<IUIThreadDispatcher> ().DispatchOnUIThread (delegate { // Run on UI thread
                    buildingTextView.Text = value;
                });
            }
        }

        public override void PushViewController (UIViewController viewController, bool animated)
        {
            if (!modifiedViewControllers.Contains (viewController))
            {
                viewController.View = new PaddedView (viewController.View, new InnsetF (0, viewOffset, 0, 0));
                modifiedViewControllers.Add (viewController);
            }

            viewController.NavigationItem.RightBarButtonItem = pickBuildingItem;
            base.PushViewController (viewController, animated);
        }

        private class PaddedView : UIView
        {
            private UIView view;
            private InnsetF innsets;

            public PaddedView (UIView view, InnsetF innsets)
                : base(view.Frame)
            {
                this.view = view;
                this.innsets = innsets;
                this.AutoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight;
                this.AddSubview (view);
            }

            public override void LayoutSubviews ()
            {
                //apply the insets to the subview
                view.Frame = new RectangleF (innsets.Left, innsets.Top,
                    Frame.Size.Width - innsets.Left - innsets.Right,
                    Frame.Size.Height - innsets.Top - innsets.Bottom);
            }
        }

        private class InnsetF
        {
            private float top, bottom, left, right;
            public InnsetF (float left, float top, float right, float bottom)
            {
                this.top = top;
                this.left = left;
                this.bottom = bottom;
                this.right = right;
            }

            public float Top
            {
                get { return top; }
                set { top = value; }
            }

            public float Bottom
            {
                get { return bottom; }
                set { bottom = value; }
            }

            public float Right
            {
                get { return right; }
                set { right = value; }
            }

            public float Left
            {
                get { return left; }
                set { left = value; }
            }
        }
    }
}
相关推荐

iphone - 最佳实践:将子类化的UIView(具有自己的xib)呈现为UIViewControllers的子视图

iphone - 自定义表格视图单元何时取消分配?

iphone - 如何为NSString drawAtPoint设置上下文?

iphone - 为什么在此参数中使用for循环

iphone - iOS-UITextView不绘制文本吗?

objective-c - 最有效的防裂方法

iphone - UITableView的编辑状态的自定义按钮

ios - iOS-后台进程和UI更新

iphone - 在iOS 4.2上使用SDK 4.3“ Hangs”构建的UIImagePicker

objective-c - main方法中引发了Objective C异常