首页 文章

何时在Xamarin Forms中初始化UITextView的边界和字体?

提问于
浏览
0

我正在尝试为Xamarin.Forms项目实现一个带有提示文本功能的编辑器 . 这在Android中是微不足道的,因为底层的EntryEditText控件具有Hint属性 . 在iOS中,实现有点复杂,因为UITextView类不实现提示文本 .

我不喜欢这种技术,“将文本设置为占位符,如果键入开始则清除它,如果键入结束则返回,文本为空” . 这意味着我必须做额外的工作来判断控件是否为空白,并且有很多涉及文本颜色的摆弄 . 但是我一直有这么多麻烦我不得不诉诸它 . 也许有人可以帮助我 .

我开始回答Placeholder in UITextView . 我开始了一个新的Xamarin iOS项目,偶然发现了一个粗略的Obj-C到C#的转换,并且通过一个小改动它运行得很好:UITextView的Font属性不是't initialized yet in the constructor, so I had to override AwakeFromNib() to set the placeholder label' s字体 . 我测试了它并且它工作了,所以我将该文件带入Xamarin Forms项目,事情开始变得有点疯狂 .

第一个问题是,事实证明MonoTouch在Xamarin Forms中有一些轻微的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()被调用 . 您还会注意到我没有设置Font属性 . 事实证明,在iOS MonoTouch项目中,有时父项的字体为null,将标签的字体设置为null也是非法的 . 在构建Xamarin设置字体后,似乎在某些时候,因此在AwakeFromNib()中设置该属性是安全的 .

我写了一个快速的编辑器派生类和一个自定义渲染器,因此Xamarin Forms可以渲染控件,渲染器稍微有点值得注意,因为我派生自NativeRenderer而不是EditorRenderer . 我需要从重写的OnModelSet()调用SetNativeControl(),但是在程序集查看器中查看显示,EditorRenderer会进行一些私人调用,我必须在我的中重新实现 . 嘘 . 没有发布,因为这已经很大了,但我可以根据需要进行编辑 .

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

我假设这可以通过将标签的实例化移动到AwakeFromNib()中来解决,或者至少在那里调整它的大小 . 这是因为我发现由于某种原因,在控件中没有调用AwakeFromNib() . 韦尔普 . 我试图找到一个等效的回调/事件,这个回调/事件发生得足够晚,可以设置边界,但是在iOS端找不到任何东西 . 在尝试了很多很多东西之后,我注意到自定义渲染器收到了这个混乱的Xamarin Forms Model方面的属性更改事件 . 所以,如果我监听Height / Width更改事件,我可以调用标签上的方法,根据当前控件给它一个合理的大小 . 这暴露了另一个问题 .

我找不到设置标签字体以匹配UITextView字体的方法 . 在构造函数中,Font属性为null . 在iOS和Xamarin Forms项目中都是如此 . 在iOS项目中,当调用AwakeFromNib()时,属性被初始化并且一切都很好 . 在XF项目中,它永远不会被调用,甚至当我从5秒延迟的任务中调用特技来调用方法时(为了确保显示控件),该属性仍为空 .

逻辑和iOS文档规定字体的默认值应为17点Helvetica . 如果我捏造大小以使其可见,则占位符标签也是如此 . UITextView控件不是这样,但由于它将其字体报告为null,我无法看到字体实际是什么 . 如果我手动设置它一切都很好,当然,但我希望能够处理默认情况 . 这似乎是一个bug;这个盒子似乎在撒谎 . 我有一种感觉,它与Xamarin.Forms.Editor类没有Font属性的任何原因有关 .

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

  • 如果我发现高度/宽度更改会在渲染器中引发事件,这是唯一可行的方法吗?

  • 当用户未设置该属性时,Xamarin Forms中的UITextView字体是否设置为非空值?我可以满足这种控制要求明确设置字体的要求,但它希望避免使用它 .

我希望我错过了一些明显的东西,因为我开始咆哮错误的树木 .

1 回答

  • 0

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

    这是我所知道的唯一方式,因为渲染器的外露元素非常有限 .

    当用户未设置该属性时,Xamarin Forms中的UITextView字体是否设置为非空值?我可以忍受这个控件需要明确设置字体的要求,但它很难吃,我想避免它 .

    不,没有为Font指定默认的非null值 .

相关问题