Home Android & Kotlin Books Android Debugging by Tutorials

6
Layout Inspector Written by Zac Lippard

Heads up... You're reading this book for free, with parts of this chapter shown beyond this point as scrambled text.

You can unlock the rest of this book, and our entire catalogue of books and videos, with a raywenderlich.com Professional subscription.

Up until now, you’ve learned many ways to debug your app’s code. But what if you wanted to debug the UI? Enter, the Layout Inspector.

The Layout Inspector is a tool provided by Android Studio that enables you to debug layouts in your app. The inspector takes a snapshot of the UI to provide details about the layout. These details can be what views are in the UI hierarchy, attributes of each view and a 3D rendering to inspect the views at different angles.

Effective use of the Layout Inspector can help you catch potential defects in your layouts, as well as help improve the overall UI performance.

In this chapter, you’ll use the Layout Inspector and learn how to:

  • Inspect the view hierarchy.
  • Generate a 3D rendering of your app’s UI.
  • Read the attributes of a view.
  • Condense layout layers.
  • Validate layouts on different devices and configurations.

Running the Layout Inspector

Begin by opening the Podplay starter project in Android Studio. Before running the app, click Select Run/Debug Configuration from the toolbar and choose Edit Configurations…

In the Run/Debug Configurations dialog, click the Miscellaneous tab and check the Connect to Layout Inspector without restarting activity box.

When you check this option, the Layout Inspector passes a flag to the launching activity. The flag allows the inspector to connect to the app immediately. Otherwise, the inspector has to restart the activity each time it’s loaded, and you’ll have to navigate back to the view you want to inspect.

Click OK to save changes.

Run the app. When the app launches, start the Layout Inspector by clicking Tools ▸ Layout Inspector from the Android Studio menu.

The following sections in the inspector include:

  1. Component Tree: This shows all the views in the hierarchy. You’ll notice this particular layout’s hierarchy is shallow, with only two layers.
  2. Layout Display: This is the rendered display of your layout. This section allows you to zoom in on specific views in the layout and explore the layers of the hierarchy in 3D.
  3. View Attributes: When you select a view from the component tree or the layout display, the attributes for that view appear here.

At the bottom right of the layout display section click the 3D Mode button.

Note: The first time you do this, it may ask you to install some additional components within Android Studio.

The display rendering updates to show a 3D layering of your views:

Notice there’s a toolbar at the top of the layout display section. This toolbar includes several features such as:

  1. Showing and hiding certain aspects of views.
  2. Loading overlays.
  3. Exporting snapshots.
  4. Enabling live updates of the inspector.
  5. Refreshing the inspector.
  6. Adjusting the spacing of the hierarchy layers.

You’ll learn more about each of these later in this chapter.

The 3D rendering in the layout display allows you to observe the layout and its layers, view outlines display and show you how many nested view groups are in your layout. This rendering can help you determine if you have too many layers and if your layouts are complex.

When the UI gets rendered, the system has to do a number of layout passes to draw each view layer in the hierarchy. Too many nested layers can cause drawing issues like overdraw and will slow down the layout process.

Overdraw occurs when the system attempts to draw over the same pixel or group of pixels in layout passes. Overdraw is inefficient and often unnecessary as the GPU has to re-process rendering and draw the same part of the screen multiple times.

Note: To learn more about overdraw and ways to reduce it, read the Overdraw Android developer documentation.

The layout display will show you potential overdraw areas within the 3D rendering. Overlapping layers with background colors set in the same region are candidates for overdraw. You should avoid this as much as possible.

Now that you’ve understood what the Layout Inspector can do, it’s time to improve one layout in the Podplay app!

In the starter project, fragment_episode_player.xml contains a number of nested RelativeLayout and LinearLayout view groups. You’ll improve this layout file and use the Layout Inspector to view the changes.

Refreshing the Layout Inspector

You’ll need to refresh the inspector to load the episode player view. To do so, go to the running Podplay app, tap Search and enter “android”. Tap a podcast from the list and choose an episode so the player screen loads.

Isolating a View

There’s a lot going on in the current layout display with all the views in the hierarchy. What you’ll focus on is the podcastDetailsContainer view. Click that view in the component tree, highlighting the associated view in the display.

Condensing Layouts With ConstraintLayout

Open fragment_episode_player.xml in Android Studio. Look for the RelativeLayout with id set to @+id/headerView:

<RelativeLayout
  android:id="@+id/headerView"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:background="#eeeeee"
  app:layout_constraintEnd_toEndOf="parent"
  app:layout_constraintStart_toStartOf="parent"
  app:layout_constraintTop_toTopOf="parent">

  <ImageView
    android:id="@+id/episodeImageView"
    android:layout_width="60dp"
    android:layout_height="60dp"
    android:layout_marginStart="8dp"
    android:layout_marginTop="8dp"
    android:contentDescription="@string/episode_thumbnail"
    android:src="@android:drawable/ic_menu_report_image" />

  <TextView
    android:id="@+id/episodeTitleTextView"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    android:layout_alignBottom="@+id/episodeImageView"
    android:layout_alignTop="@+id/episodeImageView"
    android:layout_marginEnd="8dp"
    android:layout_marginStart="8dp"
    android:layout_toEndOf="@+id/episodeImageView"
    android:text="" />
</RelativeLayout>
<ImageView
  android:id="@+id/episodeImageView"
  android:layout_width="68dp"
  android:layout_height="68dp"
  android:paddingStart="8dp"
  android:paddingTop="8dp"
  android:contentDescription="@string/episode_thumbnail"
  android:src="@android:drawable/ic_menu_report_image"
  android:background="#eeeeee"
  app:layout_constraintTop_toTopOf="parent"
  app:layout_constraintStart_toStartOf="parent" />

<TextView
  android:id="@+id/episodeTitleTextView"
  android:layout_width="0dp"
  android:layout_height="0dp"
  android:paddingEnd="8dp"
  android:paddingStart="8dp"
  android:text=""
  android:gravity="center_vertical"
  android:background="#eeeeee"
  app:layout_constraintTop_toTopOf="@id/episodeImageView"
  app:layout_constraintStart_toEndOf="@id/episodeImageView"
  app:layout_constraintEnd_toEndOf="parent"
  app:layout_constraintBottom_toBottomOf="@id/episodeImageView" />
<androidx.constraintlayout.widget.Group
  android:id="@+id/headerView"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  app:constraint_referenced_ids="episodeImageView,episodeTitleTextView" />
<androidx.constraintlayout.widget.ConstraintLayout
  android:id="@+id/playerControls"
  android:layout_width="0dp"
  android:layout_height="wrap_content"
  android:background="@android:color/background_dark"
  app:layout_constraintBottom_toBottomOf="parent"
  app:layout_constraintEnd_toEndOf="parent"
  app:layout_constraintStart_toStartOf="parent">
<Button
  android:id="@+id/playToggleButton"
  android:layout_width="34dp"
  android:layout_height="34dp"
  android:layout_marginTop="8dp"
  android:background="@drawable/ic_play_pause_toggle"
  android:scaleType="fitCenter"
  app:layout_constraintTop_toTopOf="parent"
  app:layout_constraintStart_toStartOf="parent"
  app:layout_constraintEnd_toEndOf="parent"
  app:layout_constraintBottom_toTopOf="@id/seekBar" />

<ImageButton
  android:id="@+id/forwardButton"
  android:layout_width="34dp"
  android:layout_height="34dp"
  android:layout_marginStart="24dp"
  android:layout_marginTop="8dp"
  android:background="@android:color/transparent"
  android:contentDescription="@string/skip_forward"
  android:scaleType="fitCenter"
  android:src="@drawable/ic_forward_30_white"
  app:layout_constraintTop_toTopOf="parent"
  app:layout_constraintStart_toEndOf="@id/playToggleButton"
  app:layout_constraintBottom_toTopOf="@id/seekBar" />

<ImageButton
  android:id="@+id/replayButton"
  android:layout_width="34dp"
  android:layout_height="34dp"
  android:layout_marginEnd="24dp"
  android:layout_marginTop="8dp"
  android:background="@android:color/transparent"
  android:contentDescription="@string/replay_button"
  android:scaleType="fitCenter"
  android:src="@drawable/ic_replay_10_white"
  app:layout_constraintTop_toTopOf="parent"
  app:layout_constraintEnd_toStartOf="@id/playToggleButton"
  app:layout_constraintBottom_toTopOf="@id/seekBar" />

<Button
  android:id="@+id/speedButton"
  android:layout_width="wrap_content"
  android:layout_height="0dp"
  android:layout_marginEnd="8dp"
  android:layout_marginTop="5dp"
  android:background="@android:color/transparent"
  android:text="@string/_1x"
  android:textAllCaps="false"
  android:textColor="@android:color/white"
  android:textSize="14sp"
  app:layout_constraintTop_toTopOf="parent"
  app:layout_constraintEnd_toEndOf="parent"
  app:layout_constraintBottom_toTopOf="@id/seekBar" />

<TextView
  android:id="@+id/currentTimeTextView"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:layout_marginBottom="8dp"
  android:layout_marginStart="8dp"
  android:text="@string/_0_00"
  android:textColor="@android:color/white"
  android:textSize="12sp"
  app:layout_constraintStart_toStartOf="parent"
  app:layout_constraintBottom_toBottomOf="parent" />

<SeekBar
  android:id="@+id/seekBar"
  android:layout_width="0dp"
  android:layout_height="wrap_content"
  android:layout_marginBottom="8dp"
  android:layout_marginEnd="8dp"
  android:layout_marginStart="8dp"
  android:progressBackgroundTint="@android:color/white"
  app:layout_constraintStart_toEndOf="@id/currentTimeTextView"
  app:layout_constraintEnd_toStartOf="@id/endTimeTextView"
  app:layout_constraintBottom_toBottomOf="parent" />

<TextView
  android:id="@+id/endTimeTextView"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:layout_marginBottom="8dp"
  android:layout_marginEnd="8dp"
  android:text="@string/_0_00"
  android:textColor="@android:color/white"
  android:textSize="12sp"
  app:layout_constraintEnd_toEndOf="parent"
  app:layout_constraintBottom_toBottomOf="parent" />

Confirming Changes With the Layout Overlay

Start by refreshing the Layout Inspector. Next, click the Load Overlay icon:

Exporting a Layout Inspector Snapshot

The Layout Inspector provides an export tool where you can save all the inspector details to an .li file. This snapshot file is useful for sharing with your team and viewing in Android Studio.

Validating Layouts

Before running your application, you can visually inspect your changes in the XML layout files with the Layout Validation tool. This tool helps you confirm that the layouts you write look correct across a wide range of device references, color settings and font sizes.

Devices Types

As shown above, the default configuration setting is the Reference Devices. Using this configuration, the Layout Validation shows the layout on a range of device types, including phones, foldables, tablets and even desktop configurations. This saves you time from having to load multiple emulators for each device type or gather actual devices and run the app on each one.

Custom Configurations

You can create a custom configuration based on the criteria that you want to validate. To do this, change the configuration set to Custom. Notice that the validation toolbar updates to include the Add configuration icon.

Colorblind Tests

It’s important to ensure your layouts are accessible to as many people as possible. In the Layout Validation tab, you can perform a layout test to confirm that your app is still accessible to users who are color blind.

Font Sizes

Along with the topic of accessibility, font sizing is another essential aspect to test. A common way of testing your app is by adjusting the font size via the Settings app and then opening your app and verifying that the changed font size looks good.

Challenge

Congratulations on condensing down those views in the episode player! But, there’s still more you can do. You converted the playersControl view to a ConstraintLayout in fragment_episode_player.xml. Improve that layout again and remove the playerControls layer altogether. After removing the layer, move its children into the root ConstraintLayout. Afterward, verify that the layer is gone by using the Layout Inspector and its 3D rendering mode.

Key Points

  • The Layout Inspector displays the views as layers in the UI hierarchy.
  • The inspector’s 3D render tool allows you to view the layers.
  • Add overlays in the inspector to confirm changes are accurate.
  • Export snapshots of the inspector for later use.
  • Validate layouts against device types, color blindness tests, and font sizes.

Where to Go From Here?

To learn even more about the Layout Inspector, read the associated Android developer user guide.

Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.

© 2022 Razeware LLC

You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a raywenderlich.com Professional subscription.

Unlock Now

To highlight or take notes, you’ll need to own this book in a subscription or purchased by itself.