You need to enable JavaScript to run this app. Xamarin Forms Android端编辑器长文本滚动时如何固定光标在用户点击位置
优惠活动
大模型
产品
解决方案
定价
更多

Xamarin Forms Android端编辑器长文本滚动时如何固定光标在用户点击位置

问题根因

你当前代码中使用的ScrollingMovementMethod是触发问题的核心原因:该类的默认滚动逻辑会自动将光标调整至当前可见文本区域,滚动时会强制修改光标位置,导致你之前点击选中的位置丢失。

解决方案

我们可以去掉系统的滚动逻辑,自行实现滚动控制+光标位置锁定,具体修改如下:

  1. 移除原有代码中Control.MovementMethod = ScrollingMovementMethod.Instance;配置
  2. 自定义触摸监听器,同时处理滚动逻辑和用户主动选中的光标位置持久化
  3. 滚动过程中强制锁定光标到用户选中的位置

修改后的自定义渲染器代码

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.19 06:45:03