Как объявить элемент Android UI с помощью XML?
Объявление пользовательского элемента пользовательского интерфейса Android с использованием XML
Ответ 1
В Руководстве разработчика Android есть раздел Построение пользовательских компонентов. К сожалению, обсуждение атрибутов XML охватывает только объявление элемента управления внутри файла макета, а не обработку значений внутри инициализации класса. Эти шаги заключаются в следующем:
1. Объявлять атрибуты в values\attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="MyCustomView">
<attr name="android:text"/>
<attr name="android:textColor"/>
<attr name="extraInformation" format="string" />
</declare-styleable>
</resources>
Обратите внимание на использование неквалифицированного имени в теге declare-styleable
. Нестандартные атрибуты андроида, такие как extraInformation
, должны иметь тип объявления. Теги, объявленные в суперклассе, будут доступны в подклассах без необходимости их обновления.
2. Создание конструкторов
Поскольку существует два конструктора, которые используют инициализацию AttributeSet
, удобно создать отдельный метод инициализации для вызываемых конструкторов.
private void init(AttributeSet attrs) {
TypedArray a=getContext().obtainStyledAttributes(
attrs,
R.styleable.MyCustomView);
//Use a
Log.i("test",a.getString(
R.styleable.MyCustomView_android_text));
Log.i("test",""+a.getColor(
R.styleable.MyCustomView_android_textColor, Color.BLACK));
Log.i("test",a.getString(
R.styleable.MyCustomView_extraInformation));
//Don't forget this
a.recycle();
}
R.styleable.MyCustomView
- это автогенерированный ресурс int[]
, где каждый элемент является идентификатором атрибута. Атрибуты генерируются для каждого свойства в XML, добавляя имя атрибута к имени элемента. Например, R.styleable.MyCustomView_android_text
содержит атрибут android_text
для MyCustomView
. Атрибуты затем могут быть извлечены из TypedArray
с использованием различных функций get
. Если атрибут не определен в определенном в XML, возвращается null
. За исключением, конечно, если возвращаемый тип является примитивным, в этом случае возвращается второй аргумент.
Если вы не хотите извлекать все атрибуты, можно создать этот массив вручную. Идентификатор стандартных атрибутов Android включен в android.R.attr
, тогда как атрибуты для этого проекта находятся в R.attr
.
int attrsWanted[]=new int[]{android.R.attr.text, R.attr.textColor};
Обратите внимание, что вы должны не использовать что-либо в android.R.styleable
, в соответствии с этот поток он может изменяться в будущее. В документации все еще есть просмотр всех этих констант в одном месте.
3. Используйте его в файлах макетов, таких как layout\main.xml
Включить объявление пространства имен xmlns:app="http://schemas.android.com/apk/res-auto"
в элемент xml верхнего уровня. Пространства имен предоставляют метод, позволяющий избежать конфликтов, которые иногда возникают, когда разные схемы используют одни и те же имена элементов (см. эту статью для получения дополнительной информации). URL-адрес - это просто способ однозначной идентификации схем - ничего не нужно размещать на этом URL. Если это ничего не делает, это связано с тем, что вам действительно не нужно добавлять префикс пространства имен, если только вам не нужно разрешать конфликт.
<com.mycompany.projectname.MyCustomView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/transparent"
android:text="Test text"
android:textColor="#FFFFFF"
app:extraInformation="My extra information"
/>
Ссылка на пользовательский вид с использованием полного имени.
Пример LabelView для Android
Если вы хотите получить полный пример, посмотрите на образец представления метки андроида.
TypedArray a=context.obtainStyledAttributes(attrs, R.styleable.LabelView);
CharSequences=a.getString(R.styleable.LabelView_text);
<declare-styleable name="LabelView">
<attr name="text"format="string"/>
<attr name="textColor"format="color"/>
<attr name="textSize"format="dimension"/>
</declare-styleable>
<com.example.android.apis.view.LabelView
android:background="@drawable/blue"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
app:text="Blue" app:textSize="20dp"/>
Это содержится в LinearLayout
с атрибутом пространства имен: xmlns:app="http://schemas.android.com/apk/res-auto"
Ссылки
Ответ 2
Отличная ссылка. Благодарю! Кроме того:
Если у вас есть проект библиотеки, который объявил пользовательские атрибуты для пользовательского представления, вы должны объявить пространство имен проектов, а не его библиотеку. Например:
Учитывая, что в библиотеке есть пакет "com.example.library.customview", а рабочий проект имеет пакет "com.example.customview", то:
Ошибка работы (показывает ошибку): идентификатор ресурса не найден для атрибута 'newAttr' в пакете 'com.example.library.customview' "):
<com.library.CustomView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res/com.example.library.customview"
android:id="@+id/myView"
app:newAttr="value" />
Будет работать:
<com.library.CustomView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res/com.example.customview"
android:id="@+id/myView"
app:newAttr="value" />
Ответ 3
Дополнение к большинству голосующих ответов.
obtainStyledAttributes()
Я хочу добавить несколько слов об использовании getStyledAttributes() при создании пользовательского представления с использованием атрибутов android: xxx prdefined. Особенно, когда мы используем TextAppearance.
Как упоминалось в "2. Создание конструкторов", пользовательское представление получает AttributeSet при его создании. Основное использование мы можем увидеть в исходном коде TextView (API 16).
final Resources.Theme theme = context.getTheme();
// TextAppearance is inspected first, but let observe it later
TypedArray a = theme.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.TextView, defStyle, 0);
int n = a.getIndexCount();
for (int i = 0; i < n; i++)
{
int attr = a.getIndex(i);
// huge switch with pattern value=a.getXXX(attr) <=> a.getXXX(a.getIndex(i))
}
a.recycle();
Что мы можем увидеть здесь?
obtainStyledAttributes(AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes)
Набор атрибутов обрабатывается темой в соответствии с документацией. Значения атрибутов скомпилируются поэтапно. Первые атрибуты заполняются из темы, затем значения заменяются значениями из стиля, и, наконец, точные значения из XML для специального экземпляра вида заменяют другие.
Массив запрашиваемых атрибутов - com.android.internal.R.styleable.TextView
Это обычный массив констант. Если мы запрашиваем стандартные атрибуты, мы можем создать этот массив вручную.
Что не упоминается в документации - порядок результата. Элементы TypedArray.
Когда пользовательский вид объявляется в attrs.xml, генерируются специальные константы для индексов атрибутов. И мы можем извлечь значения таким образом: a.getString(R.styleable.MyCustomView_android_text)
. Но для руководства int[]
нет констант. Я полагаю, что getXXXValue (arrayIndex) будет работать нормально.
И другой вопрос: "Как мы можем заменить внутренние константы и запрашивать стандартные атрибуты?" Мы можем использовать значения android.R.attr. *.
Итак, если мы хотим использовать стандартный атрибут TextAppearance в пользовательском представлении и читать его значения в конструкторе, мы можем изменить код из TextView таким образом:
ColorStateList textColorApp = null;
int textSize = 15;
int typefaceIndex = -1;
int styleIndex = -1;
Resources.Theme theme = context.getTheme();
TypedArray a = theme.obtainStyledAttributes(attrs, R.styleable.CustomLabel, defStyle, 0);
TypedArray appearance = null;
int apResourceId = a.getResourceId(R.styleable.CustomLabel_android_textAppearance, -1);
a.recycle();
if (apResourceId != -1)
{
appearance =
theme.obtainStyledAttributes(apResourceId, new int[] { android.R.attr.textColor, android.R.attr.textSize,
android.R.attr.typeface, android.R.attr.textStyle });
}
if (appearance != null)
{
textColorApp = appearance.getColorStateList(0);
textSize = appearance.getDimensionPixelSize(1, textSize);
typefaceIndex = appearance.getInt(2, -1);
styleIndex = appearance.getInt(3, -1);
appearance.recycle();
}
Если определен CustomLabel:
<declare-styleable name="CustomLabel">
<!-- Label text. -->
<attr name="android:text" />
<!-- Label text color. -->
<attr name="android:textColor" />
<!-- Combined text appearance properties. -->
<attr name="android:textAppearance" />
</declare-styleable>
Возможно, я ошибаюсь, но документация на Android по getStyledAttributes() очень бедна.
Расширение стандартного компонента пользовательского интерфейса
В то же время мы можем просто расширить стандартный компонент пользовательского интерфейса, используя все его объявленные атрибуты. Этот подход не так хорош, потому что TextView, например, объявляет много свойств. И это будет невозможно для реализации полной функциональности в overrideen onMeasure() и onDraw().
Но мы можем пожертвовать теоретическим широким повторным использованием пользовательского компонента. Скажем: "Я точно знаю, какие функции я буду использовать", и не передавайте код ни с кем.
Тогда мы можем реализовать конструктор CustomComponent(Context, AttributeSet, defStyle)
.
После вызова super(...)
мы получим все атрибуты, проанализированные и доступные с помощью методов getter.
Ответ 4
Кажется, Google обновил страницу своего разработчика и добавил там различные тренинги.
Один из них касается создания пользовательских представлений и может быть найден здесь
Ответ 5
Большое спасибо за первый ответ.
Что касается меня, у меня была только одна проблема. При раздувании моего взгляда у меня была ошибка: java.lang.NoSuchMethodException: MyView (контекст, атрибуты)
Я решил это, создав новый конструктор:
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
// some code
}
Надеюсь, это поможет!
Ответ 6
Вы можете включить любой файл макета в другой файл макета как -
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginRight="30dp" >
<include
android:id="@+id/frnd_img_file"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
layout="@layout/include_imagefile"/>
<include
android:id="@+id/frnd_video_file"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
layout="@layout/include_video_lay" />
<ImageView
android:id="@+id/downloadbtn"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_centerInParent="true"
android:src="@drawable/plus"/>
</RelativeLayout>
здесь файлы макета в теге include - это другие файлы макета .xml в той же папке res.