I want to set an initial scrolled position to a ListView.
I thought I could do that by calling list.setSelectionFromTop after adapter.notifyDataSetInvalidated, but of course the later only notifies the listview and the actual population may happen later.
Is there a way be notified when the listview has populated itself, so I can change the scroll?
Ok, so I tried onFinishInflate and onSizeChanged, but they didn't work. The later worked if the number if items changed, but not if the data was simply altered.
I then tried everything else, and the working methods to override were onFinishInflate and onSizeChanged. These are however also called on scrolling.
In fact, the last line in ListViews layoutChildren is a call to invokeOnItemScrollListener, so it turns out you don't have to extend ListView, but can simply set an onScrollListener.
No matter what solution you choose, you do however need to manually work around the problem of methods being called on scroll.
Related
As far as I can tell, Views only receive DragEvents if they had implemented onDragEvent() or had set an OnDragListener before startDrag() (or startDragAndDrop() for API 24+) is called. They will then continue to receive additional drag events if they return true for DragEvent.ACTION_DRAG_STARTED.
However, I am looking for a way to receive DragEvents after a drag operation had already started, for Views that got added to the layout during the drag operation.
To illustrate why, my situation is roughly the following:
I have a ViewPager2 with ListView fragments whose list items can be dragged. If I drag an item over another item, I "enter" that item and a new ListView fragment is shown with new child items. This works fine.
However, since these new child items didn't exists at the time of starting the drag operation, they don't receive DragEvents when I continue to drag the item over those new items.
So, basically, I want to be able to enter multiple levels deep in one continuous drag operation.
Is it possible to have newly added Views receive DragEvents for an ongoing drag operation?
Okay, I've managed to solve it by re-dispatching the original DragEvent (the one with action DragEvent.ACTION_DRAG_STARTED) to my main component, which is an instance of ViewGroup.
On inspecting the source code for ViewGroup.dispatchDragEvent() I found that ViewGroup has a member variable called mChildrenInterestedInDrag that gets filled with children interested in drag events, when DragEvent.ACTION_DRAG_STARTED is received.
So when I called ViewGroup.dispatchDragEvent() with the original DragEvent, after I entered an item in the list to view its child items, those new ListView child items were now responding to additional DragEvents.
I'm a bit worried that this approach might yield unexpected side effects. If I come across such effects upon further testing, I'll update this answer. But for now it will do.
If somebody knows that this indeed might yield unexpected side effects and/or has a better solution I'd love to hear them.
Addendum:
Upon storing the original DragEvent for re-dispatching, I had to "clone" the event, because, while it worked properly in an API 19 emulator, on an API 19 phone the original DragEvent's action were continuously altered during dragging, so its action wouldn't reflect DragEvent.ACTION_DRAG_STARTED anymore and re-dispatching didn't have the desired effect of registering newly added Views as interested in the ongoing drag operation.
Since DragEvents cannot be cloned or constructed, I had to "clone" it with the help of a Parcel:
void storeStartEvent(DragEvent startEvent) {
Parcel parcel = Parcel.obtain();
startEvent.writeToParcel(parcel, 0);
// important to "rewind" the Parcel first
parcel.setDataPosition(0);
this.startEvent = DragEvent.CREATOR.createFromParcel(parcel);
}
Other than that, I didn't experience any noticeable problems yet, so it may have just solved my issue nicely.
I've got a RecyclerView which contains items, obviously. It uses the DefaultAnimator for all its animations.
When deleting an item, the deletion is animated, but not as it should be. The issue is that it seems like the size of the list is reduced by one first, then the clicked item is deleted and afterwards all items below are moved upwards by one. Take a look at this short video to see what I'm talking about.
The code used for the removal of a item is the following:
MainActivity.events.events.remove(listItems.keyAt(0));
notifyItemRemoved(listItems.keyAt(0));
Where MainActivity.events.events contains the data for the items and listItems.keyAt(0) contains the currently selected item.
What I've tried yet (none of this worked):
Made sure there's no other call which interrupts the animation (like notifyDataSetChanged()).
Implemented the above code directly into a onClickListener for the items inside the adapter.
Implemented the data directly into the adapter instead of a different class.
Replaced the position with getAdapterPosition() or a fixed value (i.e. 0)
Used notifyItemRangeRemoved() after notifItemRemoved().
Hint: I've got the animation to work previously, but as of today it doesn't work anymore.
EDIT:
If I remove the actual removal command (i.e. MainActivity.events.events.remove(listItems.keyAt(0));) from the code snippet given above, the animation is played correctly, but the element then isn't actually removed, so this doesn't solve the problem at all.
In my app i have a ListView with an ArrayAdapter. Every Item contains a picture, which takes a bit of time to render.
Now i want to add items dynamicly at the end of the List. The problem is, that wehenever add() is called my List blinks, because notifyDataSetChanged() is called and my pictures take a few milliseconds to render. I tried to avoid this by calling setNotifyOnChange(false). I solved the blinking with that, but unfortunately it is only updating the "length" of my list irregularly.
Is there some way to update the "length" of my listview, without updating the views which are shown?
I would agree that the UI thread should be avoided, especially for lists, and especially when using images for each list item.
Perhaps you need to find a more robust list adapter that is geared towards images? See this question for some helpful ideas/hints at how to improve your own list.
Also, the AndroidQuery (AQuery) library may be useful when fetching images for use in the arrayadapter: Image Loading via AQuery. It takes care of the burden of image caching as well, which I have found to be quite useful.
Good afternoon,
I have a list view that show a list of items...well not all of them but they are all there. Rather than let the user scroll up / down the requirement asks for and up / down buttons. I have everything handled quite well EXCEPT how to advance the ListView. Say I'm looking at item 3 in the list. The user hits next...I want to ListView to advance to item 4. I am keeping track internally of which page they are on for incrementing / decrementing. I was expecting to find something like this but no dice.
ListView.MoveNext();
or
ListView.Move(int);
Per Brayden's suggestion I tried the accepted solution here: Maintain/Save/Restore scroll position when returning to a ListView and it did not APPEAR to scroll the list....i.e. it stayed on the first list item. I also tried setSelection.
Here is my code:
public void btn_NextClick(View vw_Current)
{
//increment page count 1
i_PageTracker ++;
//advance to next record
//int x = lstvw_LiftData.getFirstVisiblePosition();
View v = lstvw_LiftData.getChildAt(0);
int top = (v == null) ? 0 : v.getTop();
lstvw_LiftData.setSelectionFromTop(i_PageTracker, top);
//lstvw_LiftData.setSelection(i_PageTracker);
}
Based upon Vladimir's success and my lack thereof I wanted to provide some additional info that I thought irrelevant but....
I've extended the SimpleAedapter and override the getView. I also have a DataBinder to populate TextViews with certain data from the data object.
Interestingly when I set a breakpoint in the getView of the DataAdapter and the setViewValue of the binder at load we hit them as appropriate. However when the next button is clicked we do not hit them which I would expect if the list was advancing to the next position....hmmmm I wonder....I have another Idea....be right back.
I figured it out....but I don't know what to do about it. See not knowing what I am doing I shot myself. I ONLY want to see one item in the list at a time and I don't want the user to be able to scroll. Well what I did to accomplish that was to override getCount in the DataAdapter and return a 1. This SEEMED to be the answer as only one item displayed cool! But then overriding getCount also means there is only one item to display so we never advance...there's nothing to advance to.
So what I want to know is this. How do I keep the user from being able to scroll and force them to use the navigation button. Do I handle the scroll event and return null?
I figured it out....but I don't know what to do about it. See not knowing what I am doing I shot myself. I ONLY want to see one item in the list at a time and I don't want the user to be able to scroll. Well what I did to accomplish that was to override getCount in the DataAdapter and return a 1. This SEEMED to be the answer as only one item displayed cool! But then overriding getCount also means there is only one item to display so we never advance...there's nothing to advance to.
So what I want to know is this. How do I keep the user from being able to scroll and force them to use the navigation button. Do I handle the scroll event and return null?
I'm trying to make it so that the user can drag a textview from one listview and then drop it into another, and I'm finding it to be very difficult.
The biggest problem I have found so far is that onTouchEvents seem to only be heard in the view that the ACTION_DOWN event originated in. I'll click in one list and the ACTION_DOWN is heard in there. Then I'll drag outside the list and let go over another list. But the onTouchEvent is only being called for the original list, no matter where I'm going. I thought it was going to be as simple as listening for an ACTION_UP event in the receiving list; but that's called on the original list even though I'm outside it.
What I have so far is a bit messy. When onLongTouchEvent is called, the list tells the main activity to start dragging a draggableTextView (which has a moveTo method). Since the move events continue to be called on the original list, I have it continually setting the position of this draggableTextView. But I can't insert it into another list because I can't figure out what I'm letting go on top of.
Yes, you are right, this is not an easy task. However it is possible: you might check commonsguy's cwac-touchlist example.