Android – запись пользовательского (составного) компонента

У Android-приложения, которое я сейчас разрабатываю, есть основной вид деятельности, который стал довольно большим. Это главным образом потому, что в нем есть TabWidget с 3 вкладками. На каждой вкладке имеется немало компонентов. Деятельность должна контролировать все эти компоненты сразу. Поэтому я думаю, вы можете себе представить, что эта активность имеет 20 полей (поле для почти каждого компонента). Кроме того, он содержит много логики (щелчок слушателей, логика для заполнения списков и т. Д.).

То, что я обычно делаю в инфраструктурах, основанных на компонентах, состоит в том, чтобы разбить все на пользовательские компоненты. Тогда каждый пользовательский компонент будет иметь четкую ответственность. Он будет содержать собственный набор компонентов и всю другую логику, связанную с этим компонентом.

Я попытался выяснить, как это можно сделать, и я нашел что-то в документации на Android, что они любят называть «Compound Control». (См. Http://developer.android.com/guide/topics/ui/custom-components.html#compound и перейдите к разделу «Compound Controls»). Я хотел бы создать такой компонент на основе XML-файла, определяющего Структура представления.

В документации говорится:

Обратите внимание, что так же, как с помощью Activity, вы можете использовать либо декларативный (основанный на XML) подход к созданию содержащихся компонентов, либо вы можете их программно вложить из своего кода.

Ну, это хорошие новости! Основанный на XML подход – именно то, что я хочу! Но он не говорит, как это сделать, за исключением того, что это «как с Activity» … Но то, что я делаю в Activity, это call setContentView(...) чтобы раздуть представления из XML. Этот метод недоступен, если вы, например, подкласс LinearLayout .

Поэтому я попытался раздуть XML вручную следующим образом:

 public class MyCompoundComponent extends LinearLayout { public MyCompoundComponent(Context context, AttributeSet attributeSet) { super(context, attributeSet); LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); inflater.inflate(R.layout.my_layout, this); } } 

Это работает, за исключением того факта, что загружаемый LinearLayout XML имеет LinearLayout объявленный как корневой элемент. Это приводит к завышенному LinearLayout являющемуся дочерним элементом MyCompoundComponent который уже является LinearLayout !! Итак, теперь у нас есть избыточный LinearLayout между MyCompoundComponent и представлениями, которые ему действительно нужны.

Может кто-нибудь, пожалуйста, предоставит мне лучший способ приблизиться к этому, избегая создания избыточного LinearLayout ?

Solutions Collecting From Web of "Android – запись пользовательского (составного) компонента"

Используйте тег merge как ваш корень XML

 <merge xmlns:android="http://schemas.android.com/apk/res/android"> <!-- Your Layout --> </merge> 

Проверьте эту статью.

Я думаю, что вы должны это делать, это использование имени вашего класса в качестве корневого элемента XML:

 <com.example.views.MyView xmlns:.... android:orientation="vertical" etc.> <TextView android:id="@+id/text" ... /> </com.example.views.MyView> 

И тогда ваш класс будет получен из любого макета, который вы хотите использовать. Обратите внимание: если вы используете этот метод, здесь вы не используете разводку макета.

 public class MyView extends LinearLayout { public ConversationListItem(Context context, AttributeSet attrs) { super(context, attrs); } public ConversationListItem(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public void setData(String text) { mTextView.setText(text); } private TextView mTextView; @Override protected void onFinishInflate() { super.onFinishInflate(); mTextView = (TextView)findViewById(R.id.text); } } 

И тогда вы можете использовать свое представление в XML-макетах как обычно. Если вы хотите сделать вид программным, вы должны раздуть его самостоятельно:

 MyView v = (MyView)inflater.inflate(R.layout.my_view, parent, false); 

К сожалению, это не позволяет вам делать v = new MyView(context) потому что, похоже, проблема с вложенными макетами не существует, поэтому это не совсем полное решение. Вы можете добавить такой метод в MyView чтобы сделать его немного приятнее:

 public static MyView create(Context context) { return (MyView)LayoutInflater.fromContext(context).inflate(R.layout.my_view, null, false); } 

Отказ от ответственности: я могу говорить полные болтовни.