AndroidはListView 2の弾力性のあるListViewを徹底的に征服した.


AndroidのデフォルトのListViewは、先端または下端までスクロールする際に、あまり良いヒントはないが、リストを弾力性を持たせるべきである.すなわち、下端または先端までスクロールすると、下または上へスライドし続ける.ソースを表示するには、次の手順に従います.
/** * Scroll the view with standard behavior for scrolling beyond the normal * content boundaries. Views that call this method should override * {@link #onOverScrolled(int, int, boolean, boolean)} to respond to the * results of an over-scroll operation. * * Views can use this method to handle any touch or fling-based scrolling. * * @param deltaX Change in X in pixels * @param deltaY Change in Y in pixels * @param scrollX Current X scroll value in pixels before applying deltaX * @param scrollY Current Y scroll value in pixels before applying deltaY * @param scrollRangeX Maximum content scroll range along the X axis * @param scrollRangeY Maximum content scroll range along the Y axis * @param maxOverScrollX Number of pixels to overscroll by in either direction * along the X axis. * @param maxOverScrollY Number of pixels to overscroll by in either direction * along the Y axis. * @param isTouchEvent true if this scroll operation is the result of a touch event. * @return true if scrolling was clamped to an over-scroll boundary along either * axis, false otherwise. */
    @SuppressWarnings({"UnusedParameters"})
    protected boolean overScrollBy(int deltaX, int deltaY,
            int scrollX, int scrollY,
            int scrollRangeX, int scrollRangeY,
            int maxOverScrollX, int maxOverScrollY,
            boolean isTouchEvent) {
        final int overScrollMode = mOverScrollMode;
        final boolean canScrollHorizontal =
                computeHorizontalScrollRange() > computeHorizontalScrollExtent();
        final boolean canScrollVertical =
                computeVerticalScrollRange() > computeVerticalScrollExtent();
        final boolean overScrollHorizontal = overScrollMode == OVER_SCROLL_ALWAYS ||
                (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollHorizontal);
        final boolean overScrollVertical = overScrollMode == OVER_SCROLL_ALWAYS ||
                (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollVertical);

        int newScrollX = scrollX + deltaX;
        if (!overScrollHorizontal) {
            maxOverScrollX = 0;
        }

        int newScrollY = scrollY + deltaY;
        if (!overScrollVertical) {
            maxOverScrollY = 0;
        }

        // Clamp values if at the limits and record
        final int left = -maxOverScrollX;
        final int right = maxOverScrollX + scrollRangeX;
        final int top = -maxOverScrollY;
        final int bottom = maxOverScrollY + scrollRangeY;

        boolean clampedX = false;
        if (newScrollX > right) {
            newScrollX = right;
            clampedX = true;
        } else if (newScrollX < left) {
            newScrollX = left;
            clampedX = true;
        }

        boolean clampedY = false;
        if (newScrollY > bottom) {
            newScrollY = bottom;
            clampedY = true;
        } else if (newScrollY < top) {
            newScrollY = top;
            clampedY = true;
        }

        onOverScrolled(newScrollX, newScrollY, clampedX, clampedY);

        return clampedX || clampedY;
    }

ソースコードから分かる:@param maxOverScrollY Number of pixels to overscroll by in either direction along the Y axis.maxOverScrollY:デフォルト値は0で、値を変更すればListViewに弾力性を持たせることができます.
public class FlexibleListView extends ListView {

    private static int mMaxOverDistance = 50;
    private Context mContext;

    public FlexibleListView(Context context, AttributeSet attrs,
                            int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.mContext = context;
        initView();
    }

    public FlexibleListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.mContext = context;
        initView();
    }

    public FlexibleListView(Context context) {
        super(context);
        this.mContext = context;
        initView();
    }

    private void initView() {
        DisplayMetrics metrics = mContext.getResources().getDisplayMetrics();
        float density = metrics.density;
        mMaxOverDistance = (int) (density * mMaxOverDistance);
    }

    @Override
    protected boolean overScrollBy(int deltaX, int deltaY,
                                   int scrollX, int scrollY,
                                   int scrollRangeX, int scrollRangeY,
                                   int maxOverScrollX, int maxOverScrollY,
                                   boolean isTouchEvent) {
        return super.overScrollBy(deltaX, deltaY,
                scrollX, scrollY,
                scrollRangeX, scrollRangeY,
                maxOverScrollX, mMaxOverDistance,
                isTouchEvent);
    }
}