Подтвердить что ты не робот

Масштабирование размера шрифта в универсальном приложении Windows Store (W8.1 + WP8.1)

Как масштабировать текст в Windows Store Universal App (W8.1 + WP8.1)? В принципе, приложение должно выглядеть одинаково независимо от того, какое устройство/разрешение используется. Текущая ситуация заключается в том, что макет (макет динамической сетки) и изображения хорошо масштабируются, за исключением текста (размер шрифта).

Отображаемый текст выглядит хорошо для WVGA-разрешения (480 × 800), но невероятно мало для разрешения 1080p.

Я уже много читал Рекомендации по масштабированию плотности пикселей или Рекомендации по поддержке нескольких размеров экрана

Но я до сих пор не знаю, как масштабировать текст, чтобы оставаться читаемым, независимо от разрешения экрана /DPI.

Конечно, я мог бы написать класс, который использует свойство DisplayInformation.ResolutionScale для преобразования размера шрифта в присваиваемое значение.

Пример:

  • FontSize 16 на WVGA с ScaleFactor 1x равен FontSize 16
  • FontSize 16 на WXGA с ScaleFactor 1.6x равен FontSize 25,6
  • FontSize 16 на 720p с ScaleFactor 1.5x равен FontSize 24
  • FontSize 16 на 1080p с ScaleFactor 2.25x равен FontSize 36

Но я не уверен, что это будет работать для всех сценариев. Есть ли лучший способ сделать это? Я думал, что такая общая задача может быть выполнена с некоторой функциональностью.

Отказ от ответственности: это (надеюсь) не "позвольте мне ответить на этот вопрос для вас". Я нашел массу страниц, которые касаются масштабирования, но все они покрывают макет или изображения. Но я не мог найти ничего о масштабировании размера шрифта. Пожалуйста, простите меня, если я что-то пропустил.


Изменить: Боюсь, я не смог четко выразить эту проблему: (WVGA слева, 1080p справа) WVGA vs. 1080p
4b9b3361

Ответ 1

То, что я сделал для моего приложения Windows Store, было привязать свойство FontSize к высоте страницы и преобразовать значение (вам придется немного поиграть, пока не найдете правильное значение для вашего случая).

<TextBlock Grid.Row="0" Text="Some Text" 
FontSize="{Binding ElementName=pageRoot, Path=ActualHeight, 
Converter={StaticResource PageHeightConverter}, ConverterParameter='BodyFontSize'}" />

И вот мой класс конвертера

    class PageHeightConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language)
    {
        switch ((string)parameter)
        {
            case "HeroImage":
                return ((((double)value) * 2) / 3);
            case "TitleFontSize":
                return (int)((double)value / 40);
            case "BodyFontSize":
                return (int)((double)value / 60);
            default:
                return 0;
        }
    }
}

Это не идеально, но работает очень хорошо, пока я не найду более мягкое решение.

Ответ 2

Я обнаружил, что использование метода IValueConverter очень хорошо работает при использовании в сочетании с ResolutionScale свойство:

class ScaleConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language)
    {
        var resolutionScale = (int)DisplayInformation.GetForCurrentView().ResolutionScale / 100.0;
        var baseValue = int.Parse(parameter as string);
        var scaledValue = baseValue * resolutionScale;
        if (targetType == typeof(GridLength))
            return new GridLength(scaledValue);
        return scaledValue;
    }
}

Обратите внимание, что если вы используете больше, чем FontSize (поскольку я также использую его для ColumnDefinition.Width), вам нужно будет обрабатывать возвращаемый правильный вывод типа.

Использование моего XAML выглядит примерно так:

<TextBlock Text="string" FontSize="{Binding ElementName=root, Path=ActualHeight, Converter={StaticResource ScaleConverter}, ConverterParameter='30'}" />

И чтобы просто завершить решение, для каждой страницы XAML, в которой вы используете это, вам необходимо включить следующее, заменив SwapChainBackgroundPanel на любой класс, который вы используете, и правильно определите пространство имен xml:

<SwapChainBackgroundPanel.Resources>
    <local:ScaleConverter x:Key="ScaleConverter"></local:ScaleConverter>
</SwapChainBackgroundPanel.Resources>

Ответ 3

WinRT может автоматически масштабировать все, что работает поверх него, и будет делать это на основе плотности пикселей дисплея. В Windows 8.0 он использовался для масштабирования в 100%, 140% и 180%. Более новая версия может иметь еще более масштабные коэффициенты. Я не считаю, что вы можете отказаться от этого масштабирования.

Если вы не заинтересованы в использовании встроенного масштабирования, который работает на системном уровне, то вы в значительной степени вынуждены делать все сами. Вы можете масштабировать текст вручную, задав размер шрифта, или вы можете использовать силу преобразований для масштабирования вашего текста или всего пользовательского интерфейса.

Ответ 4

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

Если вам нужен точный контент на каждом экране (т.е. 6-дюймовый телефон просто показывает взорванную версию 4-дюймового телефона, вместо того, чтобы показывать на 50% больше контента), используйте ViewBox, чтобы масштабировать ваше приложение. Однако это не очень хороший пользовательский интерфейс.

Ответ 5

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

Мой iValueConverter выглядит следующим образом:

class FontSizeConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
    {
    var display = Helpers.ScreenResolution();
    var height = display.Height;
    var oldFontSize = (int)value;
    if(oldFontSize == null) return;

    // Calculate the new Fontsize based on the designed Fontsize
    // and design display size in Visual Studio designer...
    var newFontSize = (int)Math.Round((oldFontSize / 768.0) * height, 0);
    return newFontSize;
}

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

Надеюсь, это поможет...