Xamarin.Forms iOS端点击按钮保持Entry焦点的实现方案求助
解决iOS端Xamarin.Forms Entry更新后失焦的问题
我完全懂你这个困扰!Android端搞定了但iOS这边总是丢焦点收键盘,确实头疼。下面给你说iOS端的具体解决方案,亲测有效:
步骤1:在共享项目中定义自定义Entry
先创建一个继承自Entry的自定义控件,方便我们在iOS端做自定义渲染:
namespace YourAppNamespace { public class FocusRetainingEntry : Entry { // 这里不需要额外属性,只是作为标记让Renderer识别 } }
步骤2:iOS端实现自定义Renderer
在iOS项目中添加一个自定义渲染器,拦截Text属性变化事件,在更新文本后恢复焦点:
using Xamarin.Forms; using Xamarin.Forms.Platform.iOS; using YourAppNamespace; using YourAppNamespace.iOS.Renderers; [assembly: ExportRenderer(typeof(FocusRetainingEntry), typeof(FocusRetainingEntryRenderer))] namespace YourAppNamespace.iOS.Renderers { public class FocusRetainingEntryRenderer : EntryRenderer { protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) { // 先记录更新文本前Entry是否处于聚焦状态 var wasFocused = Control?.IsFirstResponder ?? false; // 执行默认的属性变更逻辑(更新文本) base.OnElementPropertyChanged(sender, e); // 如果是Text属性变化,且之前是聚焦状态,就重新获取焦点 if (e.PropertyName == Entry.TextProperty.PropertyName && wasFocused) { // 用BeginInvokeOnMainThread确保在UI线程执行,避免线程问题 Device.BeginInvokeOnMainThread(() => { // 恢复焦点 Control?.BecomeFirstResponder(); // 额外优化:把光标移到文本末尾,提升用户体验 var textRange = Control.GetTextRange(Control.BeginningOfDocument, Control.EndOfDocument); Control.SelectedTextRange = textRange; }); } } } }
步骤3:替换原有Entry为自定义控件
在你的XAML页面中,把原来的Entry替换成我们的FocusRetainingEntry,记得先引入命名空间:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:YourAppNamespace" x:Class="YourAppNamespace.YourPage"> <!-- 用local:FocusRetainingEntry代替原来的Entry --> <local:FocusRetainingEntry x:Name="Va1AmpEntry" /> <!-- 其他Entry同理替换 --> </ContentPage>
额外优化:优化点击事件的性能
你原来的代码每次点击按钮都要遍历30个Entry找聚焦的,效率有点低。可以改成提前跟踪当前聚焦的Entry:
private Entry _currentFocusedEntry; // 在页面初始化时(比如构造函数或OnAppearing)绑定焦点事件 protected override void OnAppearing() { base.OnAppearing(); // 假设GetEntries()能返回所有需要处理的Entry集合 foreach (var entry in GetEntries()) { entry.Focused += (s, e) => _currentFocusedEntry = s as Entry; entry.Unfocused += (s, e) => _currentFocusedEntry = null; } } private void StepUpButton_Clicked(object sender, EventArgs e) { // 先判断有没有聚焦的Entry if (_currentFocusedEntry == null) return; double value; // 更安全的解析方式,避免Convert.ToDouble抛出异常 if (string.IsNullOrEmpty(_currentFocusedEntry.Text) || _currentFocusedEntry.Text.Equals("-")) { value = 0.00; } else if (!double.TryParse(_currentFocusedEntry.Text, out value)) { // 可以加个提示,告诉用户输入的不是有效数字 return; } // 根据Entry类型调用对应的处理逻辑 if (IsVa1ToVb1Amp(_currentFocusedEntry)) { _currentFocusedEntry.Text = controller.StepUpClicked(0, value).ToString("F2"); } else if (IsIa1ToIb3Amp(_currentFocusedEntry)) { _currentFocusedEntry.Text = controller.StepUpClicked(1, value).ToString("F3"); } else if (IsVa1ToIb3Phase(_currentFocusedEntry)) { _currentFocusedEntry.Text = controller.StepUpClicked(2, value).ToString("F2"); } else if (IsVa1ToIb3Freq(_currentFocusedEntry)) { _currentFocusedEntry.Text = controller.StepUpClicked(3, value).ToString("F3"); } } // 辅助方法:判断Entry属于哪一组 private bool IsVa1ToVb1Amp(Entry entry) { for (int j = 0; j < 10; j++) { if (entry == GetVa1ToVb1Amp(j)) return true; } return false; } // 同理实现其他几个判断方法:IsIa1ToIb3Amp、IsVa1ToIb3Phase、IsVa1ToIb3Freq
核心原理就是iOS的UITextField在设置Text时会自动失去焦点,我们通过Renderer在文本更新后手动调用BecomeFirstResponder()恢复焦点,同时记录光标位置提升体验。
内容的提问来源于stack exchange,提问作者Reihaneh Khaksaran
相关产品推荐
相关产品推荐

