1

我正在使用一个 EditText 控件,我允许使用(粗体、斜体等)的文本格式。

要应用格式,在我的 TextWatcher 的 AfterTextChanged 事件处理程序中,我检测是否已通过 UI 切换了格式样式(例如粗体)。如果是这样,我尝试了两种不同的方法,但由于不同的原因,这两种方法都不令人满意:

方法一

textView.EditableText.SetSpan(new StyleSpan(TypefaceStyle.Bold), start, end, SpanTypes.ExclusiveExclusive);

对于起始值,我尝试使用_textView.SelectionStart - 1或首次应用 StyleSpan 时的起始位置。而对于最终_textView.SelectionStart

尽管使用此方法文本的格式看起来很好,但当只有一个就足够时,它会创建不必要的 StyleSpan。当我尝试通过 Html 转换将文本保存到本地数据库时,这一点很清楚:

string html = Html.ToHtml(new SpannableString(Fragment_Textarea.Instance().Textarea().EditableText));

例如,<b>this is bold text</b>我得到的是 ,而不是<b><b><b><b><b><b><b><b><b><b><b><b><b><b><b><b><b>this is bold text</b></b></b></b></b></b></b></b></b></b></b></b></b></b></b></b></b>。所以,很明显,我在这种方法中做错了/效率低下。显然,这导致在输入文本和启动时检索时最终都会变慢。

我考虑过的是检查前一个_textView.SelectionStart - 1字符_textView.SelectionStart(检查/删除/添加必要的跨度。但这似乎是另一种处理此问题的低效方法。

方法二

textView.EditableText.SetSpan(new StyleSpan(TypefaceStyle.Bold), start, end, SpanTypes.ExclusiveInclusive);

因此,这不会导致与上述相同的低效率,但是由于该SpanTypes.ExclusiveInclusive标志,当我通过 UI 将其关闭时,我无法停止样式格式化以结束。换句话说,当我打开粗体样式时,后面的所有文本都将被格式化为粗体样式,即使我已经关闭了它的切换。

在这两者中,在我看来,这似乎是正确的一般方法,所以我想知道我是否可以做任何事情来阻止在我关闭其切换时立即应用该样式。还是有另一种我完全错过的方法作为处理此类要求的最佳实践。

4

1 回答 1

0

所以,我最终采取了完全不同的方法,将设置跨度的责任转移到工具栏上的按钮激活样式被切换时(与任何文本更改的侦听器相反)。

例如,当打开粗体样式时,其事件处理程序会运行并点击以下代码:

int start = _textarea.SelectionStart - 1;
var spanType = SpanTypes.ExclusiveInclusive;
_textarea.EditableText.SetSpan(new StyleSpan(TypefaceStyle.Bold), start, _textarea.SelectionStart, spanType);

如上所述,跨度类型需要是 ExclusiveInclusive。诀窍是在样式关闭后立即更改此设置。如果您以粗体输入然后关闭样式,这相对简单(只需找到跨度,删除它,然后添加具有相同起点/终点的新跨度,但那是 ExcExc)。但是我需要代码更加灵活,并考虑到您以后可能决定在另一种样式的跨度文本中键入的情况。例如,假设我从以下开始:

这是粗体字

但后来我编辑并想将其更改为:

这是粗体文本

在这种情况下,我需要确保在“是”的任一侧创建一个 ExclusiveExclusive 粗体跨度。:

int start = -1;
int end = -1;
List<Tuple<int, int>> respans = new List<Tuple<int, int>>(); 

// go through all relevant spans that start from -1 indices ago
var spans = _textarea.EditableText.GetSpans(_textarea.SelectionStart - 1, _textarea.SelectionStart, Class.FromType(typeof(StyleSpan)));
if (spans.Length > 0)
{
    for (int u = 0; u < spans.Length; u++)
    {
        // found a matching span!
        if (((StyleSpan)spans[u]).Style == TypefaceStyle.Bold)
        {
            // get the starting and ending indices for the iterated span
            start = _textarea.EditableText.GetSpanStart(spans[u]);
            end = _textarea.EditableText.GetSpanEnd(spans[u]);

            // remove the span
            _textarea.EditableText.RemoveSpan(spans[u]);

            // if the current index is less than when this iterated span ended
            // and greater than when it started
            // then that means non-bold text is being inserted in the middle of a bold span
            // that needs to be split into 2 (before current index + after current index)
            if (_textarea.SelectionStart > start && _textarea.SelectionStart < end)
            {
                respans.Add(new Tuple<int, int>(start, _textarea.SelectionStart - 1));
                for(int c = _textarea.SelectionStart + 1; c < _textarea.Length(); c++ )
                {
                    if(_textarea.Text[c] != ' ' )
                    {
                        respans.Add(new Tuple<int, int>(c, end));
                        break;
                    }
                }
            }
            // otherwise, the recreated span needs to start and end when the iterated did
            // with one important change in relation to its span type
            else
            {
                respans.Add(new Tuple<int, int>(start, end));
            }
        }
    }

    // if there are 1 or more spans that need to be restored,
    // go through them and add them back according to start/end points set on their creation
    // as an ExclusiveExclusive span type
    if( respans.Count > 0 )
    {
        foreach( Tuple<int,int> tp in respans )
        {
            _textarea.EditableText.SetSpan(new StyleSpan(TypefaceStyle.Bold), tp.Item1, tp.Item2, SpanTypes.ExclusiveExclusive);
        }
    }
}

这似乎在做这项工作:当 UI 交互时创建/管理跨度(而不是文本更改)

于 2020-02-21T14:19:53.193 回答