简体   繁体   中英

Android: automatically make variables for all IDs in xml

I noticed one of the most tedious parts of Android development is the layout design, even with layout builder.

After setting up the graphics, then the layout, making variable associations with the layout elements is very tedious, such as ImageButton myButton = (ImageButton)findViewById(R.id.myButton);

in larger layouts, these can get tedious to keep track of (recalling the names of the elements) and then the need to add more variables in any kind of order gets frustrating.

To slightly mitigate this, it would be very convenient if all of the IDs I declared in the XML were automatically associated with their proper variables, and all of those datatypes were already included in that class

Is there something that already does this?

for instance if I write

 <ImageButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/myButton" android:id="@+id/myButton"></ImageButton>

then I would like the classes which include this layout to already have

 import android.ImageButton;

 ImageButton myButton;

 myButton = (ImageButton)findViewById(R.id.myButton);

is this a setting or a feature to request? I am using the Eclipse IDE and it would be very convenient

I made a tool to automatically generate the Java code for tying layout XML's and program logic together.

Basically it takes an XML layout, and generates all the necessary Java code for you in an instant. There is support for basic member variables, ViewHolder pattern, ArrayAdapter, CursorAdapter and RoboGuice code types.

You can find it here: Android Layout Finder | Buzzing Android

Try using Android Annotations . It provides useful annotations to replace boilerplate code.

For instance, see @ViewById documentation : just declare the fields annotated

@ViewById
EditText myEditText;

@ViewById(R.id.myTextView)
TextView textView;

It replaces

EditText myEditText;

TextView textView;
@Override
public void onCreate(Bundle savedInstanceState) {
    [...]
    myEditText = (EditText) findViewById(R.id.myEditText);
    textView = (TextView) findViewById(R.id.myTextView);
}

Since version 3.6 of android studio they have officially added the support of autometically view binding that's generates a binding class for each XML layout file. These classes contain direct references to all views that have an ID in the corresponding layout.

you can enable it by modifying your build.gradle file.

android {
  ...
  viewBinding {
      enabled = true
  }
}

If view binding is enabled for a module, a binding class is generated for each XML layout file that the module contains. Each binding class contains references to the root view and all views that have an ID.

For example, given a layout file called result_profile.xml The generated binding class will be called ResultProfileBinding .

Example:

private ResultProfileBinding binding;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    binding = ResultProfileBinding.inflate(getLayoutInflater());
    View view = binding.getRoot();
    setContentView(view);
}

Please check the official documentation here .

UPDATE : Android View Binding (AVB) Code Generator , this does exactly what i am going to say :|


REGEX!

I had the same problem and i tried to solve it myself so i turned into REGEX inside of search and replace of dear Android Studio . Personally i use ButterKnife for dependency injection with java annotation but the more important part is how to automate the procedure of turning ids in xml layout to java objects. Its kind of like the Android Layout Finder | Buzzing Android (the website has more features but old :( ) answer but with annotation result.

  1. go to your xml and select all of the ids with this regex ( \\+id/.* ). To do that first press Ctrl + F to open the search panel, then make sure that the Regex checkbox is checked. then enter the regex ( \\+id/.* ) inside the box and then press Ctrl + Alt + Shift + J to select all occurrences. Now Ctrl + C to copy them (u know the shortcut).

for example i had this layout:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layoutDirection="rtl"
    tools:context=".jobs.return_from_entrance.ReturnFromEntranceActivity"
    tools:ignore="HardcodedText">

    <android.support.constraint.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <GridLayout
            android:id="@+id/return_entrance_grid_layout"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:columnCount="2"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/text_margin"
                android:text="شماره برگشت" />

            <TextView
                android:id="@+id/return_entrance_return_entrance_number_text_view"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/text_margin"
                android:text="123123123"
                android:textColor="@android:color/black"
                android:textSize="18sp" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/text_margin"
                android:text="@string/owner_of_cargo" />

            <TextView
                android:id="@+id/return_entrance_owner_text_view"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/text_margin"
                android:text="الجی"
                android:textColor="@android:color/black"
                android:textSize="18sp" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/text_margin"
                android:text="تاریخ و زمان" />

            <TextView
                android:id="@+id/return_entrance_time_text_view"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/text_margin"
                android:text="12/12/12/ 12:12"
                android:textColor="@android:color/black"
                android:textSize="18sp" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/text_margin"
                android:text="نوع حواله" />

            <TextView
                android:id="@+id/return_entrance_kind_of_order_text_view"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/text_margin"
                android:text="حواله"
                android:textColor="@android:color/black"
                android:textSize="18sp" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/text_margin"
                android:text="خریدار" />


            <TextView
                android:id="@+id/return_entrance_buyer_name_text_view"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/text_margin"
                android:text="علی امیدی"
                android:textColor="@android:color/black"
                android:textSize="18sp" />


            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/text_margin"
                android:text="مقصد" />

            <TextView
                android:id="@+id/return_entrance_destination_text_view"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/text_margin"
                android:text="آزادی"
                android:textColor="@android:color/black"
                android:textSize="18sp" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/text_margin"
                android:text="وزن ناخالص" />

            <TextView
                android:id="@+id/return_entrance_gross_weight_text_view"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/text_margin"
                android:text="123"
                android:textColor="@android:color/black"
                android:textSize="18sp" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/text_margin"
                android:text="شماره جواز" />

            <TextView
                android:id="@+id/return_entrance_permission_number_text_view"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/text_margin"
                android:text="126545643"
                android:textColor="@android:color/black"
                android:textSize="18sp" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/text_margin"
                android:text="شماره بارنامه" />

            <TextView
                android:id="@+id/return_entrance_waybill_number_text_view"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/text_margin"
                android:text="654"
                android:textColor="@android:color/black"
                android:textSize="18sp" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/text_margin"
                android:text="زمان ورود" />

            <TextView
                android:id="@+id/return_entrance_enter_time_text_view"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/text_margin"
                android:text="21/12/12 22:22"
                android:textColor="@android:color/black"
                android:textSize="18sp" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/text_margin"
                android:text="زمان خروج" />

            <TextView
                android:id="@+id/return_entrance_exit_time_text_view"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/text_margin"
                android:text="21/12/12 22:22"
                android:textColor="@android:color/black"
                android:textSize="18sp" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/text_margin"
                android:text="محوطه بارگیری" />

            <TextView
                android:id="@+id/return_entrance_load_location_text_view"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/text_margin"
                android:text="حیاط"
                android:textColor="@android:color/black"
                android:textSize="18sp" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/text_margin"
                android:text="نیاز به جرثقیل" />

            <TextView
                android:id="@+id/return_entrance_is_crane_needed_text_view"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/text_margin"
                android:text="ندارد"
                android:textColor="@android:color/black"
                android:textSize="18sp" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/text_margin"
                android:text="نیاز به لیفتراک" />

            <TextView
                android:id="@+id/return_entrance_is_forklift_needed_text_view"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/text_margin"
                android:text="ندارد"
                android:textColor="@android:color/black"
                android:textSize="18sp" />

            <CheckBox
                android:id="@+id/return_entrance_internal_return_entrance_checkbox"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginEnd="@dimen/margin_large"
                android:layout_marginStart="@dimen/margin_medium"
                android:layout_marginTop="@dimen/margin_large"
                android:text="خروج داخلی" />

            <View
                android:layout_width="0dp"
                android:layout_height="0dp" />

            <CheckBox
                android:id="@+id/return_entrance_warehouse_delivery_checkbox"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginEnd="@dimen/margin_large"
                android:layout_marginStart="@dimen/margin_medium"
                android:layout_marginTop="@dimen/margin_large"
                android:text="تحویل در انبار" />

            <View
                android:layout_width="0dp"
                android:layout_height="0dp" />

            <Button
                android:id="@+id/return_entrance_location_delivery_button"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/margin_large"
                android:text="تحویل در محل" />

            <View
                android:layout_width="0dp"
                android:layout_height="0dp" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/text_margin"
                android:text="عکس راننده" />

            <ImageView
                android:id="@+id/return_entrance_driver_image_view"
                android:layout_width="120dp"
                android:layout_height="120dp"
                android:layout_gravity="center"
                android:layout_marginTop="@dimen/item_margin"
                android:src="@drawable/ic_account_circle_black_24dp" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/text_margin"
                android:text="@string/name_of_driver" />

            <TextView
                android:id="@+id/return_entrance_name_of_driver_text_view"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/text_margin"
                android:text="علی امیدی"
                android:textColor="@android:color/black"
                android:textSize="18sp" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/text_margin"
                android:text="@string/kind_of_car" />

            <TextView
                android:id="@+id/return_entrance_kind_of_car_text_view"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/text_margin"
                android:text="وانت مزدا"
                android:textColor="@android:color/black"
                android:textSize="18sp" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/text_margin"
                android:text="@string/plaque" />

            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/margin_large"
                android:orientation="horizontal">

                <TextView
                    android:id="@+id/return_entrance_plaque_2digit_text_view"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:background="@drawable/plaque_background"
                    android:padding="10dp"
                    android:text="11"
                    android:textColor="@android:color/black"
                    android:textSize="10pt"
                    android:textStyle="bold" />

                <TextView
                    android:id="@+id/return_entrance_plaque_6digit_text_view"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:background="@drawable/plaque_background"
                    android:padding="10dp"
                    android:text="999ج77"
                    android:textColor="@android:color/black"
                    android:textSize="10pt"
                    android:textStyle="bold" />
            </LinearLayout>
        </GridLayout>

        <Button
            android:id="@+id/return_entrance_barcode_scan_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_margin="@dimen/margin_small"
            android:drawableStart="@drawable/ic_barcode"
            android:padding="@dimen/margin_medium"
            android:text="@string/scan_barcode"
            android:textSize="18sp"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@id/return_entrance_grid_layout" />

        <android.support.v7.widget.RecyclerView
            android:id="@+id/return_entrance_cargo_list_recycler_view"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@id/return_entrance_barcode_scan_button" />

        <GridLayout
            android:id="@+id/return_entrance_bottom_grid_layout"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:columnCount="2"
            android:layoutDirection="rtl"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@id/return_entrance_cargo_list_recycler_view">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/text_margin"
                android:text="میزان موجودی کالای قابل تحویل" />

            <TextView
                android:id="@+id/return_entrance_deliverable_availability_text_view"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/text_margin"
                android:text="50"
                android:textColor="@android:color/black"
                android:textSize="18sp" />

        </GridLayout>

        <LinearLayout
            android:id="@+id/return_entrance_bottom_linear_2"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center_horizontal"
            android:orientation="vertical"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@id/return_entrance_bottom_grid_layout">

            <Button
                android:id="@+id/return_entrance_cost_report_button"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/margin_medium"
                android:text="گزارش هزینه" />

            <Button
                android:id="@+id/return_entrance_confirm_button"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/margin_medium"
                android:text="تایید برگشت" />

        </LinearLayout>

    </android.support.constraint.ConstraintLayout>
</android.support.v4.widget.NestedScrollView>

a lot of text views to fill, huh?

  1. go to your java class and paste the copied ids( Ctrl + V ). so we have bunch of ids which we want to change them into java objects. in our example, my ids would be like this :

     +id/return_entrance_grid_layout" +id/return_entrance_return_entrance_number_text_view" +id/return_entrance_owner_text_view" +id/return_entrance_time_text_view" ...

Its time to find and replace! so first we hit Ctrl + R to open the find and replace panel. (make sure the REGEX checkbox is checked) now im going to do some find and replaces to get the ideal result:

  1. Find : \\+id/(.*)" Replace with: @BindView(R.id.$1) so we will have this:

     @BindView(R.id.return_entrance_grid_layout) @BindView(R.id.return_entrance_return_entrance_number_text_view) @BindView(R.id.return_entrance_owner_text_view) @BindView(R.id.return_entrance_time_text_view) ...

now its time to define each variable type and name them. my xml naming has WHERE_DESCRIPTION_WHAT pattern, ( something like this ). so for the variable name i want to remove the WHERE part. and then define the object type . so here we go:

  1. Find: (@BindView\\(R\\.id\\.return_entrance_(.*)_text_view\\)) Replace with: $1 TextView $2TextView; the result will be:

     @BindView(R.id.return_entrance_grid_layout) @BindView(R.id.return_entrance_return_entrance_number_text_view) TextView return_entrance_numberTextView; @BindView(R.id.return_entrance_owner_text_view) TextView ownerTextView; @BindView(R.id.return_entrance_time_text_view) TextView timeTextView; @BindView(R.id.return_entrance_kind_of_order_text_view) TextView kind_of_orderTextView; ...

(just hit a Ctrl + Alt + L to reformat your code) the names are ulgy :( . so we do this to camelCase! :

  1. Find: TextView \\b(.*)_(.*) Replace With: TextView $1\\u$2\u003c/code> and the result will be:

     @BindView(R.id.return_entrance_owner_text_view) TextView ownerTextView; @BindView(R.id.return_entrance_time_text_view) TextView timeTextView; @BindView(R.id.return_entrance_kind_of_order_text_view) TextView kind_ofOrderTextView; @BindView(R.id.return_entrance_buyer_name_text_view) TextView buyerNameTextView; @BindView(R.id.return_entrance_destination_text_view) TextView destinationTextView;

if you repeat the last part, any name that has more than one underline, each _ will be replaced with the Uppercase of the next character. so in this example if i do the Find: TextView \\b(.*)_(.*) Replace With: TextView $1\\u$2\u003c/code> again, my TextView kind_ofOrderTextView; will be TextView kindOfOrderTextView;

It may seem a bit complicated but when u get used to it, it becomes so fast and it becomes so more useful! for example imagine in an MVP , u have a Model with the same String names of the TextViews , so u can do this to set all of their texts' from the Model with similar approach...

That's a feature request. It's very good one and I think it would be pretty useful; on the other hand there are cases where it wouldn't work very well, for example if you are inflating views dynamically and don't know, at compile time, which view a particular Activity will inflate. However, I tend to think this case would be the exception rather than the rule.

The easiest way to do that would be to code a script that scans your layout XML files in search for components with ID's and creates .java files with the proper definitions. Then, your activities could derive from those auto-generated classes. Something like this:

When processed by your script, that generates a class:

class FooBarLayoutActivityBase extends Activity ... {
  protected ImageButton myButton;

  FooBarLayoutActivityBase() {
    myButton = (ImageButton)findViewById(R.id.myButton);
  }
}

Then, you can simply inherit from that base class to use the components...

The script approach is simple and doesn't require you to delve into the toolchain's code -- but you could also do it directly in the ADT plugin.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM