2

Situation

Need to present text files as a list of editable sentences or phrases as shown in the example below, for the purpose of a speech therapy tool. This was relatively easy.

Ode To A Small Lump of Green Putty

The colored flags can be added, removed, or dragged to new positions as needed, and can be set to snap-to-character or snap-to-word (they will also eventually display data).
This was achieved by sub-classing EditText, to take advantage of all the in-built features like word-wrapping, spell-checking, text-selection etc.

Problem

The number of phrases or sentences in a document can be large, so using a simple LinearLayout in a ScrollView to display them is no good in this case.

To efficiently display my FlaggedEditText widgets the solution needs to take advantage of view recycling, so ListView is an obvious consideration. But as shown by the number of S.O. questions out there, ListView and EditText don't play nice together.
The requirements of the list are that:

  • FlaggedEditText widgets get focused when touched (the item containing the FlaggedEditText also gets selected).
  • Notification when an item in the list has been edited (including which item).
  • Standard gestures such as fling.

I've tried out numerous approaches suggested in the many S.O. questions over the past few days, to try and bend ListView to my requirements, but all seem to have their own short comings and result in hacky, messy code.

Questions

  • Does anyone know of any existing alternatives to the standard Android ListView out there, that are more EditText friendly?
  • Alternatively, does anyone have a clean, efficient, definitive approach to getting EditText working as desired in the standard ListView?
  • Finally, I'm considering sub-classing AdapterView to make my own FlaggedEditText specific ListView alternative. But if the issues stem from AdapterView of which ListView is also an indirect subclass, then I'd be wasting my time. Has anyone already been down this path?

Edit

Jim's excellent response below, and a recent viewing of Romain Guy and Adam Powell's old Google I/O 2010 presentation The world of ListView have suggested a possible solution.

In the I/O talk I was reminded that they convert views to bitmaps for some of their optimizations. Since only one EditText at a time can ever be focused for editing, I'm thinking I can sub-class ListView to provide an interface which, if ChoiceMode is single, will give the Rect of the selected Item and bitmaps of the ListView regions above and below the selected item. This could then be used to temporarily overlay the ListView with a vertical LinearLayout containing the "above" bitmap, an active FlaggedEditText and the "below" bitmap.

In this way, the FlaggedEditText widgets can effectively act as non-focusable EditText's in the ListView, but when an Item is selected, interaction is with the temporary overlay.
The "above" and "below" bitmaps could also easily be tinted to suggest inactivity.

Additional
In fact, I've just realized I probably don't even need the Rect of the selected Item from the interface. The "above" and "below" bitmaps and a FlaggedEditText using the same LayoutParams as per the ListView should be enough.

Sound Conception
  • 5,263
  • 5
  • 30
  • 47

1 Answers1

3

Many of the answers out there do not seem to describe the core issues surrounding this "problem" and why it is not "solved." The "problem" you face is that an EditText can expand and/or scroll, along with your ListView. Also, the expanding soft keyboard forces the ListView to redraw causing problems with keeping track of the focused item. And when an item is focused and has dynamic content, UX confusion can occur with touch gestures (e.g. if you touch an item in an EditText like the cursor and then swipe, did you want the cursor to move? Or the entire list?) It can lead to a lot of user frustration.

I'm sure you've seen this post:

Issues focusing EditTexts in a ListView (Android)

This creates problems in correctly displaying the elements within the ListView, problems with recycling properly (the redraw) and problems with gaining focus correctly. It is possible that creating a custom class that extends AdapterView will work, but it will probably still feel like a hack, and probably will not work as you want it to or it will be a large effort.

You will need to do a lot of backend measuring of the fonts, images and "visible" (or partially visible) items in the custom object that also account for the keyboard animation and dual scrolling (the ListView can scroll and so can the EditText - or the EditText will change in size, forcing the parent custom AdapterView to determine if it should also scroll and whether views have become visible or invisible as a result of adding or removing text/images from the focused object).

If you make assumptions like "the EditText will never be larger than X height" then you may get it to work, but obviously that is a very customized solution, which is why it is not easily implemented and isn't supported generically.

Also, you will need to make UX decisions about how to handle a focused item that has scrolled off the screen (you can track it easily, but if it scrolls back onto the screen, but it can interrupt user expectations about how swipe and touch gestures are handled - for example, does the cursor in the EditText move or does the entire list? if an image is touched, does a swipe move the image or does it scroll the list? You can assume it is not focused, but then a "redraw" event can make it lose focus unexpectedly, like the current ListView implementation.) In other words, you are likely to end up with many unanticipated odd UX issues...

Your best solution will probably be to use a dialog pop-up as mentioned in the post I referenced above. Or, when an item is tapped to be edited, you could have a layout appear above or below the ListView. You may possibly get the ListView to scroll and lock to it - to have it appear as if it were in the ListView - but again, that would be hard with the soft keyboard changing the usable portion of the screen - you can expect "drag" or a slow feel to the "snap" effect. And you will need a "done" button...

To get your custom EditText to work with this suggestion, in the ListView you could disable it and make it non-focusable, then place an empty layout over the entire EditText that captures and processes the touch/fling/swipe events. This "invisible" layout may be the only option you really have.

In other words, you should probably plan to change your UI/UX rather than try to force Android to figure out how to handle several dynamic, and possibly conflicting or unpredictable, aspects of the UX interaction of these layouts.

Community
  • 1
  • 1
Jim
  • 10,172
  • 1
  • 27
  • 36
  • Thank you for an excellent response. Yes sub-classing `AdapterView` would be a lot of work. I recently re-watched the old I/O 2010 [The world of ListView](http://www.youtube.com/watch?v=wDBM6wVEO70) presentation, and was reminded that they convert views to bitmaps for some of their optimizations. That, and your thoughts suggested a possible solution. See my edit. – Sound Conception Dec 12 '14 at 08:51