Як я можу оголосити елемент інтерфейсу Android за допомогою XML?
Як я можу оголосити елемент інтерфейсу Android за допомогою XML?
Відповіді:
Посібник для розробників Android має розділ під назвою Створення спеціальних компонентів . На жаль, обговорення атрибутів XML охоплює лише декларування контролю всередині файлу макета, а фактично не обробляє значення всередині ініціалізації класу. Кроки такі:
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
тегу використовується некваліфіковане ім’я . Нестандартні атрибути Android, як, наприклад, extraInformation
повинні декларувати їх тип. Теги, задекларовані в суперкласі, будуть доступні в підкласах без необхідності переоформлення.
Оскільки є два конструктори, які використовують 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
, оскільки ця тема може змінитися в майбутньому. Документація ще є, оскільки корисно переглянути всі ці константи в одному місці.
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"
/>
Посилайтеся на спеціальний вигляд, використовуючи повністю кваліфіковане ім’я.
Якщо ви хочете повний приклад, подивіться зразок перегляду етикетки для 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"
Чудова довідка. Дякую! Доповнення до нього:
Якщо у вас є проект бібліотеки, який оголосив спеціальні атрибути для спеціального перегляду, ви повинні оголосити простір імен свого проекту, а не бібліотечного. Наприклад:
Зважаючи на те, що бібліотека має пакет "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" />
xmlns:app="http://schemas.android.com/apk/res-auto"
Suspicious namespace: Did you mean http://schemas.android.com/apk/res-auto
res-auto
оскільки ми використовуємо Android Studio та Gradle. В іншому випадку (наприклад, деякі версії Eclipse) це, як правило, закінчується lib/[your package name]
. тобтоhttp://schemas.android.com/apk/lib/[your package name]
Доповнення до найбільш проголосованої відповіді.
Я хочу додати кілька слів про використання dobitiStyledAttributes (), коли ми створюємо власні подання за допомогою атрибутів 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 про отриманняStyledAttributes () дуже погана.
У той же час ми можемо просто розширити стандартний компонент інтерфейсу, використовуючи всі його заявлені атрибути. Такий підхід не дуже хороший, оскільки, наприклад, TextView оголошує безліч властивостей. І неможливо реалізувати повну функціональність у переосмисленому onMeasure () та onDraw ().
Але ми можемо пожертвувати теоретично широким використанням користувацьких компонентів. Скажіть "Я точно знаю, які функції я буду використовувати", і не діліться кодом ні з ким.
Тоді ми можемо реалізувати конструктор CustomComponent(Context, AttributeSet, defStyle)
. Після дзвінкаsuper(...)
нас будуть розібрані всі атрибути та доступні методами getter.
Схоже, Google оновив сторінку розробника та додав там різні тренінги.
Один з них стосується створення спеціальних представлень і їх можна знайти тут
Дуже дякую за першу відповідь.
Щодо мене, у мене була лише одна проблема. Надуваючи свій погляд, у мене з'явилася помилка: java.lang.NoSuchMethodException: MyView (контекст, атрибути)
Я вирішив це, створивши новий конструктор:
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
// some code
}
Сподіваюся, це допоможе!
Ви можете включити будь-який файл макета в інший файл макета як-
<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.