我正在尝试为Xamarin.Forms项目实现带有提示文本功能的编辑器。这在Android中是微不足道的,因为底层的EntryEditText控件具有Hint属性。在iOS中,实现有点复杂,因为UITextView类没有实现提示文本。
我不喜欢这种技巧,"将文本设置为占位符,如果键入开始则清除它,如果键入结束则返回,文本为空白"。这意味着我必须做额外的工作来判断控件是否空白,并且有很多涉及文本颜色的摆弄。但是我一直有这么多麻烦我不得不诉诸它。也许有人可以帮助我。
我开始回答Placeholder in UITextView。我开始了一个新的Xamarin iOS项目,偶然发现了一个粗略的Obj-C到C#的转换,并且只需稍加改动就可以了:UITextView的Font属性还没有在构造函数中初始化,所以我不得不重写AwakeFromNib()设置占位符标签的字体。我测试了它并且它工作了,所以我将该文件带入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项目中,有时父母的字体为空,将标签的字体设置为空也是非法的。在构建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属性的任何原因有关。
所以我正在寻找两个问题的答案:
我希望自己错过了一些明显的东西,因为我开始咆哮错误的树木。
答案 0 :(得分:0)
如果我在XF中扩展iOS控件以添加子视图,那么它是什么 处理子视图大小的最佳方法?我找到了高度/宽度 更改会在渲染器中引发事件,这是唯一可行的方法吗?
这是我所知道的唯一方式,因为渲染器的曝光元素非常有限。
当用户未设置该属性时,是一个字体 Xamarin Forms中的UITextView是否设置为非null值?我可以活下去 要求此控件需要字体 明确设定,但它很难吃,我想避免它。
不,没有为Font指定默认的非空值。