Skip to content

Instantly share code, notes, and snippets.

@ogero
Last active August 29, 2015 14:17
Show Gist options
  • Save ogero/3f49d29bb04562e2bcae to your computer and use it in GitHub Desktop.
Save ogero/3f49d29bb04562e2bcae to your computer and use it in GitHub Desktop.
A ListView that informs when and how much its content is scrolled.
/*
* Copyright 2015 Gerónimo Oñativia
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import android.content.Context;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.AbsListView;
import android.widget.ListView;
/**
* ListView that calls ScrollValueChangedListener.onScrollValueChanged
* when its content is scrolled.
* Informs as much as possible the amount scrolled.
*
* @author Gerónimo Oñativia / PixDart.com <[email protected]>
*/
public class ScrollTrackingListView extends ListView {
private static final String TAG = ScrollTrackingListView.class.getName();
private int firstChildInitialTop = Integer.MIN_VALUE;
private boolean zeroScrollChanged = false;
private ScrollValueChangedListener scrollValueChangedListener = null;
public ScrollTrackingListView(Context context) {
this(context, null);
}
public ScrollTrackingListView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ScrollTrackingListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) init();
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public ScrollTrackingListView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
private void init() {
getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
View firstChild = getChildAt(0);
if (firstChild != null) {
firstChildInitialTop = firstChild.getTop();
Log.d(TAG, "firstChildBaseTop obtained: " + firstChildInitialTop);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN)
getViewTreeObserver().removeGlobalOnLayoutListener(this);
else
getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
}
});
getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
@Override
public void onScrollChanged() {
if (isReadyForComputation()) computeCurrentScroll();
}
});
setOnScrollListener(new OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if (isReadyForComputation()) computeCurrentScroll();
}
});
}
public boolean isReadyForComputation() {
return firstChildInitialTop != Integer.MIN_VALUE;
}
public void computeCurrentScroll() {
if (scrollValueChangedListener == null) return;
View firstChild = getChildAt(0);
if (firstChild != null) {
int firstChildNewTop = firstChild.getTop();
int deltaY = firstChildNewTop - firstChildInitialTop;
if (deltaY < 0 || (deltaY == 0 && zeroScrollChanged)) {
zeroScrollChanged = deltaY != 0; //Do not call listener multiple times to inform ZERO scroll. Also skip first call by initializing as false on declaration.
Log.d(TAG, "firstChildInitialTop:" + firstChildInitialTop + " firstChildNewTop:" + firstChildNewTop + " variation:" + deltaY);
scrollValueChangedListener.onScrollValueChanged(deltaY);
}
}
}
public void setScrollValueChangedListener(ScrollValueChangedListener listener) {
scrollValueChangedListener = listener;
}
public interface ScrollValueChangedListener {
public void onScrollValueChanged(int currentScrollAmmount);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment