#performance #xamarin #richtextbox
#Производительность #xamarin #richtextbox
Вопрос:
Мы хотим создать богатый (но не слишком богатый) текстовый редактор с помощью xamarin, чтобы можно было:
- Выделите некоторые слова
- Поместите курсор в любом месте с помощью мыши или коснитесь
- Показать положение курсора
Наша попытка заключается в использовании метки для отображения текста, и когда пользователь нажимает на метку, на самом деле фокусируется скрытая запись. Чтобы переместить курсор, мы разделяем FormattedString на больший промежуток, по одному для каждого символа, чтобы мы знали, какой из них выбран или нажат.
Теперь проблема заключается в производительности, поскольку с ростом содержимого время обновления представления значительно увеличивается. Например, только для добавления одного символа может потребоваться 3000 мс, если длина содержимого составляет около 30 символов. Кстати, это занимает всего 10 мс, если длина содержимого составляет всего 1-5 символов. Время обновления метки не зависит линейно от длины текста.
Здесь я помещаю код, в котором возникает проблема с производительностью, и я хочу спросить вас, есть ли проблема в моем коде или, может быть, я не могу сделать это в xamarin таким образом.
Stopwatch stopwatch = Stopwatch.StartNew();
string newText = e.NewTextValue;
string oldText = (e.OldTextValue ?? string.Empty);
List<string> newParts = newText.Split('#').ToList();
List<string> oldParts = oldText.Split('#').ToList();
// ...
foreach (string part in newParts)
{
string placeholderCode = $"#{part}#";
string textToShow = isPlaceholder ? placeholders[placeholderCode] : part;
if (isPlaceholder)
{
editorPosition = placeholderCode.Length;
}
Span tmpSpan = new Span();
foreach (char character in textToShow)
{
Span item = viewer.FormattedText.Spans.ElementAtOrDefault(currentSpan );
if (item == null)
{
item = new Span();
TapGestureRecognizer gestureRecognizer = new TapGestureRecognizer();
gestureRecognizer.Tapped = delegate {
editor.CursorPosition = spanToEditorPosition[item];
FocusEditor();
};
item.GestureRecognizers.Add(gestureRecognizer);
viewer.FormattedText.Spans.Add(item);
}
if (isPlaceholder)
{
tmpSpan.FontAttributes = FontAttributes.Bold;
}
else
{
tmpSpan.FontAttributes = FontAttributes.None;
editorPosition ;
}
tmpSpan.Text = character.ToString();
if (tmpSpan.Text != item.Text || tmpSpan.FontAttributes != item.FontAttributes)
{
item.Text = tmpSpan.Text;
item.FontAttributes = tmpSpan.FontAttributes;
}
spanToEditorPosition.Add(item, editorPosition);
}
isPlaceholder = !isPlaceholder;
}
stopwatch.Stop();
Комментарии:
1. во-первых, профилировали ли вы свой код, чтобы определить, где проблема с производительностью? Во-вторых, я подозреваю, что нечто подобное действительно должно быть реализовано на уровне платформы и представлено с помощью пользовательского средства визуализации, а не непосредственно в формах.
2. Спасибо @jason за комментарий. Я измерил время выполнения с помощью класса StopWatch, я не знаю, как использовать и как работает профилировщик. Вы имеете в виду, должен ли я создать пользовательскую метку и пользовательское средство визуализации меток?
3. вы профилировали общий цикл, но следующим шагом будет профилирование внутренних циклов и отдельных операторов, чтобы определить, какие из них являются худшими нарушителями