我正在开发专门针对iOS平台的Xamarin.Forms项目。我有一个Editor
控件和一个Button
控件,彼此相邻。当我关注编辑器时,输入一些文本,然后单击它出现的按钮,命令没有被触发,而键盘只是关闭。然后,我必须再次点击添加按钮才能触发命令。
<StackLayout Orientation="Horizontal">
<Editor HorizontalOptions="FillAndExpand"
Text="{Binding EditorText}"/>
<Button Text="Add"
Command="{Binding AddCommand}"/>
</StackLayout>
我尝试过创建自定义渲染器,以防止键盘最初关闭,然后在延迟后关闭它。这允许命令被触发,但我被困在键盘打开。
public class KeyboardEditorRenderer : EditorRenderer
{
protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName == VisualElement.IsFocusedProperty.PropertyName)
{
if (Control != null)
{
Control.ShouldEndEditing = (UITextView textField) =>
{
Task.Delay(10).ContinueWith(_ =>
{
// THIS DOES NOT WORK
textField.EndEditing(true);
});
return false;
};
}
}
base.OnElementPropertyChanged(sender, e);
}
}
我理想的解决方案是您可以输入文本,点击添加按钮,键盘关闭,命令同时执行。关于如何实现这一点的任何想法?
编辑:事实证明问题在于我用于页面的自定义渲染器。当键盘出现时,自定义渲染器会调整页面的大小,使其不会覆盖我的编辑器字段。
public class KeyboardPageRenderer : PageRenderer
{
private bool keyboardShowing;
private NSObject keyboardWillShow;
private NSObject keyboardWillHide;
private double duration;
private UIViewAnimationCurve curve;
public override void ViewDidLoad()
{
base.ViewDidLoad();
this.keyboardWillShow = UIKeyboard.Notifications.ObserveWillShow(this.KeyboardWillShow);
this.keyboardWillHide = UIKeyboard.Notifications.ObserveWillHide(this.KeyboardWillHide);
}
public override void ViewDidDisappear(bool animated)
{
base.ViewDidDisappear(animated);
this.keyboardWillShow.Dispose();
this.keyboardWillHide.Dispose();
}
private void KeyboardWillShow(object sender, UIKeyboardEventArgs args)
{
if (!this.keyboardShowing)
{
this.keyboardShowing = true;
var keyboardFrame = UIKeyboard.FrameBeginFromNotification(args.Notification);
this.duration = args.AnimationDuration;
this.curve = args.AnimationCurve;
this.ScrollTheView(true, keyboardFrame.Height);
}
}
private void KeyboardWillHide(object sender, UIKeyboardEventArgs args)
{
if (this.keyboardShowing)
{
this.keyboardShowing = false;
var keyboardFrame = UIKeyboard.FrameBeginFromNotification(args.Notification);
this.duration = args.AnimationDuration;
this.curve = args.AnimationCurve;
this.ScrollTheView(false, keyboardFrame.Height);
}
}
private void ScrollTheView(bool scale, nfloat scrollAmount)
{
UIView.BeginAnimations(string.Empty, IntPtr.Zero);
UIView.SetAnimationDuration(this.duration);
UIView.SetAnimationCurve(this.curve);
var frame = View.Frame;
// Assumes the page belongs to a tabbed view.
// This does not scale to pages that do not have one.
UITabBarController tabBarController = new UITabBarController();
nfloat tabHeight = tabBarController.TabBar.Frame.Size.Height;
scrollAmount -= tabHeight;
if (scale)
{
frame.Y -= scrollAmount;
}
else
{
frame.Y += scrollAmount;
}
View.Frame = frame;
UIView.CommitAnimations();
}
}
答案 0 :(得分:0)
您的方法有两个问题
Task.Delay(10)
之后,您不再处于UI线程上,这意味着您必须使用Device.BeginInvokeOnMainThread
才能访问UI元素。Control.ShouldEndEditing
必须先清除,然后再致电EndEditing
有效的解决方案如下所示:
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (Element == null || Control == null)
return;
VisualElement element = Element as VisualElement;
if (element == null)
return;
if (e.PropertyName == VisualElement.IsFocusedProperty.PropertyName && element.IsFocused == false)
{
Control.ShouldEndEditing = (UITextView control) =>
{
Device.BeginInvokeOnMainThread(() =>
{
control.ShouldEndEditing = null;
control.EndEditing(true);
});
// prevent the keyboard from closing
return false;
};
}
}