Xamarin.ios UITextView的边界和字体何时以Xamarin形式初始化?

Xamarin.ios UITextView的边界和字体何时以Xamarin形式初始化?,xamarin.ios,custom-controls,xamarin.forms,Xamarin.ios,Custom Controls,Xamarin.forms,我正试图为一个Xamarin.Forms项目实现一个具有提示文本功能的编辑器。这在Android中很简单,因为底层EntryEditText控件有一个Hint属性。在iOS中,实现稍微复杂一些,因为UITextView类不实现提示文本 我不喜欢这种技术,“将文本设置为占位符,如果键入开始,则清除它,如果键入结束,且文本为空,则返回它”。这意味着我必须做额外的工作来判断控件是否为空白,并且需要对文本颜色进行大量的修改。但是我遇到了很多麻烦,我不得不求助于它。也许有人能帮我 我开始回答这个问题。我启

我正试图为一个Xamarin.Forms项目实现一个具有提示文本功能的编辑器。这在Android中很简单,因为底层EntryEditText控件有一个Hint属性。在iOS中,实现稍微复杂一些,因为UITextView类不实现提示文本

我不喜欢这种技术,“将文本设置为占位符,如果键入开始,则清除它,如果键入结束,且文本为空,则返回它”。这意味着我必须做额外的工作来判断控件是否为空白,并且需要对文本颜色进行大量的修改。但是我遇到了很多麻烦,我不得不求助于它。也许有人能帮我

我开始回答这个问题。我启动了一个新的Xamarin iOS项目,并在一个粗略的Obj-C到C#转换中遇到了困难,它做了一个很好的修改:UITextView的字体属性尚未在构造函数中初始化,因此我必须重写AwakeFromNib()来设置占位符标签的字体。我对它进行了测试,结果成功了,所以我将该文件引入到Xamarin Forms项目中,事情开始变得有点疯狂

第一个问题是,MonoTouch在Xamarin形式上显然有一些轻微的API差异,例如使用了一些类型,如RectangleF而不是CGRect。这是显而易见的,如果不是出乎意料的话。在过去的几天里,我一直在努力解决其他一些差异,但似乎无法以一种让我高兴的方式克服它们。这是我的文件,因为我一直在尝试各种调试方法,所以被大幅缩减:

using System;
using MonoTouch.UIKit;
using MonoTouch.Foundation;
using MonoTouch.CoreGraphics;
using System.Drawing;

namespace TestCustomRenderer.iOS {
    public class PlaceholderTextView : UITextView {

        private UILabel _placeholderLabel;
        private NSObject _notificationToken;

        private const double UI_PLACEHOLDER_TEXT_CHANGED_ANIMATION_DURATION = 0.25;

        private string _placeholder;
        public string Placeholder {
            get {
                return _placeholder;
            }
            set {
                _placeholder = value;
                if (_placeholderLabel != null) {
                    _placeholderLabel.Text = _placeholder;
                }
            }
        }

        public PlaceholderTextView() : base(RectangleF.Empty) {
            Initialize();
        }

        private void Initialize() {
            _notificationToken = NSNotificationCenter.DefaultCenter.AddObserver(TextDidChangeNotification, HandleTextChanged);
            _placeholderLabel = new UILabel(new RectangleF(8, 8, this.Bounds.Size.Width - 16, 25)) {
                LineBreakMode = UILineBreakMode.WordWrap,
                Lines = 1,
                BackgroundColor = UIColor.Green,
                TextColor = UIColor.Gray,
                Alpha = 1.0f,
                Text = Placeholder
            };

            AddSubview(_placeholderLabel);
            _placeholderLabel.SizeToFit();
            SendSubviewToBack(_placeholderLabel);
        }

        public override void DrawRect(RectangleF area, UIViewPrintFormatter formatter) {
            base.DrawRect(area, formatter);

            if (Text.Length == 0 && Placeholder.Length > 0) {
                _placeholderLabel.Alpha = 1;
            }
        }

        private void HandleTextChanged(NSNotification notification) {
            if (Placeholder.Length == 0) {
                return;
            }

            UIView.Animate(UI_PLACEHOLDER_TEXT_CHANGED_ANIMATION_DURATION, () => {
                if (Text.Length == 0) {
                    _placeholderLabel.Alpha = 1;
                } else {
                    _placeholderLabel.Alpha = 0;
                }
            });
        } 

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

            _placeholderLabel.Font = this.Font;
        }

        protected override void Dispose(bool disposing) {
            base.Dispose(disposing);

            if (disposing) {
                NSNotificationCenter.DefaultCenter.RemoveObserver(_notificationToken);
                _placeholderLabel.Dispose();
            }
        }

    }
}
这里一个值得注意的变化是将标签的初始化从DrawRect()重新定位到构造函数。据我所知,Xamarin从不允许调用DrawRect()。您还会注意到我没有设置字体属性。在iOS MonoTouch项目中,有时父项的字体为null,将标签的字体设置为null也是非法的。似乎在构造之后的某个时刻,Xamarin设置了字体,因此在AwakeFromNib()中设置该属性是安全的

我编写了一个快速编辑器派生类和一个自定义渲染器,因此Xamarin Forms可以渲染控件,渲染器有点值得注意,因为我是从NativeRenderer而不是EditorRenderer派生的。我需要从重写的OnModelSet()调用SetNativeControl(),但查看程序集查看器时发现EditorRenderer进行了一些私人调用,我必须在我的程序中重新实现。喝倒采没有张贴,因为这已经是巨大的,但我可以编辑它,如果需要的话

上面的代码是值得注意的,因为占位符根本不可见。在面向iOS的MonoTouch中,您通常使用帧初始化控件,而调整大小是一种非常罕见的情况,您可以假定它不会发生。在Xamarin表单中,布局是由布局容器执行的,因此构造函数提供的框架是无关的。但是,标签的大小是在构造函数中设置的,因此它的宽度为负。哎呀

我认为这可以通过将标签的实例化移动到AwakeFromNib()中来解决,或者至少在那里调整它的大小。这时我发现由于某种原因,控件中没有调用AwakeFromNib()。好的。我试图找到一个等效的回调/事件,该事件发生得足够晚,可以设置边界,但在iOS端找不到任何东西。在尝试了很多东西之后,我注意到定制渲染器收到了这个混乱的Xamarin表单模型端的属性更改事件。因此,如果我侦听高度/宽度更改事件,那么我可以调用标签上的方法,根据当前控件为其提供合理的大小。这暴露了另一个问题

我无法找到将标签的字体设置为与UITextView的字体匹配的方法。在构造函数中,字体属性为null。iOS和Xamarin表单项目都是如此。在iOS项目中,调用AwakeFromNib()时,属性已初始化,一切正常。在XF项目中,它从来没有被调用过,甚至当我从一个延迟5秒的任务中调用一个方法(以确保控件被显示)时,该属性仍然为空

逻辑和iOS文档规定字体的默认值应为17点Helvetica。这对于占位符标签是正确的,如果我伪造了大小,使其可见。对于UITextView控件来说,情况并非如此,但由于它将其字体报告为null,因此我无法看到该字体的实际内容。当然,如果我手动设置,一切都很好,但我希望能够处理默认情况。这看起来像一只虫子;盒子的字体好像有问题。我觉得这与Xamarin.Forms.Editor类没有字体属性的任何原因有关

所以我在寻找两个问题的答案:

  • 如果我在XF中扩展iOS控件以添加子视图,那么处理该子视图大小的最佳方法是什么?我发现高度/宽度更改会在渲染器中引发事件,这是唯一可用的方法吗
  • 当用户未设置属性时,Xamarin表单中UITextView的字体是否设置为非空值?我可以接受这样一个要求,即这个控件需要显式设置字体,但这很恶心,我想避免它
  • 我希望我错过了一些明显的东西,因为我开始在错误的树上吠叫

    如果我在XF中扩展iOS控件以添加子视图,那么 调整子视图大小的最佳方法?我找到了高度/宽度 更改会在渲染器中引发事件,这是唯一可用的方法吗

    这是我知道的唯一方法,因为渲染器的公开元素非常有限

    如果用户未设置属性,则为 Xamarin表单中的UITextView是否设置为非空值?我能活下去 此控件要求字体为 显式设置,但这很恶心,我想避免它

    不,t