AWT AWT - 4 months ago 14
Android Question

Is it possible to reuse the outer elements of an Android layout?

I have two very similar Android layouts:

default_spinner.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:minHeight="@dimen/settings_line_min_height"
android:orientation="horizontal"
android:paddingLeft="@dimen/common_padding"
android:paddingRight="@dimen/common_padding">

<TextView
android:id="@id/label"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1" />

<ImageButton
android:id="@+id/down_spinner_btn"
style="@style/SpinnerDownButton"
android:layout_width="wrap_content"
android:layout_height="match_parent" />

<EditText
android:id="@+id/edit_box"
style="@style/EditableSpinnerText"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:inputType="number"
android:imeOptions="actionDone"
android:longClickable="false" />

<ImageButton
android:id="@+id/up_spinner_btn"
style="@style/SpinnerUpButton"
android:layout_width="wrap_content"
android:layout_height="match_parent" />

</LinearLayout>


and

custom_spinner.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingLeft="@dimen/common_padding"
android:paddingRight="@dimen/common_padding">

<TextView
android:id="@id/label"
style="@style/Subhead.Translucent"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1" />

<ImageButton
android:id="@+id/down_spinner_btn"
style="@style/SpinnerDownButton"
android:layout_width="wrap_content"
android:layout_height="match_parent" />

<com.company.CustomEditText
android:id="@+id/edit_box"
style="@style/EditableSpinnerText"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:inputType="text" />

<ImageButton
android:id="@+id/up_spinner_btn"
style="@style/SpinnerUpButton"
android:layout_width="wrap_content"
android:layout_height="match_parent" />

</LinearLayout>


As you can see, the only difference between the two is that the second one has a custom implementation of the EditText class.

In some classes, I load the default spinner:

View view = inflater.inflate(R.layout.default_spinner, parent, false);


And in other classes, I load the custom spinner:

View view = inflater.inflate(R.layout.custom_spinner, parent, false);


This all works fine, but the inefficiency bothers me.

I know it's possible to reuse layout elements in Android using the
<import />
command... however, I'm not sure if that would be applicable here. Since a majority of both of these layouts is the same, I'd like to consolidate the identical code and just have it use either the CustomEditText or EditText class, depending on the situation.

Does anyone have an idea of how I could reuse the outer elements of these layouts and eliminate all of that duplication?

Answer

Yes, there is. In this case, you can have a single layout file with a ViewStub in place of EditText/CustomEditText. Like this:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:paddingLeft="@dimen/common_padding"
    android:paddingRight="@dimen/common_padding">

    <TextView
        android:id="@id/label"
        style="@style/Subhead.Translucent"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:layout_weight="1" />

    <ImageButton
        android:id="@+id/down_spinner_btn"
        style="@style/SpinnerDownButton"
        android:layout_width="wrap_content"
        android:layout_height="match_parent" />

    <ViewStub
        android:id="@+id/view_stub"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1" />

    <ImageButton
        android:id="@+id/up_spinner_btn"
        style="@style/SpinnerUpButton"
        android:layout_width="wrap_content"
        android:layout_height="match_parent" />

</LinearLayout>

Then, in your Java code, you will lazily inject the EditText of your choice:

ViewStub viewStub = (ViewStub) findViewById(R.id.view_stub);
viewStub.setLayoutResource(someCondition ? R.layout.custom_edit_text : R.layout.regular_edit_text);
viewStub.inflate();

As you can see, you'll have two more layout files for each EditText:

custom_edit_text.xml

<com.company.CustomEditText
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/edit_box"
        style="@style/EditableSpinnerText"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:inputType="text" />

regular_edit_text.xml

<EditText
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/edit_box"
        style="@style/EditableSpinnerText"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:inputType="text" />