I am trying to make a ListView for showing lyrics. I have very little experience with making custom compound views. So I would like to know what my approach should be to make this view. The ListView must have these features
auto-scrolling based on the song (the timing information will be stored in the list adapter)
highlighting the current line which is being played on the audio
indentation on some lines to make it look more like a nicely formatted poem
users should not be able to scroll the list when the song is playing (i.e. the list is being auto-scrolled) but it should be scrollable when the song is paused
I don't know if the view should extend list view or not. If not then what should it extend and what should be my approach?
Frankly, I really don't have enough information to answer this completely, but this is what I would do:
If it were up to me, since you don't want a scroll capability at all (you want to make it appear as if it is scrolling, not to actually allow the user to scroll), I would not use any of the complex views like ListView or ScrollView, I would just write a custom view, simply extending View. I would override it's onDraw() method and use Canvas.drawText(...) to draw the words, having two different Paints, one for the current word and another for all other words. As for the "scrolling" effect, you can keep a number that represents the current top line that you can see, and add one to this number when you want to scroll to the next line. However to make it smooth you can manipulate where exactly you start drawing the texts and move it slowly upwards, so that it would appear that everything is scrolling down.
** Maybe it would be better to use SurfaceView here instead of just View, especially if you want a background image and smooth blending and better a look, since SurfaceView is much better for complex drawings **
If that is too complicated for you and you want to use existing views entirely without doing any of the drawing yourself, I would recommend a vertical ScrollView, you fill the ScrollView with horizontal LinearLayouts for each line, and each of those is filled with TextViews for every specific word. You can programatically build the TextViews and the LinearLayouts. Use ScrollView's scrollTo(...) or SmoothScrollTo(...) to scroll to the right location. You can prevent the user from scrolling by capturing all the motion events before they are used to scroll.
Both approaches will of course require you to maintain some form of data structure to hold the times each word is selected.
Related
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.
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.
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.
I am creating layouts at run time using heavy data, and adding these layouts to a scroll view. After the view get created, its working fine. The problem here is, the data is very heavy and it takes more than a minute to create the screen, which is not so good user experience. I want to create layouts only for the part of screen that are visible, and rest I can create on scrolling the scroll view. Pls suggest how is that possible? Also, If someone has a better approach, Pls suggest.
You can start by creating only a set number of views each time[1], but always add a dummy 'loading' view at the end of the list if there are more views 'pending'. As soon as the user scrolls the ScrollView at the end of the list, start loading the next part of views on a background thread, and as soon as they are built, remove the dummy loading view, and add the new views into your container.
An other approach would be to start loading the next group of views, as soon as the previous group is done finish, but that might be a waste of resources.
An even better approach, is to combine those two methods described, and always have the next group of views being created, if the user is halfway done scrolling to the end
You can check how to know when the scrollview scrolls to the bottom here: Android: Detecting When ScrollView Hits Bottom
[1] Since you care about UX I would suggest that the number of rows should depending on the row's height and device max height. I.e. 4 views on a small device, 6 on a medium, 10 on a large.
I created a scrollable custom ViewGroup which has several >200 EditTexts in it (not all of them are shown at the same time - I am using a recycler). The problem I am having is that the scrolling is very slow.
Interestingly, I don't have the problem if I do one of the following
1) disable the editText [editText.setEnabled(false)]
or
2) If I change the view from EditText to TextView
Any ideas on what the issue could be?
EditText is huge. Take a look especially at all those methods it inherits.
Why don't you try using just one EditText with 199 custom TextViews or a large grid of rectangles drawn within a Canvas? You could always customize your TextViews (or your drawn grid of rectangles) to make them look like edit boxes, but only use one EditText for the cell that has the focus itself.
That's even how Excel works for some of the functionality it has. It can edit a cell directly (yes), but it also has a static cell on the upper left of the Excel spreadsheet to show you the content of a formula (that may already be rendered as a view within the focused cell itself). You could do something similar yourself. You could extend an EditText to do all the hard stuff, like auto-complete, etc, but you could just draw the text inside the rectangle that has focus (or insert it inside the particular TextView that has focus).
Take a look at this example:
https://github.com/dennis-sheil/android-spreadsheet
He seems to be using mostly TextViews (although TextViews are heavy too, I'm starting to think that the Canvas may be better for something like this, and that everything could be simulated with the drawing method, by everything I mean the blinking cursor, the highlighting of the cell, the character by character typing, etc). With the Canvas at least, you can easily tell it what part needs to be drawn, and what part is off the screen and doesn't need to be drawn, so you're less likely to get into memory problems.
It can be issue with focusing the EditText during the scroll or you create too much objects and it is slow. Use ListView with EditText. Recycle views using viewHolder pattern. It will be smooth but I'm not sure if it is what you are looking for.
I have a ListView in my Android application. The individual views in the list are a little bit smaller than the size of the screen.
I want the list to always show one item centered in the screen, with just a small sliver of the previous and next items showing above and below it.
When the user scrolls, I need to reposition the child view at position 0 or 1 (depending on which way they are scrolling). Currently I am doing this by calling "setSelectionFromTop" in my onScrollStateChanged method. This works, but the transition is immediate, not smooth. It is jarring and confusing in a lot of cases.
What's the best approach to fixing this? I want to animate the process of scrolling the list into the position I want, but I can't find any methods in ListView or its superclasses that let me directly control the scroll position of the entire list.
I think I could animate it using multiple calls to setSelectionFromTop(int position, int y) with progressive values of y, but I don't know how to determine the initial value of y. Is there some way to get that by interrogating the view object at the designated position?
Another challenge I have in front of me is that I want to animate the removal of an item from the list - by having it either disappear or slide away to the left, and then having the surrounding views move up and down to fill the space. Is there a straightforward and reliable way to do this with a ListView? Should I just give up on the ListView and write the whole thing as a custom view from scratch?
Thanks.
This definitely should be possible. Does smoothScrollToPosition() work?
Otherwise, you can try simulating the touches using TouchUtils.
I have a quite problematic UI layout to implement, and I'm not sure if it's even possible using standard UI widgets. It looks something like this:
Picture 1
The green, lined thing is supposed to be a ListView, and the red rectangle is another View. This red View should be scrolled with the ListView, as if it's part of it. Some list-elements should also be narrower, because that embedded View gets in their way. Could you please recommend any ideas? Can this be done somehow with the Android UI framework? I was thinking about some kind of a floating View above the ListView, which reacts to the List's scrolling events too, but it doesn't seem like an elegant solution.
Thanks
I don't think you can accomplish that easily with a ListView. You could do the overlay using a FrameLayout, but it would be very awkward to get it to stay probably aligned as the user scrolls.
How many elements are you talking about?
I would probably use a LinearLayout within a ScrollPane to simulate the ListView.
Or, a TableLayout where the overlayed view is contained within a single, complex row.
I would set the green rows that the red block overlap and the red block as one big view in the listview. So the items in your listview would be (for the example pic) two green rows, then the view of three green rows and the overlapping red block, and then the remainder of the green rows.
Trying to have the red block on an overlay that scrolls with the listview sounds like more trouble than it's worth.