Xamarin Forms Android端编辑器长文本滚动时如何固定光标在用户点击位置
问题根因
你当前代码中使用的ScrollingMovementMethod是触发问题的核心原因:该类的默认滚动逻辑会自动将光标调整至当前可见文本区域,滚动时会强制修改光标位置,导致你之前点击选中的位置丢失。
解决方案
我们可以去掉系统的滚动逻辑,自行实现滚动控制+光标位置锁定,具体修改如下:
- 移除原有代码中
Control.MovementMethod = ScrollingMovementMethod.Instance;配置 - 自定义触摸监听器,同时处理滚动逻辑和用户主动选中的光标位置持久化
- 滚动过程中强制锁定光标到用户选中的位置
修改后的自定义渲染器代码
if (e.OldElement == null) { var nativeEditText = (global::Android.Widget.EditText)Control; nativeEditText.OverScrollMode = OverScrollMode.Always; nativeEditText.ScrollBarStyle = ScrollbarStyles.InsideInset; nativeEditText.VerticalScrollBarEnabled = true; // 把当前EditText实例传入自定义触摸监听器 nativeEditText.SetOnTouchListener(new DroidTouchListener(nativeEditText)); Control.VerticalScrollBarEnabled = true; Control.ScrollBarStyle = Android.Views.ScrollbarStyles.InsideInset; Android.Content.Res.TypedArray a = Control.Context.Theme.ObtainStyledAttributes(new int[0]); InitializeScrollbars(a); a.Recycle(); // 初始默认定位到文本末尾 Control.SetSelection(Control.Length()); // 新增:监听用户主动选中光标的事件 nativeEditText.SelectionChanged += (s, e) => { // 仅保存用户主动点击触发的光标位置,过滤系统滚动导致的自动选中 if(DroidTouchListener.IsUserTapping) { DroidTouchListener.FixedCursorPosition = nativeEditText.SelectionStart; } }; }
新增/修改DroidTouchListener实现
public class DroidTouchListener : Java.Lang.Object, View.IOnTouchListener { // 持久化保存用户锁定的光标位置 public static int FixedCursorPosition = -1; // 标记当前是否是用户主动点击操作 public static bool IsUserTapping = false; private float _lastTouchY; private readonly EditText _targetEditText; public DroidTouchListener(EditText editText) { _targetEditText = editText; } public bool OnTouch(View v, MotionEvent e) { switch(e.Action) { case MotionEventActions.Down: IsUserTapping = true; _lastTouchY = e.GetY(); // 点击时先恢复锁定的光标位置,避免之前滚动导致的偏移 if(FixedCursorPosition != -1 && FixedCursorPosition <= _targetEditText.Text.Length) { _targetEditText.SetSelection(FixedCursorPosition); } break; case MotionEventActions.Move: IsUserTapping = false; // 自行处理滚动逻辑,替代系统的ScrollingMovementMethod float scrollOffsetY = _lastTouchY - e.GetY(); _targetEditText.ScrollBy(0, (int)scrollOffsetY); _lastTouchY = e.GetY(); // 滚动过程中强制锁定光标位置 if(FixedCursorPosition != -1 && FixedCursorPosition <= _targetEditText.Text.Length) { _targetEditText.SetSelection(FixedCursorPosition); } return true; case MotionEventActions.Up: IsUserTapping = false; // 触摸结束后再次确认光标位置 if(FixedCursorPosition != -1 && FixedCursorPosition <= _targetEditText.Text.Length) { _targetEditText.SetSelection(FixedCursorPosition); } break; } return false; } }
注意事项
- 如果你的编辑器支持选中文本,可把
FixedCursorPosition扩展为光标起始、结束两个位置,即可同时锁定选中范围 - 如果需要适配软键盘弹出、横屏切换等场景,可在对应生命周期回调里再次调用
SetSelection恢复锁定的光标位置即可
内容的提问来源于stack exchange,提问作者Monali K
相关产品推荐
相关产品推荐

