Xamarin Forms Android Autosize Label TextCompat pre android 8 не изменяет размер текста автоматически - PullRequest
0 голосов
/ 12 июля 2020

Я хочу использовать функцию автоматического изменения размера android текстовых представлений в моем решении форм xamarin, чтобы по мере увеличения длины текста размеры шрифта сокращались, чтобы никогда не выходить за границы метки и не усекаться. Для этого я создал настраиваемый элемент управления Label и добавил настраиваемое средство визуализации android. Не работает в Android 7 и ниже. Он работает в Android 8 и выше.

Согласно docs поддержка автоматического изменения размера была введена в android 8, но может поддерживаться обратно до Android 4 с помощью AppCompat. v4. Однако моя настраиваемая визуализированная метка просто отображает размер шрифта по умолчанию в Android pre 8. Он отлично работает на 8+ устройствах, размер текста метки изменяется по мере необходимости, чтобы не выходить за границы. В принятом ответе на этот вопрос с аналогичной проблемой на нативном android говорится, что это может быть связано с отсутствием установки ширины и высоты, я пробовал явно установить widthrequest и heightrequest, и это не меняется что-нибудь. Также установка maxlines = 1 ничего не меняет. Альтернативный тред предполагает, что виноваты нестандартные шрифты. Я создал решение ванильных форм, используя шрифт устройства по умолчанию, и получил тот же эффект.

Мой код:

internal class AutosizeLabelRenderer : LabelRenderer
{
    #region constructor

    public AutosizeLabelRenderer(Context context) : base(context)
    {
    }

    #endregion

    #region overridable

    protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
    {
        base.OnElementChanged(e);

        if (e.NewElement == null || !(e.NewElement is AutoSizeLabel autoLabel) || Control == null) { return; }

        TextViewCompat.SetAutoSizeTextTypeUniformWithConfiguration(Control, autoLabel.AutoSizeMinTextSize,
                autoLabel.AutoSizeMaxTextSize, autoLabel.AutoSizeStepGranularity, (int)ComplexUnitType.Sp);
        
    }

    #endregion
}

public class AutoSizeLabel : Label
{
    public int AutoSizeMaxTextSize
    {
        get => (int)GetValue(AutoSizeMaxTextSizeProperty);
        set => SetValue(AutoSizeMaxTextSizeProperty, value);
    }

    public static readonly BindableProperty AutoSizeMaxTextSizeProperty = BindableProperty.Create(
        nameof(AutoSizeMaxTextSize),        // the name of the bindable property
        typeof(int),     // the bindable property type
        typeof(AutoSizeLabel));      // the default value for the property

    public int AutoSizeMinTextSize
    {
        get => (int)GetValue(AutoSizeMinTextSizeProperty);
        set => SetValue(AutoSizeMinTextSizeProperty, value);
    }

    public static readonly BindableProperty AutoSizeMinTextSizeProperty = BindableProperty.Create(
        nameof(AutoSizeMinTextSize),        // the name of the bindable property
        typeof(int),     // the bindable property type
        typeof(AutoSizeLabel));      // the default value for the property


    public int AutoSizeStepGranularity
    {
        get => (int)GetValue(AutoSizeStepGranularityProperty);
        set => SetValue(AutoSizeStepGranularityProperty, value);
    }

    public static readonly BindableProperty AutoSizeStepGranularityProperty = BindableProperty.Create(
        nameof(AutoSizeStepGranularity),        // the name of the bindable property
        typeof(int),     // the bindable property type
        typeof(AutoSizeLabel));      // the default value for the property

    //
}

Не работает: Android 7 - текст не усадка

enter image description here

Working as expected: Android 8 and above

enter image description here

Xaml for above images:

          

Ответы [ 2 ]

1 голос
/ 13 июля 2020

Размер шрифта TextView изменяется вместе с размером элемента управления, что является новым в Android 8.0 (API26), поэтому при использовании предыдущей версии необходимо учитывать проблемы совместимости. Вы можете изменить TextView на AppCompatTextView.

Поменяйте

protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
  {
     base.OnElementChanged(e);
     if (e.NewElement == null || !(e.NewElement is AutoSizeLabel autoLabel) || Control == null) { return; }
        AppCompatTextView appCompatTextView = new AppCompatTextView(_context);
        appCompatTextView.Text = Element.Text;
        appCompatTextView.SetMaxLines(1);
        SetNativeControl(appCompatTextView);                       
        TextViewCompat.SetAutoSizeTextTypeUniformWithConfiguration(Control,autoLabel.AutoSizeMinTextSize,autoLabel.AutoSizeMaxTextSize, autoLabel.AutoSizeStepGranularity, (int)ComplexUnitType.Sp);
  }
0 голосов
/ 14 июля 2020

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

Различия между моим ответом и ответом Лео:

  1. Создание нового собственного элемента управления в области видимости, как предложил Лео, означало, что он работал некоторое время, но был удален сборщиком мусора и вызывал исключение при возврате на страницу после перехода. Чтобы исправить это, мне нужно было переопределить свойство ManageNativeControlLifetime, чтобы оно возвращало false, а затем вручную управлять удалением объекта, переопределив метод удаления и вызвав Control.RemoveFromParent () ;. Этот совет исходит от сотрудника xamarin в этой ветке .

  2. Контекст форматирования и привязки не наследуется автоматически при создании нового собственного элемента управления и должен быть установлен вручную . Мне нужно было добавить их в соответствии с моими потребностями, используя синтаксис привязки android Speci c. Возможно, вам понадобится добавить другой код форматирования и привязки в зависимости от ваших потребностей, я просто задаю здесь цвет шрифта, гравитацию и контекст привязки.

Я установил контекст привязки с помощью appCompatTextView.SetBindingContext(autoLabel.BindingContext) ;

После установки контекста привязки мне нужно было добавить новое строковое свойство в мой класс XF AutoSizeLabel для передачи через XAML, а затем использовать его для установки пути привязки для соответствующего свойства (в моем случае текст свойство). Если требуется более одной привязки, вам нужно будет добавить несколько новых свойств пути привязки для каждого необходимого свойства. Я установил определенную привязку c следующим образом:

appCompatTextView.SetBinding("Text", new Binding(autoLabel.TextBindingPath));

Чтобы облегчить это в моих Xamarin Forms Xaml, мой Xaml изменился с <Label Text="{Binding MyViewModelPropertyName}" /> на <controls:AutoSizeLabel TextBindingPath="MyViewModelPropertyName" />

Вот полный код рендерера:

    protected override bool ManageNativeControlLifetime => false;

    protected override void Dispose(bool disposing)
    {
        Control.RemoveFromParent();
        base.Dispose(disposing);
    }

    private AppCompatTextView appCompatTextView;

    protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
    {
        base.OnElementChanged(e);

        if (e.NewElement == null || !(e.NewElement is AutoSizeLabel autoLabel) || Control == null) { return; }

        //v8 and above supported natively, no need for the extra stuff below.
        if (DeviceInfo.Version.Major >= 8)
        {
            Control?.SetAutoSizeTextTypeUniformWithConfiguration(
                autoLabel.AutoSizeMinTextSize,
                autoLabel.AutoSizeMaxTextSize, autoLabel.AutoSizeStepGranularity,
                (int)ComplexUnitType.Sp);
            return;
        }

            appCompatTextView = new AppCompatTextView(Context);
            appCompatTextView.SetTextColor(Element.TextColor.ToAndroid());
            appCompatTextView.SetMaxLines(1);
            appCompatTextView.Gravity = GravityFlags.Center;
            appCompatTextView.SetBindingContext(autoLabel.BindingContext);
            appCompatTextView.SetBinding("Text", new Binding(autoLabel.TextBindingPath));
            SetNativeControl(appCompatTextView);
        

        TextViewCompat.SetAutoSizeTextTypeUniformWithConfiguration(Control, autoLabel.AutoSizeMinTextSize, autoLabel.AutoSizeMaxTextSize, autoLabel.AutoSizeStepGranularity, (int)ComplexUnitType.Sp);
    }
...