UWP transparent LinearGradientBrush

У меня проблемы с моим приложением C # UWP.

<Grid VerticalAlignment="Bottom" Height="40" Grid.Row="3" Margin="0,0,0,-1">
  <Grid.Background>
    <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
        <GradientStop Color="#00000000" Offset="0"/>
        <GradientStop Color="{StaticResource stdBackgroundColor}" Offset="1"/>
    </LinearGradientBrush>
  </Grid.Background>
</Grid>

Этот фрагмент кода должен отображать прозрачное наложение внизу страницы, но вместо этого он создает черноватое наложение, как будто он добавляет прозрачные значения поверх существующего фона (который также имеет цвет stdBackgroundColor) и поэтому выглядит довольно странно (см. изображение ниже)

Проблема с наложением

Как добиться прозрачного наложения на контент (например, ScrollViewer) без этого эффекта?


person user3079834    schedule 01.02.2016    source источник
comment
Это выглядит немного забавно, и я не уверен, что правильно визуализирую ваш предполагаемый результат. Поскольку для вашего первого смещения альфа-канал установлен на 0, и я не уверен, что такое stdBackgroundColor, есть ли у вас пример желаемого эффекта?   -  person Chris W.    schedule 01.02.2016
comment
Ожидаемый результат на картинке должен заключаться в том, что ничего не видно, но все то же Color (в данном случае это stdBackgroundColor, то есть # FFa1a1a1). Когда за сеткой сверху находится контент, он должен постепенно переходить в цвет фона (stdBackgroundColor).   -  person user3079834    schedule 01.02.2016


Ответы (1)


Заявление об отказе от ответственности, я на работе, и у меня нет доступа к платформе, на которой я могу протестировать этот код, но, судя по тому, что я искал, он должен работать.

Основная проблема заключается в смешивании цветов, а именно в том, что мы хотим плавно переходить от полной альфы к любому произвольному цвету. Проблема с началом с Color.Transparent заключается в том, что вы получите белую полосу, в то время как альфа-канал будет прогрессировать больше, чем другие компоненты. Аналогичная проблема возникает с #00000000, поскольку у него есть черная полоса. Решение состоит в том, чтобы начать с версии вашего цвета, у которой непрозрачность установлена ​​на 0. То, как мы это делаем, немного отличается в зависимости от того, какую версию приложения на основе XAML вы разрабатываете, и мне сложно их придерживаться. В UWP у нас нет маски непрозрачности, и мы не можем создать градиент только на основе непрозрачности. Осталось только использовать IValueConverter.

Свойство Color в GradientStop - это Color, а не Brush, так как это чрезмерно усложнит систему рендеринга. Итак, первый шаг, который нам нужен, - это IValueConverter, который берет любое Color и удаляет альфа-значение:

public class TransparentColorConverter : IValueConverter
{
    public object Convert(object value, Type targetType,
                          object parameter, string language)
    {
        Color convert = (Color) value; // Color is a struct, so we cast
        return Color.FromArgb(0, convert.R, convert.G, convert.B);
    }

    public object ConvertBack(object value, Type targetType,
                              object parameter, string language)
    {
         throw new NotImplementedException();
    }
}

Следующая задача - создать привязку, для которой мы можем использовать этот цвет. Объект привязки позволяет нам указать Source, которым может быть любой объект, который мы передаем. ElementName не будет работать, потому что на ресурсы ссылаются по ключу, а не по имени.

<LinearGradientBrush x:Key="OpacityGradientBrush" StartPoint="0,0" EndPoint="0,1">
  <GradientStop Color="{Binding Source={StaticResource stdBackgroundColor},
                       Converter={StaticResource TransparentColorConverter}}" Offset="0"/>
  <GradientStop Color="{StaticResource stdBackgroundColor}" Offset="1"/>
</LinearGradientBrush>

Конечно, не забудьте указать TransparentColorConverter в Resources, чтобы вы могли сослаться на него здесь. Лично я бы предпочел не использовать преобразователи, но в данном случае я считаю, что это оправдано.

ПРИМЕЧАНИЕ. Мы используем Source в привязке, чтобы можно было ссылаться на статический ресурс. Если бы у нас было свойство, к которому мы могли бы привязаться, мы могли бы вместо этого использовать Path.


Приведенный ниже ответ действителен для WPF, но не для UWP. Я бы хотел, чтобы Microsoft перестала пересматривать ту же концепцию несовместимыми способами, но это мир, в котором мы живем.

Исправление моего ответа на основе этого ответа

Вы хотите изменить LinearGradientBrush, чтобы использовать свойство Opacity, а не цвет #00000000. Проблема в том, что он интерполируется от основного черного к желаемому цвету. Чтобы добиться желаемого эффекта, вам нужно настроить кисть с маской непрозрачности следующим образом:

<LinearGradientBrush x:Key="OpacityGradientBrush" StartPoint="0,0" EndPoint="0,1">
  <GradientStop Color="#00FFFFFF" Offset="0"/>
  <GradientStop Color="#FFFFFFFF" Offset="1"/>
</LinearGradientBrush>

Затем в коде, к которому вам нужно применить маску непрозрачности, вы ссылаетесь на нее следующим образом:

<Grid VerticalAlignment="Bottom" Height="40" Grid.Row="3"
    Background="{StaticResource stdBackgroundColor}"
    OpacityMask="{StaticResource OpacityGradientBrush} Margin="0,0,0,-1"/>

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

person Berin Loritsch    schedule 01.02.2016
comment
Звучит разумно, но, к сожалению, я получаю сообщение об ошибке The property 'Opacity' was not found in type 'GradientStop'. , так как же вы реализовали Opacity в LinearGradientBrush? - person user3079834; 03.02.2016
comment
Я изменил код, чтобы обеспечить тот же эффект, но не использовал непрозрачность в ограничителе градиента. Надеюсь, это сработает для вас. Комментарии о смешивании цветов по-прежнему актуальны, и я их не менял. - person Berin Loritsch; 03.02.2016
comment
К сожалению, ответ, с которым вы связались, предназначен только для WPF, но не для приложений UWP С #. В UWP нет OpacityMask (пока) - person user3079834; 05.02.2016
comment
Единственное, что я могу сейчас придумать, - это использовать ValueConverter, чтобы взять ваш цвет и удалить альфа (установив альфа на 0 и скопировав значения RGB в новый цвет). Конечно, это применимо только к начальному значению. Почему у Microsoft не может быть только один API? Очень сложно точно сказать, какие функции и в каком вкусе XAML. - person Berin Loritsch; 05.02.2016
comment
В частности, для OpacityMask я еще не смотрел видео, но, возможно, теперь есть способ, поскольку он находится на Channel9: Как применить маску непрозрачности к изображению в универсальных приложениях с помощью Direct2D channel9.msdn.com/Blogs/OneCode / - person Dmitry Lyalin; 04.09.2016