This is driving me crazy. Something that is implemented by default in ListView is missing from RecyclerView.
I want to have the exact behavior of a listview which is set to single choice mode. I tried the solution from this question but it doesn't fully solve the problem. When I touch the list with 2-3 fingers etc it may only highlight one row indeed, but if I lift my fingers rapidly everything gets triggered even tho only one row is highlighted each time. (I can also hear the sound effect from my phone that gets repeated 3 times very fast)
Basically I want to disable multi touch events from the phone so that the list is forced to select only 1 item each time no matter how many fingers the user uses
To disable multi touch in recyclerview, you can use
android:splitMotionEvents="false" in your recyclerview tag in layout file.
By that attribute, you will not receive multi touch in recyclerview.
The problem is that i start a new thread every time user clicks on a row so if i try to multi touch the recycler's items, even in your sample app more than one threads start simultaneously and unexpected results happen.
That has nothing to do with multi-touch. You would get the same effect with one finger, rapidly tapping on different rows. It may be easier for you to reproduce the effect via multi-touch, but there is no guarantee that the user will never tap a second row while the thread for your first row is still outstanding.
Your problem is with your implementation. Either:
Tapping on multiple rows in rapid succession is fine, and you need to fix the "unexpected results", such as serializing the threads, having a single thread and a LinkedBlockingQueue, or synchronizing access to shared data, or
Tapping on multiple rows in rapid succession is not fine, in which case you would need to track whether a thread is outstanding when the user taps on a row, then decide what to do (discard the event? queue the work to be done, so it is performed after the current thread is done? something else?).
Another possibility would be to get rid of the "fork a thread on a list row click" entirely, and require a more positive step (e.g., click some Done button) before you do whatever work it is that you are trying to do.
Related
I have a basic RecyclerView setup on a chat-like app and I have hit an issue with the item animations.
The project is making use of Room with Paging 3 and DiffUtils for the RecyclerView adapter, so this is all automated, but the core of the problem can be simplified to this:
When I send a new message, that message is added to the RecyclerView
here the adapter is triggering notifyItemInserted or notifyItemRangeInserted which causes the entire message list to shift up softly and the new message fades in after
I scroll the list to the bottom so the new added item becomes visible
When I receive a read status from the server I update the status of that message
here the adapter is triggering notifyItemChanged or notifyItemRangeChanged which has no default animations on its own, it just updates the item with the new information
All of this is working well on its own, but the problem is when I receive a status update from the server faster than the insert animation has a chance to finish. When that happens the notifyItemChanged or notifyItemRangeChanged kicks in and skips the animation initiated by notifyItemInserted or notifyItemRangeInserted. The list till shifts upwards, but the fade in no longer happens, instead the item is instantly made visible all the while the list is still shifting up, overlaying the item previously occupying that last position causing an ugly visual experience.
I can kinda "cheat" by delaying the step in 2. to engage after the animation is supposedly over, but then it introduces another visual issue if the user sends multiple messages quickly or receives them in the same fashion or in certain cases it just does not show any animation because the new item is loaded outside of the list and only scrolled after the animation time is elapsed, so this is not a solution.
first
second
In this example there are 2 recyclerviews set up with the same adapter slightly changed to make it easier to compare the issue in the same action.
The left recyclerview is not doing any update when an item is inserted, but it is the behavior I expect to display even if I update the item during the item insertion animation.
On the right recyclerview is the actual problem, as you can see new items are showing in full over the old ones before they have a chance to move out of the way.
The first example recording has scroll to bottom with no delay after the item is inserted, the second example has a delay that matches the insertion animation duration.
Reminder: this is just a manual example, the real application in my case is being done automatically via the integration I mentioned above, I am not the one in control of when the notifyItem* calls are made at any point.
How can I make sure the insert animation does not get interrupted even if I am updating the item data in the middle of the animation?
EDIT: I already searched for a solution in the questions posted before, but none are related to this one nor do the similar ones provide a solution to my problem.
I would like to start by saying if you can think of a better title for this problem, feel free to change it since I have no clue how to explain this in a short way.
So here is my problem:
For the application I am trying to make I have these schedules, one schedule for today, and one for upcoming days. Both of these are a listview inside a fragment.
(I used those fragments to create tabs to seperate the two.)
Each game (let's call them games because calling them activities would be confusing) on the schedule has a status, and here is where the annoying part comes. I have been asked to check if any game has been started, and if so I need to disable the buttons to start any other game than the one that is already ongoing.
EDIT: The main problem is that I cannot use findViewById on the listview item because apparently it is a null object reference
I made a little "paint"ing to give you more of a graphical representation.
So long story short, I need a way to check the status inside of every listview item inside of the listview inside of the fragment inside the activity to use said status to disable every button except for the one of the ongoing game.
Little side note: If no games have been started yet, all buttons are enabled.
I hope this made sense.
If you want some code to go with this, feel free to ask but be warned, I am making this inside a testing app so a lot of useless testing data and sloppy code.
EDIT:
This is where I am stuck in a more clear example:
The start buttons are enabled but should be disabled.
Scrolling further down the list, there is a started 'game' and right below it, a game with the same status as in the previous picture where the button is disabled as it should be.
This is because the "isStartable" boolean in my code goes to false after the game with status "start" has passed and the following items are disabled.
When I scroll back up, it is how it should be, the items are all disabled but I need them to be like this when the listview gets filled. Any way to refresh the data in this listview and taking the "isStartable" boolean with it?
This is what it looks like after I scroll back up.
create a model class for your listview data items. Set a boolean variable in model class like isGameStarted. Set that variable as per your result.Then in your listview adapter, put a condition as below
if(isGameStarted){
holder.startButton.setEnable(true);
else
holder.startButton.setEnable(false);
I have a ListView with some products names. What I have to do is to change the layout of one row when the user performs double-tap on that row, with another layout which has other data regarding the product. Is this possible? If yes, how can I do this?
Thanks in advance
I dont if I have understood clearly what you need but it is possible.
1. Make a custom listview (the listview must have all the components needed when double-tapped)
2. At start hide all the components except the textview which has the products name.
3. On double tap show the components of the tap row (visible = true)
Note: As for double tap it is another matter. You should consider Long Press instead.
See this question for a similar setup How to detect a double touch/taps on an Android ListView?
There an answer points to http://developer.android.com/guide/topics/ui/ui-events.html
If you really, really want to handle double-click you'll have to handle the OnClick() event and count the first click as part of the double click.
Register a delayed handler for the single click action (if there should be one).
When you next receive an OnClick() event then calculate the time between that click and the previous one. If it is below some arbitrary threshold then you count it as a double click. Cancel the delayed SingleClick handler and run your DoubleClick Handler.
But it'll be brittle; could confuse the user and will be more difficult to build and maintain.
So, in short, use OnLongClick() instead of OnClick(). The Twitter app is a good example of the use of this UX.
However, once you've decided how to capture the event take a look here for a blog post on replacing individual items in a ListView
I have a list that uses a database to display some data. There are several operations that the user can perform on each list item and instead of implementing a context menu where the user uses a long press to bring up a list of possible operations I would like to add buttons to each item so the user can just tap the button and perform the operation. The list can be potentially large and attaching a listener to each button for each list item is overkill so I would like to do what Javascript programmers do with event bubbling, i.e. attach a single handler to a top level element like the entire list and let the click events bubble up to it. How would I go about doing this?
View.OnClickListener.onClick() does not bubble, so the solution you propose would not work.
OTOH, View.OnTouchListener.onTouch() does bubble so this could possibly be used, but it would require you to manually handle MotionEvent's down/up to detect a click.
Besides, if you create a lot of Buttons, than are you sure that adding onCLick handlers would be a lot of overhead, especially since you can register the same method for all of them.
What you are trying to do sounds like a premature optimization. Be sure there is real overhead affecting your users, before you try to deal with it.
I have a ListView backed by customized ArrayAdapter where each item has 2 LinearLayouts - one I call head, and the other one - body.
The body is hidden (gone) until user clicks on the row at which time it slides out. The second click (on the head) will hide the body. However if user clicks on the body it brings another activity. All of this works just fine, here comes the problem:
When user presses on body I want a visual indication of the action just the same way as regular list item will flicker an orange background when pressed. I'm not getting this by default since (my theory) the onPress event is intercepted by body's view and not processed by the list item.
The first thing I tried was to execute body.setBackground('#ff00ff') (never mind the color) in onPress event. That didn't work since (I suspect) there's no repainting after the call. Then I dig a little bit more and decided to use <selector/>-based background. I defined body_background.xml in drawable folder and assigned that to the body's background property.
There I noticed that background will only change if the even is processed by the list. For example if I set <item android:state_selected="true" android:drawable="#drawable/selected"/> then when I press on the head - the background of both elements (head and body) will change, however when I press on body - nothing.
So to summarize my question - how do I change background of the child element in the list item if I assign custom onClick handler to it? Any hints will be greatly appreciated
OK. Here's some more info I dig along the way.
I'm currently trying to switch implementation to ExpandableListView which provides the functionality I had to coded in (sliding body). The problem I may have here is that I have a fancy "endless" list implementation and I'm using ArrayAdapter#add method to dynamically add items to the list while scrolling (see my tutorial on androidguys.com) Well, the add method is missing from the BaseExpandableListAdapter so I need to see if adding items to internal array will work (it didn't for ArrayAdapter) possibly doing ExpandableListView#notifyChanged() will take care of that
The fact that I don't see anything when I'm directly using setBackgroundColor method is probably due to the subsequent call to startActivity call that halts all painting until new Activity is displayed
P.S. this has been resolved by switching to ExpandableListView. And may I add - it's beautiful! No need to invent anything