Получение IAttributeSet из процесса просмотра инфляции - PullRequest
0 голосов
/ 21 января 2020

Я работаю над проектом, который основывается на добавлении пользовательского атрибута в их элементы Android. Так же, как MvvmCross 'app:MvxBind. Не существует пользовательских классов представлений, поскольку идея заключается в том, что пользователь может использовать обычные Android представления.

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

У меня есть рабочий пример, использующий LayoutInflater.IFactory, однако, для этого мне нужно установить свой собственный LayoutInflater / factory, который, если пользователь использует библиотеку, такую ​​как MvvmCross, вызывает проблемы, так как только одна фабрика может быть установлена ​​одновременно.

Я ищу способ, которым я могу получить объект IAttributeSet всякий раз, когда представление завышено проверить мой атрибут, который не мешает стандартному LayoutInflater или LayoutInflater из других библиотек. Или, если есть какой-либо способ получить мой атрибут после того, как представление было завышено.

Заранее спасибо!

Редактировать

Я хочу быть возможность получить значение MyAttribute из представления без разделения на подклассы или создания пользовательских представлений. Это легко сделать с помощью LayoutInflater.IFactory, но этот метод мешает работе таких библиотек, как MvvmCross.

<TextView
    android:layout_width="wrap_content"
    android:layout_width="wrap_content"
    app:MyAttribute="My attribute value" />

Ответы [ 2 ]

0 голосов
/ 11 февраля 2020

Мне наконец-то удалось это выяснить.

Решение, не относящееся к MvvmCross

Я наткнулся на статью под названием «Раздувание макета: друг или враг?». Я думаю, это ссылка , но во время публикации этого ответа она не работает.

Автор провел потрясающую беседу о LayoutInflater и о том, как он изменил процесс Android LayoutInflater. чтобы он мог перехватить его для своей библиотеки Каллиграфия . Полученное в результате решение называется ViewPump и написано в Kotlin.

Я написал библиотеку ViewPump на Xamarin для использования с проектами, не относящимися к MvvmCross: https://github.com/lewisbennett/viewpump.

Решение MvvmCross

MvvmCross использует решение на основе InflationX 'ViewPump для выполнения привязки, и мы можем получить к нему доступ, сначала создав следующие классы:

public class BindingBuilder : MvxAndroidBindingBuilder
{
    protected override IMvxAndroidViewBinderFactory CreateAndroidViewBinderFactory()
    {
        return new ViewBinderFactory();
    }
}

public class ViewBinderFactory : IMvxAndroidViewBinderFactory
{
    public IMvxAndroidViewBinder Create(object source)
    {
        return new ViewBinder(source);
    }
}

public class ViewBinder : MvxAndroidViewBinder
{
    public override void BindView(View view, Context context, IAttributeSet attrs)
    {
        base.BindView(view, context, attrs);

        // Do your intercepting here.
    }

    public ViewBinder(object source)
        : base(source)
    {
    }
}

Затем в ваш класс MvxAndroidSetup или MvxAppCompatSetup добавьте следующее:

protected override MvxBindingBuilder CreateBindingBuilder()
{
    return new BindingBuilder();
}

Готово! Надеюсь, это кому-нибудь поможет:)

0 голосов
/ 22 января 2020

Я не уверен, понимаю ли я, что вы имеете в виду. Пожалуйста, обратитесь к следующему:

вы можете создать пользовательское представление и определить его атрибут в attrs.xml, и когда он создается из макета XML, все атрибуты в теге XML читаются из пакета ресурсов и передается в конструктор представления как, например, IAttributeSet

, здесь пользовательское представление с именем IconView

public class IconView : View
{
}

определяет некоторые атрибуты в attrs.xml ( Ресурсы / значения / атрибуты. xml)

<declare-styleable name="IconView">
  <attr name="bg_color" format="color" />
  <attr name="src" format="integer" />
  <attr name="showIconLabel" format="boolean" />
  <attr name="iconLabelTextColor" format="color" />
  <attr name="iconLabelText" format="string" />
</declare-styleable>

тогда мы можем обработать атрибуты в конструкторе представления при его создании (здесь определяется метод Initialize) :

public IconView(Context context) : base(context)
{
  Initialize(context);
}

public IconView(Context context, IAttributeSet attrs) : base(context, attrs)
{
  Initialize(context, attrs);
}

private void Initialize(Context context, IAttributeSet attrs = null)
{
  if (attrs != null)
  {
    // Contains the values set for the styleable attributes you declared in your attrs.xml
    var array = context.ObtainStyledAttributes(attrs, Resource.Styleable.IconView, 0, 0);

    iconBackgroundColor = array.GetColor(Resource.Styleable.IconView_bg_color, Color.Gray);
    iconLabelTextColor = array.GetColor(Resource.Styleable.IconView_iconLabelTextColor, Color.ParseColor("#D9000000"));
    _labelText = array.GetString(Resource.Styleable.IconView_iconLabelText);
    _showIconLabel = array.GetBoolean(Resource.Styleable.IconView_showIconLabel, false);

    var iconResId = array.GetResourceId(Resource.Styleable.IconView_src, 0);
    if (iconResId != 0) // If the user actually set a drawable
        _icon = AppCompatDrawableManager.Get().GetDrawable(context, iconResId);

    // If the users sets text for the icon without setting the showIconLabel attr to true
    // set it to true for the user anyways
    if (_labelText != null) 
        _showIconLabel = true;

    // Very important to recycle the array after use
    array.Recycle();
  }

     ...
}

Вы можете обратиться к нему для более подробной информации сделать пользовательский вид

...