Доступ к attrs в AttributeSet для пользовательских компонентов - PullRequest
20 голосов
/ 29 ноября 2011

У меня есть пользовательский компонент, содержащий два TextView, в которых включен метод настройки размера (эти два текстовых представления пропорциональны примерно 1: 2). Поскольку это подкласс RelativeLayout, он не имеет атрибута textSize, но мне интересно, можно ли все же установить атрибут android:textSize в экземпляре XML для этого компонента, а затем получить textSize атрибут из AttributeSet для использования с моим пользовательским методом setSize() в конструкторе.

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

Ответы [ 2 ]

70 голосов
/ 29 ноября 2011

да, это возможно;

давайте предположим, что у вашего объявления RelativeLayout (в xml) есть textSize, определенный с 14sp:

android:textSize="14sp"

В конструкторе вашего пользовательского представления (того, который принимает в AttributeSet), вы можете получитьатрибуты из пространства имен Android как таковые:

String xmlProvidedSize = attrs.getAttributeValue("http://schemas.android.com/apk/res/android", "textSize");

Значением xmlProvidedSize будет что-то вроде этого "14.0sp", и, возможно, с небольшим изменением String вы можете просто извлечь числа.


Другой вариант объявить свой собственный набор атрибутов был бы немного длинным, но это также возможно.

Итак, у вас есть свой пользовательский вид, и ваши TextViews объявили что-то вроде этого:

public class MyCustomView extends RelativeLayout{

    private TextView myTextView1;
    private TextView myTextView2;

// rest of your class here

great ...

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

public MyCustomView(Context context, AttributeSet attrs){   
    super(context, attrs);
    init(attrs, context);  //nice, clean method to instantiate your TextViews// 
}

хорошо, давайте посмотрим, чтоМетод init () теперь:

private void init(AttributeSet attrs, Context context){
    // do your other View related stuff here //


    TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.MyCustomView);
    int xmlProvidedText1Size = a.int(R.styleable.MyCustomView_text1Size);
    int xmlProvidedText2Size = a.int(R.styleable.MyCustomView_text2Size);

    myTextView1.setTextSize(xmlProvidedText1Size);
    myTextView2.setTextSize(xmlProvidedText2Size);

    // and other stuff here //
}

Вы, вероятно, задаетесь вопросом, где используются R.styleable.MyCustomView, R.styleable.MyCustomView_text1Size и R.styleable.MyCustomView_text2Size приходят из;Позвольте мне подробнее остановиться на них.

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

Итак, давайте посмотрим, как вы объявляете эти пользовательские атрибуты, как вы просили: Вот весь мой attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="MyCustomView">
        <attr name="text1Size" format="integer"/>
        <attr name="text2Size" format="integer"/>
    </declare-styleable>
</resources>

Теперь вы можетеустановить размер вашего TextViews в вашем XML, но НЕ без объявления пространства имен в вашем макете, вот как:

<com.my.app.package.MyCustomView
    xmlns:josh="http://schemas.android.com/apk/res-auto"
    android:id="@+id/my_custom_view_id"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    josh:text1Size="15"
    josh:text2Size="30"     
    />

Обратите внимание, как я объявил пространство имен «josh» в качестве первой строки внабор атрибутов вашего CustomView.

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

1 голос
/ 08 февраля 2017

Принятый ответ немного длинный.Вот сокращенная версия, которой, я надеюсь, будет легко следовать.Чтобы добавить атрибут textSize (или что-либо, что использует dp / sp) к вашему пользовательскому представлению, выполните следующие шаги:

1.Создайте пользовательский атрибут

. Создайте (или добавьте следующий раздел) в attrs.xml .Обратите внимание на формат dimension.

<resources>
    <declare-styleable name="CustomView">
        <attr name="textSize" format="dimension" />
    </declare-styleable>
</resources>

2.Установите атрибут в макете xml.

Обратите внимание на пользовательское пространство имен app.

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:app="http://schemas.android.com/apk/res-auto"
                android:layout_width="match_parent"
                android:layout_height="match_parent">

    <com.example.myproject.CustomView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:textSize="20sp" /> 

</RelativeLayout>

3.Получите значение атрибута в вашем пользовательском представлении

Обратите внимание на использование getDimensionPixelSize.В вашем собственном представлении просто работайте с пикселями.См. этот ответ , если вам нужно преобразовать в другое измерение.

public class CustomView extends View {

    private float mTextSize; // pixels

    public CustomView(Context context, AttributeSet attrs) {
        super(context, attrs);
        TypedArray a = context.getTheme().obtainStyledAttributes(
                attrs, R.styleable.CustomView, 0, 0);
        try {
            mTextSize = a.getDimensionPixelSize(R.styleable.CustomView_textSize, 0);
        } finally {
            a.recycle();
        }
    }

    /**
     * @param size in SP units
     */
    public void setTextSize(int size) {
        mTextSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
                size, getResources().getDisplayMetrics());
        mTextPaint.setTextSize(mTextSize);
        invalidate();
        requestLayout();
    }

    // ...
}

Примечания

...