UWP: вычисление преобразования на основе ScrollViewer
У меня есть универсальное приложение для Windows, где я показываю сцену с DirectX. Я хочу использовать Scrollviewer, и поэтому я делаю свою сцену за Scrollviewer и хочу рассчитать трансформацию сцены на основе Scrollviewer. До сих пор он отлично работает, особенно в переводе и прокрутке. Но когда я увеличиваю масштаб, сцена прыгает в двух особых ситуациях:
- Сцена имела достаточно места и была сосредоточена, и теперь требуется прокрутка.
- В противоположном направлении.
Более или менее я использую следующий код:
float zoom = scrollViewer.ZoomFactor;
float inverseZoom = 1f / scrollViewer.ZoomFactor;
float scaledContentW = Document.Size.X * scrollViewer.ZoomFactor;
float scaledContentH = Document.Size.Y * scrollViewer.ZoomFactor;
float translateX;
float translateY;
if (scaledContentW < scrollViewer.ViewportWidth)
{
translateX = ((float)scrollViewer.ViewportWidth * inverseZoom - Document.Size.X) * 0.5f;
}
else
{
translateX = -inverseZoom * (float)scrollViewer.HorizontalOffset;
}
if (scaledContentH < scrollViewer.ViewportHeight)
{
translateY = ((float)scrollViewer.ViewportHeight * inverseZoom - Document.Size.Y) * 0.5f;
}
else
{
translateY = -inverseZoom * (float)scrollViewer.VerticalOffset;
}
float visibleX = inverseZoom * (float)scrollViewer.HorizontalOffset;
float visibleY = inverseZoom * (float)scrollViewer.VerticalOffset; ;
float visibleW = Math.Min(Document.Size.X, inverseZoom * (float)scrollViewer.ViewportWidth);
float visibleH = Math.Min(Document.Size.Y, inverseZoom * (float)scrollViewer.ViewportHeight);
Rect2 visibleRect = new Rect2(visibleX, visibleY, visibleW, visibleH);
transform =
Matrix3x2.CreateTranslation(
translateX,
translateY) *
Matrix3x2.CreateScale(zoom);
Здесь вы можете привести пример: https://github.com/SebastianStehle/Win2DZoomTest
Чтобы быть уверенным, что мои глаза не сломаны, я увеличивал масштаб и записывал значения трансляции и масштабирования в файл. Вы можете увидеть это здесь:
https://www.dropbox.com/s/9ak6ohg4zb1mnxa/Test.png?dl=0
Значение столбцов следующее:
Столбец 1: Вычисленное значение масштабирования матрицы преобразования (M11) = ScrollViewer.ZoomFactor
Столбец 2: Вычисленное смещение x матрицы (см. Выше)
Столбец 3: Значение x результата матрицы * vector (500, 500), здесь: Colum1 * 500 + Column2
Вы видите, что значения матрицы выглядят хорошо, но при применении преобразования вы получаете этот небольшой прыжок вправо в течение нескольких миллисекунд. Одна из теорий заключалась в том, что область просмотра может измениться, поскольку полоса прокрутки становится видимой. Но это не так. Я также пробовал фиксированные значения здесь, сделал полосы прокрутки видимыми и даже создал собственный шаблон для scrollviewer без полос прокрутки.
Btw: Это перекрестный пост, я также задал здесь вопрос: https://github.com/Microsoft/Win2D/issues/125
Ответы
Ответ 1
Вы видите это поведение, потому что, когда вы увеличиваете масштаб больше размера ScrollViewer
, точка центра масштабирования перемещается. Чтобы исправить это, вам просто нужно подписаться на событие ScrollViewer
LayoutUpdated
и внутри обработчика, вручную сохраните его содержимое в центре.
private void ScrollViewer_LayoutUpdated(object sender, object e)
{
this.ScrollViewer.ChangeView(this.ScrollViewer.ScrollableWidth / 2, this.ScrollViewer.ScrollableHeight / 2, this.ScrollViewer.ZoomFactor, true);
}
Это должно исправить прыгающее движение по двум выделенным Rectangle
из Win2D.
Update
Чтобы доказать свою точку зрения, скачкообразное поведение, скорее всего, связано с необычным изменением значения translate x и/или y, когда размер содержимого превышает размер ScrollViewer
. Поэтому я написал код для регистрации этих значений на экране, как показано ниже -
...
this.Test1.Text += ((float)translateX).ToString() + " ";
this.Test2.Text += ((float)translateY).ToString() + " ";
session.Transform =
Matrix3x2.CreateTranslation(
(float)translateX,
(float)translateY) *
Matrix3x2.CreateScale((float)zoom);
![введите описание изображения здесь]()
Теперь взгляните на цифры на изображении выше. То, что я сделал, я пробовал масштабирование до тех пор, пока не возникла прыгающая сцена. См. Выделенное значение translate y. Это немного больше, чем его предыдущее значение, что противоречит тенденции к снижению.
Итак, чтобы исправить это, вам нужно будет пропустить эти необычные значения, вызванные ScrollViewer
.