Составные преобразования в WinRT

146

При объединении разнотипных преобразований важен порядок выполнения операций. Впрочем, на практике разные преобразования обычно применяются в более или менее стандартном порядке.

Предположим, требуется выполнить поворот, масштабирование и сдвиг элемента. Преобразование ScaleTransform обычно выполняется первым, потому что масштабирование удобнее определять для неповернутого элемента. Преобразование TranslateTransform завершает цепочку, потому что обычно вы не хотите, чтобы масштабирование и повороты влияли на величину сдвига. Получается, что преобразование RotateTransform должно выполняться в середине, а операции выполняются в порядке: масштабирование, поворот, сдвиг.

Если такой порядок вас устраивает, используйте класс CompositeTransform. Он содержит набор свойств, определенных для выполнения преобразований в следующем порядке:

  1. Масштабирование.

  2. Отклонение.

  3. Поворот.

  4. Перенос.

Список свойств:

Ниже приведена небольшая программа, использующая класс CompositeTransform для удобного объединения масштабирования с отклонением:

<Page ...>

    <Page.Resources>
        <Style x:Key="txbStyle" TargetType="TextBlock">
            <Setter Property="Text" Value="qabcdy" />
            <Setter Property="FontFamily" Value="Arial" />
            <Setter Property="FontSize" Value="180" />
            <Setter Property="HorizontalAlignment" Value="Center" />
            <Setter Property="VerticalAlignment" Value="Center" />
        </Style>
    </Page.Resources>

    <Grid Background="#FF1D1D1D">
        <!-- Теневой элемент TextBlock -->
        <TextBlock Foreground="Gray" Style="{StaticResource txbStyle}"
                   RenderTransformOrigin="0 1">
            <TextBlock.RenderTransform>
                <CompositeTransform ScaleY="1.2" SkewX="-65" />
            </TextBlock.RenderTransform>
        </TextBlock>

        <!-- TextBlock со стилевыми свойствами -->
        <TextBlock Style="{StaticResource txbStyle}" />
    </Grid>
</Page>

XAML создает экземпляры двух элементов TextBlock, свойства которых задаются стилем (включая свойство Text), и с точки зрения системы формирования макета оба экземпляра занимают одно и то же пространство. Однако нижний экземпляр окрашен в серый цвет и к нему применяются преобразования масштабирования и отклонения:

Использование преобразования CompositeTransform к тексту с засечками

Обратите внимание: свойству RenderTransformOrigin задается значение (0 1), то есть преобразование выполняется относительно левого нижнего угла. Однако вместо него также можно использовать точку (1, 1) или любую промежуточную точку; результат останется неизменным. Необходимо лишь то, чтобы два элемента TextBlock имели одинаковую нижнюю сторону. Масштабный коэффициент ScaleY, равный 1.2, увеличивает высоту тени на 20%. Значение SkewX, равное -65°, сдвигает нижнюю сторону влево, но поскольку на нижней стороне находится центр масштабирования и отклонения, верх сдвигается вправо.

Присмотревшись повнимательнее, вы заметите, что нижние края выносных элементов не совсем точно совпадают. Дело в том, что TextBlock опускается чуть ниже нижних выносных элементов. Для повышения точности совпадения можно задать свойству RenderTransformOrigin значение (0, 0.96).

А если потребуется добиться аналогичного эффекта с текстом, не имеющим нижних выносных элементов? Пример:

Использование преобразования CompositeTransform к тексту без засечек

Проблема в том, что для свойства RenderTransformOrigin требуется подобрать значение Y, равное относительной высоте текста над базовой линией, а эта характеристика зависит от шрифта. Для этого конкретного примера я экспериментировал до тех пор, пока не пришел к значению (0, 0.78), но оно подходит только для шрифта Times New Roman. Для создания универсального решения потребуется доступ к метрикам шрифтов, с которыми приложение Windows 8 может работать только через DirectX. Позже я покажу, как это делается.

Пройди тесты
Лучший чат для C# программистов