Does anyone know of a way to center a ListView based on its current selection or selection set with setSelection?
I did see this other StackOverflow question without any answers: Android ListView center selection
Thanks,
Kevin
First, get the height of the ListView using getHeight, which returns the height of the ListView in pixels.
Then, get the height of the row's View using the same method.
Then, use setSelectionFromTop and pass in half of the ListView's height minus half of the row's height.
Something like:
int h1 = mListView.getHeight();
int h2 = v.getHeight();
mListView.setSelectionFromTop(position, h1/2 - h2/2);
Or, instead of doing the math, you might just pick a constant for the offset from the top, but I would think it might be more fragile on different devices since the second argument for setSelectionFromTop appears to be in pixels rather than device independent pixels.
I haven't tested this code, but it should work as long as your rows are all roughly the same height.
You will need to have the scroll view and the view of the item selected. Then you can simply do:
scrollView.smoothScrollTo(0, selectedView.getTop() - (scrollView.getHeight() / 2) + (selectedView.getHeight() / 2), 0);
This will center the scroll view exactly on selectedView
I haven't tried any of this but based on the current selection could you use public void smoothScrollByOffset (int offset) to get the view to scroll to where you want so that your selection is in the middle of the view?
Related
I am trying to get the location on screen of the ListView scrollbar thumb indicator. I'd like to position a label next to it and require the X,Y screen coordinates.
I attempted to get the height of the ListView and use the value from the 'firstVisibleItem' value obtained from the ListView OnScrollListener to position the label but due to the ListView items having varying heights this hasn't proved feasible.
Are there any other solutions to this?
Thanks
I suggest you can use a little bit of hack:
View c = listview.getChildAt(0);
int scrolly = -c.getTop() + listview.getFirstVisiblePosition() * c.getHeight();
But it will work correctly only if you will have same height for all list items.
Is it possible to make fixed (sticky) header row in ListView, but I want it to behave like on this picture:
So, when it's not scrolled I want to show "big" header, but when user scrolls down enough, header should go to limit value (50% of header row height or something like that)... I tried to use this library:
https://github.com/applidium/HeaderListView
But I didn't success with implementing this behaviour. It's possible to make the whole (full height) header row fixed, but not half or one part of it.
Use
View c = listview.getChildAt(0);
int scrolly = -c.getTop() + listview.getFirstVisiblePosition() * c.getHeight();
To get the current Y offset, then play witn onScrollListener to set the size of your header. This basically gets the position of the first visible item, multiplies it by the height of 1 row item and adds the height of visible part of the first item resulting in offset in pixels from the start of your listview.
from an answer to one of my other questions I found an Google Demo of a ListView subclass that allows item reorder.
The demo works great, but I am having some trouble to understand how the it works:
When an item is dragged above/below the bounds of the ListView, the ListView starts scrolling up/down to reveal new items. The necessary calculation uses different parameters of the underling ScrollView:
public boolean handleMobileCellScroll(Rect r) {
int offset = computeVerticalScrollOffset();
int height = getHeight();
int extent = computeVerticalScrollExtent();
int range = computeVerticalScrollRange();
int hoverViewTop = r.top;
int hoverHeight = r.height();
if (hoverViewTop <= 0 && offset > 0) {
smoothScrollBy(-mSmoothScrollAmountAtEdge, 0);
return true;
}
if (hoverViewTop + hoverHeight >= height && (offset + extent) < range) {
smoothScrollBy(mSmoothScrollAmountAtEdge, 0);
return true;
}
return false;
}
heightis the height of the ListView itself
offsetis the scroll position = how many units/pixels have been scrolled up/down
rangeis the height of the complete content.
extent - well, what is this?
ListView inherits computeVerticalScrollExtent() from View and the docu says:
Compute the vertical offset of the vertical scrollbar's thumb within
the horizontal range. This value is used to compute the position of
the thumb within the scrollbar's track.
If one looks at the code computeVerticalScrollExtent() is not implemented by one of the sublasses but only directly by View: It simply returns the height of the view.
This makes sense: If the ListView/ScrollView has a height of 500, the part of the scroll content that is visible at a time is also 500. Is this the meaning of the ScrollExtent? Why is ScrollExtent necessary? Why not simply use getHeight() directly?
I think I am missing something and I am happy about any hint!
compute*ScrollOffset - Defines the distance between the start of the scrollable area and the top of the current view window inside the scrollable area. So for example, if your list has 10 items and you've scrolled down so the 3rd item is at the top-most visible item, then the offset is 3 (or 3*itemHeight, see below).
compute*ScrollExtent - Defines the size of the current view window inside the scrollable area. So for example, if your list has 10 items and you can currently see 5 of those items, then the extent is 5 (or 5*itemHeight, see below).
compute*ScrollRange - Defines the size of the current scrollable area. So for example, if your list has 10 items then the range is 10 (or 10*itemHeight, see below).
Note that all these methods can return values in different units depending on their implementation, so for the examples above, I am using the indices, but in some cases these methods will return pixel values equivalent to the width or height of the items.
In particular, the LinearLayoutManager of the RecyclerView will return indices if the 'smooth scrollbar' feature is disabled, otherwise it will return pixel values. See ScrollbarHelper in the support library for more information.
Additional reading: https://groups.google.com/forum/#!topic/android-developers/Hxe-bjtQVvk
It's kinda late, but hope it's ok.
1) The method actually is implemented by the subclasses. For example, this is what it looks like for AbsListView (ListView's superclass).
2) View's height can be different from its vertical scroll's height - just imagine a View with weird top/bottom padding .
These two points pretty much make other questions irrelevant :)
This is a sample code which might help you to understand as to how to get scrollBar top and bottom using computeVerticalScrollExtent:
scrollbarTop = (float)this.computeVerticalScrollExtent()/this.computeVerticalScrollRange()*this.computeVerticalScrollOffset();
scrollbarBottom = (float)this.computeVerticalScrollExtent()/this.computeVerticalScrollRange()*(this.computeVerticalScrollExtent()+this.computeVerticalScrollOffset());
According to the article from here:
I found this explanation correct.
ListView with 30 items has scrollRange equals to 3000, that is due to scrollRange = numberOfItems * 100, thus scrollExtent = numberOfVisibleItems * 100 and scrollOffset = numberOfScrolledItems * 100. You can find evidance of these words in the source code of AbsListView
I have a customlist in which I overload the getView function and I need to know the y position of the current item that is being drawn. And I need it in relation to the entire list and not just the ones visible on screen. How can I find this out?
Edit: The Items have different heights.
Since you want the one relative to the top of the list (not the top of the visible screen, you can calculate it using:
int yPos = view.getHeight() * position;
Edit:
Different heights? That probably hurts performance, since the recycler isn't helping much.
I don't think there's a magic method for this case. Realistically what you have to do is keep an array of list position and y offsets, so for instance
// Item at position 0, top starts at 0, height is 15
pos[0][0] = 0
pos[0][1] = 15
// Next item starts one pixel down from previous item's top, is 10 pixels tall
pos[1][0] = 16
pos[1][1] = 10
And just populate from within getView. Note that this solution tracks individual height as well as absolute offset for each item- since the previous item's position + height is required to determine the next item's position.
Hi i am implementing a gridView and i have trouble making it scroll down 1 row at a time with every scroll event.
my grid has a height of 1 row item (items height is 75dp). i don't want scrolling to be left in a middle of a row.
is there a way i can intercept and modify the scroll distance so that it only returns fixed value ex: +-75dp.
i would appreciate any help or suggestions you can give me. tnx
APIv8 has new function, called smoothScrollBy(int distance, int duration)[1]
i think you should catch all scroll events & implement own method to scroll view.
if you want to scroll by 75dp, just convert it to pixels & use function above.
float density = getContext().getResources().getDisplayMetrics().density;
int scrollBy = (int)(density * 75);
smoothScrollBy(scrollBy, 0);
But would be nice to calculate scrollBy from your GridView, instead of using some constant value (like 75dp)
[1]: http://developer.android.com/reference/android/widget/AbsListView.html#smoothScrollBy(int, int)