Nona Blog

Android UI Gotcha’s — Diagnosis & Cures

Whenever I speak to non-Android Native coders, I always say that Android is tricky! There are so many obscure things that you just have to know and no where is this more evident than in XML layouts.

I don’t even want to know how many hours & days, I’ve spent banging my head against the wall trying to diagnose symptoms, causes and cures for some layout bugs! In this series, I hope to save you from the head banging I’ve had to endure.

As in medicine, a symptom can have multiple causes, however, the cures/solutions focused on in this article were particularly difficult to diagnose and solve. If I’ve missed an exception, or you think more information in a section could be useful, please drop a comment below and I’ll include it. 🙂

Illness #1: Jerky Scroll/Ghost Scrolling

Symptoms

  • Scrolling in a NestedScrollView isn’t smooth — seems jerky/doesn’t have momentum.
  • The NestedScrollView is scrolling down without user input. (Layout contains an EditText).

Cause

Both of the symptoms are related to focus (part of a UI selected by either the user/system):

  • Scrolling isn’t smooth because the system is unsure where to focus even if you don’t have anyEditTexts in your layout (This typically only occurs on very large layouts of a NestedScrollView that also contains a RecyclerView). Think about it this way — the system is like someone with ADHD that tries to focus on everything but doesn’t actually focus on anything in particular, and this results in jerky scrolling.
  • By default the system will always give focus to the EditText (or focusable element) closest to the top of the layout. If the top-mostEditText is toward the bottom of the layout (contained in the NestedScrollView), the view will scroll upwards (ghost scroll). This ghost scroll may not occur consistently, making this rather tricky to debug.

Cures/Solutions

There are two solutions, but I’d recommend the first one where possible.

1) Tell Android where to focus in your xml. Typically the focus should be placed on the highest level layout contained within the NestedScrollView. Usually, this would be aConstrainLayout. In some cases, you can set the focus in the parent layout containing the NestedScrollView.

android:focusable="true"
android:focusableInTouchMode="true

2) Tell Android not to focus on any elements (decedents) below the parent layout. Only do this if the first method doesn’t work because blocking focus means not views can gain focus even if the user clicks on the view i.e. anEditText wouldn’t be editable because it can’t be selected. But here’s the kicker: the keyboard might be displayed even though the EditText can’t be focused and buttons & other views can still register click events.

android:descendantFocusability="blocksDescendants"

Example:

<?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="wrap_content"
app:layout_behavior="@string/appbar_scrolling_view_behavior">

<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="@string/appbar_scrolling_view_behavior" android:focusable="true"
android:focusableInTouchMode="true
<!-- OR --> android:descendantFocusability="blocksDescendants"><!--XML Content for your layout--> </android.support.constraint.ConstraintLayout></android.support.v4.widget.NestedScrollView>

Other Potential Causes

Doing too much on the MainThread resulting in frames being lost. It’s uncommon to be intentionally doing so much on the MainThread that you lose frames — it’s much more likely that you have a memory leak or you’re doing network calls on the main thread (the latter is very naughty and not in the good way).

Illness #2: CollapsingToolbar — Not Collapsing

Symptoms

You have an activity or fragment containing a CollapsingToolbar and the content below it has variable length. You’re sure that you’ve got the right scroll flags but it just doesn’t scroll occasionally.

Causes

When content below the CollapsingToolbar doesn’t fill more than the visible area available to it, the CollapsingToolbar will only collapse if you scroll on it (not if you scroll by placing your finger on the content & drag up). This behaviour makes sense if your content is a standard size but if it isn’t the user will expect it to scroll.

Cures/Solutions

The easiest way to solve this issue is if you set a minimum height on the NestedScrollView or whatever is the main layout below the CollapsingToolbar. I’ve found a minimum height of android:minHeight=”600dp” to work well for most cases.

Potential Complications

There are some complications that can arise when up use a NestedScrollView in a fragment. If you encounter issues here, you are most welcome to get in touch with me and I’d be happy to help.

Illness #3: Shadows/Elevation Cut Off

Symptoms

Usually cut off at the bottom (can be a CardView or any layout/view with an elevation).

Causes

  1. It appears that a parent (to the layout with elevation) layout’s bounds cutoff the shadow of its children for some reason.
  2. Shadows set with android:elevation are cutoff by the child’s bounds. Extending the bounds of the view with margin or padding does not have an effect. It appears that they are cut off by the child’s original bounds.
  3. It therefore seems that the parent is clipping the child.

Solution

  1. Set padding on the parent (if needed) and set android:clipToPadding="false" on that parent.
  2. By default shadow is determined by view’s background, so if there is no background, there will be no shadow. You may therefore also need to set a non-transparent background color on the child layout that has the elevation. Alternatively you can also android:outlineProvider="bounds" which will provide the color it requires

If you have any suggestions for topics that could covered in a Part II, please drop a comment below and attempt diagnose and put forward cure. Lastly some shameful self-promotion: if you liked this article — give it some claps; if you learned something — give me a follow and you’ll notified when Part II is released.

Adrian Bunge

Adrian Bunge

Add comment