Объявление пользовательского элемента пользовательского интерфейса android с помощью XML

как объявить элемент пользовательского интерфейса Android с помощью XML?

6 ответов


в руководстве для разработчиков 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 тег. Нестандартный android атрибуты, такие как 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 содержит на MyCustomView. Затем атрибуты можно получить из TypedArray используя различные get функции. Если атрибут не определен в определенном в XML, то null возвращается. За исключением, конечно, если возвращаемый тип является примитивом, в этом случае возвращается второй аргумент.

если вы не хотите получить все атрибуты, можно создать этот массив вручную.ID для стандартных атрибутов 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"
/> 

ссылка на пользовательское представление с использованием полного имени.

Образец Android LabelView

если вы хотите полный пример, посмотрите на android label view образец.

LabelView.java

 TypedArray a=context.obtainStyledAttributes(attrs, R.styleable.LabelView);
 CharSequences=a.getString(R.styleable.LabelView_text);

attrs.в XML

<declare-styleable name="LabelView">
    <attr name="text"format="string"/>
    <attr name="textColor"format="color"/>
    <attr name="textSize"format="dimension"/>
</declare-styleable>

custom_view_1.в XML

<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.образец.библиотека.customview "и рабочий проект имеет пакет" com.образец.пользовательские", затем:

не будет работать (показывает ошибку " ошибка: не найден идентификатор ресурса для атрибут "newAttr" в пакете Ариа.образец.библиотека.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" />

дополнение к большинству проголосовавших ответ.

obtainStyledAttributes()

Я хочу добавить несколько слов об использовании obtainStyledAttributes (), когда мы создаем пользовательский вид с помощью атрибутов 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 на obtainStyledAttributes () очень плохая.

расширение стандартного компонента пользовательского интерфейса

в то же время мы можем просто расширить стандартный компонент UI, используя все его объявленные атрибуты. Этот подход не так хорош, потому что TextView, например, объявляет много свойств. И это будет невозможно реализовать полную функциональность в overriden onMeasure () и onDraw ().

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

затем мы можем реализовать конструктор CustomComponent(Context, AttributeSet, defStyle). После вызова super(...) у нас будут все атрибуты проанализировано и доступно с помощью методов getter.


похоже, что Google обновил свою страницу разработчика и добавил туда различные тренинги.

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


большое спасибо за первый ответ.

что касается меня, у меня была только одна проблема с ним. Когда я раздувал свой взгляд, у меня была ошибка : java.ленг.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.