This question is very specific, What I am trying to do (with a list view) is described in great detail in the following article: http://www.pushing-pixels.org/2011/07/18/android-tips-and-tricks-synchronized-scrolling.html
Thanks @kaushal trivedi for the link
Details: I have an android application I am working on that uses a list view with a custom adapter. The Listview Contains a Custom header of a non-fixed height. Also please note that the list items are also of variable height. My goal is to mimic the effect produced in the latest gmail app (as an example) where when you are viewing an email, and scroll past the header, it sticks to the top of the screen just under the action bar and the content continues to scroll under it. What I would like to do, is stick the bottom half of my header to the top of the screen.
My initial reasoning was to create an invisible view fixed in the desired location, and when the user scrolled to or past that location, make the view visible. The issue in this logic, is I need the exact pixel scroll height, which after many attempts I have determined very difficult to do. The exact issue I ran into is, it is not possible from what I can gather to retrieve the pixel level Y-scroll in an onScroll event, I have only been able to retrieve the value in the onScrollStateChanged event. Which as described above will not achieve the desired functionality.
Working with the onScroll event "int firstVisibleItem, int visibleItemCount, int totalItemCount" parameters is also not an option because of the fact that the content I want to "stick" is not the size of a list item, but a fraction of the size of the variable height header.
Is there a correct way to accomplish this effect? My current minSDK level is 10.
Update 10/10/13
I made some progress. The following code syncs the Y position floating view I have on the screen with the list view. b is the view I am setting just as an example.
NOTE: This is used in the onScroll
event of the list view.
View c = view.getChildAt(0);
if (c != null) {
int currY = c.getTop();
int diffY = currY - lastY;
lastY = currY;
b.setTop(b.getTop() + diffY);
}
Now the issue is, the header of my List is a non fixed height as I said earlier. So I need to get the height of the header and apply an offset to "b" to place it at the bottom of the list header floating above the list.
This is the code I've tried so far.
header.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
The issue here us header.getMeasuredHeight();
always resolves to the same value no matter how tall the actual height is.
I understand I cannot get the height until after it is displayed. Is there a way I can get that value and set the offset after it is rendered?
Update 10/11/13
I Answered my last question as soon as I woke up this morning.
While the View.measure()
code was returning a height. It appears to be the default height of the view, assuming there was no text (that would ultimately stretch the view). So I used the below event to listen for when the view is displayed, and then record its actual height (which works exactly as I had hoped :) )
ViewTreeObserver vto = header.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
b.setY(header.getMeasuredHeight() - 80); //80 is a temp offset
}
});
I have to go to work soon and being that I have still not fully achieved the desired effect, I will not mark this as answered yet. Hopefully I will be able to sit down and finish this in the next day or two. I am still open to suggestions on better ways of doing this.