Every day in development, we come across a situation where we need to preview the UI before docking with data to tweak UI details and typography. What do we do in general? If there are basic controls like TextView or ImageView, are you still testing and previewing UI effects with android:text=” XXX “and Android: SRC =”@drawable/ XXX”? Of course, you will certainly encounter the problem of “dirty data” : when you test some data should not appear, you may later realize that the layout of the control preview data did not clear the cause.

If it is RecyclerView, in the background interface is still able to test the situation, you have to generate their own “fake data” and handwritten Adapter? Is there a way to preview data for layout purposes and dynamically replace and remove irrelevant data after running with real data?

Dang dang dang! Tools Attributes for Android was born. As always, let’s look at one effect:

What? Are you kidding me? Why is such a simple list out there? Ha ha, don’t worry about objectivity. This isn’t that hard to do, would you believe me if I said I didn’t write a line of Java or Kotlin code to achieve this effect, but just preview the layout page? The image above is just the tip of the iceberg, but this is the full picture:

The following will take you step by step to implement the above functions. First, let’s start at the beginning.

To know the Tools the attributes

Tools Attributes is a namespace that starts with Tools. Here’s a common example:

<?xml version="1.0" encoding="utf-8"? >
<android.support.constraint.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    
</android.support.constraint.ConstraintLayout>
Copy the code

You’ll probably see tools: Context =”.XXXActivity “as the default configuration generated by the system. Generally, only the root View can use this property. It specifies which Activity is associated with the current layout by default, so that the layout can get information about the binding Activity, such as the Theme, and so on. And when you add an onClick event to a child View in the layout, The corresponding method code is inserted into the Activity. Android Studio supports many attributes in the Tools namespace in XML files that are erased when the App is built without any impact on APK size or runtime behavior, which is what we originally intended for this article.

Elaborate Tools attributes

Before getting into the details of Tools Attributes, we need to understand how to introduce and use the Tools namespace, simply by adding it to the root element of the XML layout file:

<RootTag xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" >
Copy the code

These utility attributes can be roughly divided into three categories:

Error handling attributes

The error and warning handling properties. This type of property is often used to get around errors and warnings that lint checks for. Let’s look at some common examples:

  • tools:ignore

    Lint mainly ignores warnings generated by lint and supports properties such as:

    <resources xmlns:tools="http://schemas.android.com/tools">
        <string name="app_name">ConstraintSample</string>
        <string name="header_image_string" tools:ignore="MissingTranslation">header image</string>
    </resources>
    Copy the code

    If your project involves internationalization support, the compiler will prompt you to adapt for each language. If you only need to support one language for certain strings, you will not need to support one language. Just add Tools as above :ignore=”MissingTranslation. A similar example can be seen when using ImageView:

    <ImageView
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:src="@drawable/ic_person_off"
      tools:ignore="contentDescription" />
    Copy the code
  • tools:targetApi

    This attribute works the same as the @targetAPI annotation in Java Code: it specifies the API level supported by the current control or element. The attribute value can be an API Code name or an API constant, and it supports all attributes. For example, we all know that Android :elevation attributes are not supported until API version 21, so we can circumvent warnings from Lint with the following code:

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:elevation="4dp"
        tools:targetApi="lollipop"/>
    Copy the code
  • tools:locale

    This attribute is used in the

    tag to specify the default language and locale for the current resource to avoid language spelling detection. For example, you can specify that the default language of the values/strings. XML file is Spanish instead of English:

    <resources xmlns:tools="http://schemas.android.com/tools"
        tools:locale="es">
    Copy the code

Resource shrinking attributes

Resource compression properties. The use of these attributes was explained in detail in a previous article that introduced you to the magic of Android confusion, but here are a few more.

We can use tools:shrinkMode and Tools: Keep to specify resource compression mode and uncompressed resources to keep. We can also use Tools: Discard to specify resources to keep, similar to keep:

<?xml version="1.0" encoding="utf-8"? >
<resources xmlns:tools="http://schemas.android.com/tools"
		tools:shrinkMode="strict" 
    tools:keep="@layout/activity_video*,@layout/dialog_update_v2"
    tools:discard="@layout/unused_layout,@drawable/unused_selector" />
Copy the code

The following is the highlight of this article, pay attention to the front of high energy attack!

Design-time View Attributes

This is an important part of our previous renderings, namely, control properties in layout design. Tools: Context is one of the “members” of the View control. Let’s look at the other important members.

Before we do that, we need to remove another layer of mystery from the Tools namespace: Tools: can replace any property prefixed with Android: and set sample data for it. Of course, as we said earlier, tools attributes are only valid during layout editing and are meaningless once the App is actually running, so we can preview the layout before it runs like this:

The layout file corresponding to the figure above is:

Card_item_layout.xml

<?xml version="1.0" encoding="utf-8"? >
<android.support.constraint.ConstraintLayout
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:background="@android:color/white"
        android:clickable="true"
        android:focusable="true"
        android:foreground="? attr/selectableItemBackground"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="2dp"
        android:layout_marginEnd="2dp"
        tools:targetApi="m"
        tools:ignore="UnusedAttribute">

    <ImageView
            android:id="@+id/card_item_avatar"
            android:layout_width="38dp"
            android:layout_height="38dp"
            app:layout_constraintStart_toStartOf="parent"
            android:layout_marginStart="16dp"
            android:layout_marginTop="16dp"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            android:layout_marginBottom="16dp"
            app:layout_constraintVertical_bias="0.0"
            tools:ignore="ContentDescription"
            tools:srcCompat="@drawable/user_other"/>
    <TextView
            android:id="@+id/card_item_username"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="16dp"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintStart_toStartOf="@+id/card_item_title"
            app:layout_constraintEnd_toEndOf="@+id/card_item_title"
            app:layout_constraintHorizontal_bias="0.0"
            android:textSize="12sp"
            android:textColor="@color/username_text_color"
            android:layout_marginEnd="16dp"
            android:paddingEnd="16dp"
            tools:text="The moon and the Wind." />
    <TextView
            android:id="@+id/card_item_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="16sp"
            android:textColor="@color/title_text_color"
            app:layout_constraintStart_toEndOf="@+id/card_item_avatar"
            android:layout_marginStart="12dp"
            app:layout_constraintTop_toBottomOf="@+id/card_item_username"
            android:layout_marginTop="8dp"
            android:maxLines="1"
            tools:text="What a beautiful night in Shanghai today!"/>
    <TextView
            android:id="@+id/card_item_content"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            app:layout_constraintStart_toStartOf="parent"
            android:layout_marginTop="24dp"
            app:layout_constraintTop_toBottomOf="@+id/card_item_avatar"
            app:layout_constraintBottom_toBottomOf="parent"
            android:layout_marginBottom="16dp"
            app:layout_constraintVertical_bias="1.0"
            android:maxLines="3"
            android:ellipsize="end"
            android:textColor="@color/content_text_color"
            android:textStyle="normal"
            app:layout_constraintEnd_toEndOf="@+id/card_item_bottom_border"
            android:layout_marginEnd="16dp"
            android:layout_marginStart="16dp"
            app:layout_constraintHorizontal_bias="0.0"
            tools:text="Life if only such as first, what autumn wind sad picture fan..."/>
    <ImageView
            android:id="@+id/card_item_poster"
            android:layout_width="0dp"
            android:layout_height="200dp"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/card_item_content"
            app:layout_constraintEnd_toEndOf="parent"
            android:layout_marginEnd="16dp"
            android:scaleType="centerCrop"
            android:layout_marginTop="8dp"
            android:layout_marginStart="16dp"
            app:layout_constraintBottom_toBottomOf="parent"
            android:layout_marginBottom="16dp"
            app:layout_constraintVertical_bias="0.0"
            tools:ignore="ContentDescription"
            android:visibility="visible"
            tools:src="@drawable/shanghai_night"/>
    <View
            android:id="@+id/card_item_bottom_border"
            android:layout_width="0dp"
            android:layout_height="2dp"
            app:layout_constraintTop_toBottomOf="@+id/card_item_poster"
            android:background="#ffededfe"
            app:layout_constraintEnd_toEndOf="parent"
            android:layout_marginTop="16dp"
            app:layout_constraintStart_toStartOf="parent"/>
    <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/card_item_date"
            android:layout_marginTop="16dp"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            android:layout_marginEnd="16dp"
            android:textColor="@color/date_text_color"
            android:textSize="12sp"
            tools:text="2019-08-10"/>
</android.support.constraint.ConstraintLayout>
Copy the code

From the above code, we can find that the text preview can be realized by using the Tools :text attribute instead of Android :text for TextView. However, this setting will not affect the actual running effect of our App. In the same way, you can preview images by applying Tools: SRC to ImageView. In addition. We can also preview other properties prefixed with Android: without affecting the actual performance. For example, the bottom line

in the layout code above, we want to hide it when the App is actually running, but we still need to know its preview effect and height:

<View
        android:id="@+id/card_item_bottom_border"
        android:layout_width="0dp"
        android:layout_height="2dp"
        android:visibility="gone"
        tools:visibility="visible"
        tools:layout_height="8dp"
        app:layout_constraintTop_toBottomOf="@+id/card_item_poster"
        android:background="#ffededfe"
        app:layout_constraintEnd_toEndOf="parent"
        android:layout_marginTop="16dp"
        app:layout_constraintStart_toStartOf="parent"/>
Copy the code

As shown above, tools:visibility and Tools :layout_height allow you to change the state and height of the View only in the layout preview. Tools: replaces all android: decorated properties.

Here are some other attributes that you’ll use more often.

  • tools:layout

    This property can only be used in fragment controls. If we declare a

    control in our activity layout file, We can use tools:layout= “@layout/fragment_main” to preview the fragment layout in the current activity layout.

  • tools:showIn

    This property is a bit more fun, specifying that other layout files will be used in the current layout file and preview the actual effect of the

    control as the

    component. For example, if we use card_item_layout. XML as a showIn object for the show_in_layout. XML layout, then I can see the following effect in show_in_layout. XML:

  • tools:menu

    This property allows you to add multiple menu items to the Toolbar of the current layout preview, but only to the root node element of the layout file. Such as:

    <?xml version="1.0" encoding="utf-8"? >
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:menu="menu1,menu2" />
    Copy the code
  • tools:maxValue | tools:minValue

    These two attributes are only used for

    , and can be specified at preview time for maximum and minimum values:

    <NumberPicker 
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/numberPicker"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        tools:minValue="0"
        tools:maxValue="10" />
    Copy the code
  • tools:listitem | tools:listheader | tools:listfooter | tools:listCount

    Let’s look at tools properties for list-related components. The above four properties are used only for

    and its subclasses (e.g., ListView and RecyclerView). However, they still have some internal restrictions: Tools :listCount is only for RecyclerView; Tools :listheader and Tools: Listfooter are limited to ListView; As for the Tools: Listitem attribute, both are available. Previous renderings relied on this property:

    Activity_main. XML:

    <?xml version="1.0" encoding="utf-8"? >
    <android.support.constraint.ConstraintLayout
            xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:tools="http://schemas.android.com/tools"
            xmlns:app="http://schemas.android.com/apk/res-auto"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            tools:context=".MainActivity"
            android:background="#ffEBEBEF">
        <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:background="? attr/colorPrimary"
                android:theme="? attr/actionBarTheme"
                android:minHeight="? attr/actionBarSize"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                android:elevation="1dp"
                app:title="@string/app_name"
                app:layout_constraintTop_toTopOf="parent"
                app:layout_constraintHorizontal_bias="0.0"/>
        <android.support.v7.widget.RecyclerView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintBottom_toBottomOf="parent"
                android:scrollbars="vertical"
                app:layout_constraintTop_toBottomOf="@+id/toolbar"
                app:layout_constraintHorizontal_bias="0.0"
                app:layout_constraintVertical_bias="0.0"
                tools:listitem="@layout/card_item_layout"/>
    </android.support.constraint.ConstraintLayout>
    Copy the code

sample data

The sample data feature, which can be used by @tools:sample, also belongs to the Design-Time View Attributes. But it’s not just an attribute, it’s more of a “tool”, so I’ll cover it in detail on its own. The tool is a new feature featured by the Android development team at this year’s Google Conference. What does it do? Very useful! The data used in the previous layout preview was directly indicated in the layout control or presented in the strings.xml file, which would produce some dirty data, which was not conducive to our later processing. With Sample Data, we can centrally save and manage ** “sample data” ** in the layout preview.

I. Use of sample data

Android Studio has provided us with the following sample data that I can use directly:

Attribute value Description of placeholder data
@tools:sample/full_names Full names that are randomly generated from the combination of@tools:sample/first_names and @tools:sample/last_names.
@tools:sample/first_names Common first names.
@tools:sample/last_names Common last names.
@tools:sample/cities Names of cities from across the world.
@tools:sample/us_zipcodes Randomly generated US zipcodes.
@tools:sample/us_phones Randomly generated phone numbers with the following format: (800) 555-xxxx.
@tools:sample/lorem Placeholder text that is derived from Latin.
@tools:sample/date/day_of_week Randomized dates and times for the specified format.
@tools:sample/date/ddmmyy
@tools:sample/date/mmddyy
@tools:sample/date/hhmm
@tools:sample/date/hhmmss
@tools:sample/avatars Vector drawables that you can use as profile avatars.
@tools:sample/backgrounds/scenic Images that you can use as backgrounds.

The above table not only has common text data and date data, but also provides some image sample data, so how to use it? Simply switch to the layout preview screen, drag an ImageView onto the panel, and Android Studio will pop up with the following screen:

Then select avatars or Background /scenic data sources. Of course, you can also set this in XML code:

<?xml version="1.0" encoding="utf-8"? >
<android.support.constraint.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:background="@android:color/white"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    <ImageView
            android:layout_width="36dp"
            android:layout_height="36dp"
            android:id="@+id/imageView"
            android:layout_marginTop="16dp"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            android:layout_marginStart="16dp"
            tools:srcCompat="@tools:sample/avatars"/>
    <TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:id="@+id/textView" app:layout_constraintStart_toEndOf="@+id/imageView"
            android:layout_marginStart="8dp" app:layout_constraintEnd_toEndOf="parent" android:layout_marginEnd="16dp"
            app:layout_constraintTop_toTopOf="parent"
            tools:text="@tools:sample/lorem/random"
            tools:maxLines="8"
            android:ellipsize="end"
            android:textSize="14sp"
            android:textColor="@color/title_color" android:layout_marginTop="16dp"
            app:layout_constraintHorizontal_bias="0.0"/>
</android.support.constraint.ConstraintLayout>
Copy the code

Similarly, TextView can @ tools: sample/lorem/random to add sample data, thus, results are as follows:

Ha ha, not bad 😄. So the question is, what if we want to use our own sample data source?

2. Customize sample Data

What if we wanted to use our own custom sample data? Create a sample Data directory in the app directory:

Next, we can customize our own data in the sampleData directory, create a new TXT data file, such as Users, and create the following data:

Do the same with our other data: titles, Descriptions, then replace and use your own data sources in the card_ITEM_layout.xml layout file above:

<TextView
            android:id="@+id/card_item_username"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="16dp"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintStart_toStartOf="@+id/card_item_title"
            app:layout_constraintEnd_toEndOf="@+id/card_item_title"
            app:layout_constraintHorizontal_bias="0.0"
            android:textSize="12sp"
            android:textColor="#8989ae"
            android:layout_marginEnd="16dp"
            android:paddingEnd="16dp"
            tools:text="@sample/users" />
Copy the code

Just one of these TextViews is used here, and the others are the same.

What? You think you’re done here? Use custom Json format data to bind data to the control:

👋, again using the example above, to see how to bind with JSON data:

<TextView
            android:id="@+id/card_item_username"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="16dp"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintStart_toStartOf="@+id/card_item_title"
            app:layout_constraintEnd_toEndOf="@+id/card_item_title"
            app:layout_constraintHorizontal_bias="0.0"
            android:textSize="12sp"
            android:textColor="#8989ae"
            android:layout_marginEnd="16dp"
            android:paddingEnd="16dp"
            tools:text="@sample/sample.json/data/username" />
Copy the code

When you do this, Android Studio will automatically prompt you for the data file in the sampleData path, as well as the specific field in the Json format.

The last

The layout editor will be more powerful in future Updates to Android, according to Google Android. From Tools attributes to ConstraintLayout1.1 to the upcoming MotionLayout in ConstraintLayout2.0, we can expect: Android will further free up our hands in TERMS of UI rendering and animation implementation. I will continue to bring you a series of articles, stay tuned to 🌈.