Определение пользовательских attrs не
Мне нужно реализовать свои собственные атрибуты, как в com.android.R.attr
ничего не нашел в официальной документации, поэтому мне нужна информация о том, как определить эти attrs и как их использовать из моего кода.
4 ответов
в настоящее время лучшая документация является источником. Вы можете взглянуть на него здесь (у attrs.в XML).
вы можете определить атрибуты в топ <resources>
или внутри <declare-styleable>
элемент. Если я собираюсь использовать attr более чем в одном месте, я помещаю его в корневой элемент. Внимание, все атрибуты одинаковые глобальное пространство имен. Это означает, что даже если вы создадите новый атрибут внутри <declare-styleable>
элемент его можно использовать вне его, и вы не можете создать другой атрибут с тем же именем другого типа.
An <attr>
элемент имеет два атрибута xml name
и format
. name
позволяет называть его чем-то, и вот как вы в конечном итоге ссылаетесь на него в коде, например,R.attr.my_attribute
. The может иметь разные значения в зависимости от типа атрибута, который вы хотите.
- reference - если он ссылается на другой идентификатор ресурса (e.g, " @color/my_color", "@layout/my_layout")
- цвета
- boolean
- измерение
- плавание
- целое
- строка
- фракция
- перечисление - обычно строго определен
- флаг - обычно строго определен
вы можете установить формат для нескольких типов с помощью |
, например, format="reference|color"
.
enum
атрибуты можно определить как следует:
<attr name="my_enum_attr">
<enum name="value1" value="1" />
<enum name="value2" value="2" />
</attr>
flag
атрибуты похожи, за исключением значений, которые необходимо определить, чтобы они могли быть бит Ored вместе:
<attr name="my_flag_attr">
<flag name="fuzzy" value="0x01" />
<flag name="cold" value="0x02" />
</attr>
в дополнение к атрибутам есть <declare-styleable>
элемент. Это позволяет определить атрибуты, которые может использовать пользовательское представление. Вы делаете это, указав <attr>
элемент, если он был ранее определен Не указан format
. Если вы хотите повторно использовать Android attr, например, android: gravity, то вы можете сделать это в name
, следующим образом.
пример пользовательского представления <declare-styleable>
:
<declare-styleable name="MyCustomView">
<attr name="my_custom_attribute" />
<attr name="android:gravity" />
</declare-styleable>
при определении пользовательских атрибутов в XML на пользовательском представлении вам нужно сделать несколько вещей. Сначала необходимо объявить пространство имен, чтобы найти атрибуты. Вы делаете это в корневом элементе layout. Обычно есть только xmlns:android="http://schemas.android.com/apk/res/android"
. Теперь вы также должны добавить xmlns:whatever="http://schemas.android.com/apk/res-auto"
.
пример:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:whatever="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<org.example.mypackage.MyCustomView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center"
whatever:my_custom_attribute="Hello, world!" />
</LinearLayout>
наконец, для доступа к этому пользовательскому атрибуту вы обычно делаете это в конструктор пользовательского представления следующим образом.
public MyCustomView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MyCustomView, defStyle, 0);
String str = a.getString(R.styleable.MyCustomView_my_custom_attribute);
//do something with str
a.recycle();
}
конец. :)
ответ Qberticus хорош, но одна полезная деталь отсутствует. Если вы реализуете их в библиотеке, замените:
xmlns:whatever="http://schemas.android.com/apk/res/org.example.mypackage"
С:
xmlns:whatever="http://schemas.android.com/apk/res-auto"
в противном случае приложение, использующее библиотеку, будет иметь ошибки выполнения.
ответ выше охватывает все в мельчайших деталях, кроме нескольких вещей.
во-первых, если нет стилей, то (Context context, AttributeSet attrs)
подпись метода будет использоваться для создания экземпляра предпочтения. В этом случае просто используйте context.obtainStyledAttributes(attrs, R.styleable.MyCustomView)
чтобы получить TypedArray.
во-вторых, он не охватывает, как иметь дело с ресурсами plaurals (количество строк). С ними нельзя справиться с помощью TypedArray. Вот фрагмент кода из моего SeekBarPreference, который устанавливает сводку предпочтение форматирование его значения в соответствии со значением предпочтения. Если xml для предпочтения устанавливает android: summary в текстовую строку или строку resouce, значение предпочтения форматируется в строку (в ней должен быть %d, чтобы забрать значение). Если android: summary установлен в ресурс plaurals, то он используется для форматирования результата.
// Use your own name space if not using an android resource.
final static private String ANDROID_NS =
"http://schemas.android.com/apk/res/android";
private int pluralResource;
private Resources resources;
private String summary;
public SeekBarPreference(Context context, AttributeSet attrs) {
// ...
TypedArray attributes = context.obtainStyledAttributes(
attrs, R.styleable.SeekBarPreference);
pluralResource = attrs.getAttributeResourceValue(ANDROID_NS, "summary", 0);
if (pluralResource != 0) {
if (! resources.getResourceTypeName(pluralResource).equals("plurals")) {
pluralResource = 0;
}
}
if (pluralResource == 0) {
summary = attributes.getString(
R.styleable.SeekBarPreference_android_summary);
}
attributes.recycle();
}
@Override
public CharSequence getSummary() {
int value = getPersistedInt(defaultValue);
if (pluralResource != 0) {
return resources.getQuantityString(pluralResource, value, value);
}
return (summary == null) ? null : String.format(summary, value);
}
- это просто приведено в качестве примера, однако, если вы хотите соблазниться установить резюме на экран предпочтений, то вам нужно позвонить
notifyChanged()
В поonDialogClosed
метод.
традиционный подход полон шаблонного кода и неуклюжей обработки ресурсов. Вот почему я сделал рамки Spyglass. Чтобы продемонстрировать, как это работает, приведем пример создания пользовательского представления, отображающего заголовок строки.
Шаг 1: Создайте пользовательский класс представления.
public class CustomView extends FrameLayout {
private TextView titleView;
public CustomView(Context context) {
super(context);
init(null, 0, 0);
}
public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs, 0, 0);
}
public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(attrs, defStyleAttr, 0);
}
@RequiresApi(21)
public CustomView(
Context context,
AttributeSet attrs,
int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(attrs, defStyleAttr, defStyleRes);
}
public void setTitle(String title) {
titleView.setText(title);
}
private void init(AttributeSet attrs, int defStyleAttr, int defStyleRes) {
inflate(getContext(), R.layout.custom_view, this);
titleView = findViewById(R.id.title_view);
}
}
Шаг 2: Определите строковый атрибут в values/attrs.xml
файл ресурсов:
<resources>
<declare-styleable name="CustomView">
<attr name="title" format="string"/>
</declare-styleable>
</resources>
Шаг 3: примените @StringHandler
аннотация к setTitle
метод, чтобы сообщить Spyglass framework для маршрутизации значения атрибута к этому методу, когда представление раздуто.
@HandlesString(attributeId = R.styleable.CustomView_title)
public void setTitle(String title) {
titleView.setText(title);
}
теперь, когда ваш класс имеет аннотацию Spyglass, структура Spyglass обнаружит ее во время компиляции и автоматически сгенерирует CustomView_SpyglassCompanion
класса.
Шаг 4: Используйте созданный класс в пользовательском представлении init
способ:
private void init(AttributeSet attrs, int defStyleAttr, int defStyleRes) {
inflate(getContext(), R.layout.custom_view, this);
titleView = findViewById(R.id.title_view);
CustomView_SpyglassCompanion
.builder()
.withTarget(this)
.withContext(getContext())
.withAttributeSet(attrs)
.withDefaultStyleAttribute(defStyleAttr)
.withDefaultStyleResource(defStyleRes)
.build()
.callTargetMethodsNow();
}
вот и все. Теперь, когда вы создаете экземпляр класса из XML, Spyglass companion интерпретирует атрибуты и делает требуемый вызов метода. Например, если мы надуваем следующий макет, то setTitle
будет вызван с "Hello, World!"
в качестве аргумента.
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:width="match_parent"
android:height="match_parent">
<com.example.CustomView
android:width="match_parent"
android:height="match_parent"
app:title="Hello, World!"/>
</FrameLayout>
платформа не ограничивается строковыми ресурсами, имеет множество различных аннотаций для обработки других типов ресурсов. Он также имеет аннотации для определения значений по умолчанию и для передачи значений-заполнителей, если ваши методы имеют несколько параметров.
посмотрите на репо Github для более информация и примеры.