All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.holoeverywhere.widget.FastScroller Maven / Gradle / Ivy

The newest version!

package org.holoeverywhere.widget;

import org.holoeverywhere.R;
import org.holoeverywhere.widget.FastScroller.FastScrollerCallback;

import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.NinePatchDrawable;
import android.os.Handler;
import android.os.SystemClock;
import android.support.v4.view.MotionEventCompat;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ExpandableListAdapter;
import android.widget.ListAdapter;
import android.widget.SectionIndexer;
import android.widget.WrapperListAdapter;

class FastScroller {
    public static interface FastScrollerCallback {
        public int getVerticalScrollbarPosition();

        public boolean isAttached();

        public boolean isInScrollingContainer();

        public void reportScrollStateChange(int state);
    }

    public class ScrollFade implements Runnable {
        static final int ALPHA_MAX = 208;
        static final long FADE_DURATION = 200;
        long mFadeDuration;
        long mStartTime;

        int getAlpha() {
            if (getState() != STATE_EXIT) {
                return ALPHA_MAX;
            }
            int alpha;
            long now = SystemClock.uptimeMillis();
            if (now > mStartTime + mFadeDuration) {
                alpha = 0;
            } else {
                alpha = (int) (ALPHA_MAX - (now - mStartTime) * ALPHA_MAX / mFadeDuration);
            }
            return alpha;
        }

        @Override
        public void run() {
            if (getState() != STATE_EXIT) {
                startFade();
                return;
            }
            if (getAlpha() > 0) {
                mList.invalidate();
            } else {
                setState(STATE_NONE);
            }
        }

        void startFade() {
            mFadeDuration = FADE_DURATION;
            mStartTime = SystemClock.uptimeMillis();
            setState(STATE_EXIT);
        }
    }

    private static final int[] DEFAULT_STATES = new int[0];
    private static final int FADE_TIMEOUT = 1500;
    private static int MIN_PAGES = 4;
    private static final int OVERLAY_AT_THUMB = 1;
    private static final int OVERLAY_FLOATING = 0;
    private static final int PENDING_DRAG_DELAY = 180;
    private static final int[] PRESSED_STATES = new int[] {
            android.R.attr.state_pressed
    };
    private static final int STATE_DRAGGING = 2;
    private static final int STATE_EXIT = 3;
    private static final int STATE_NONE = 0;
    private static final int STATE_VISIBLE = 1;
    private boolean mAlwaysShow;
    private boolean mChangedBounds;
    private final Runnable mDeferStartDrag = new Runnable() {
        @Override
        public void run() {
            if (mList.isAttached()) {
                beginDrag();
                final int viewHeight = mList.getHeight();
                int newThumbY = (int) mInitialTouchY - mThumbH + 10;
                if (newThumbY < 0) {
                    newThumbY = 0;
                } else if (newThumbY + mThumbH > viewHeight) {
                    newThumbY = viewHeight - mThumbH;
                }
                mThumbY = newThumbY;
                scrollTo((float) mThumbY / (viewHeight - mThumbH));
            }
            mPendingDrag = false;
        }
    };
    private boolean mDrawOverlay;
    private Handler mHandler = new Handler();
    float mInitialTouchY;
    private int mItemCount = -1;
    T mList;
    ListAdapter mListAdapter;
    private int mListOffset;
    private boolean mLongList;
    private boolean mMatchDragPosition;
    private Drawable mOverlayDrawable;
    private Drawable mOverlayDrawableLeft;
    private Drawable mOverlayDrawableRight;
    private RectF mOverlayPos;
    private int mOverlayPosition;
    private int mOverlaySize;
    private Paint mPaint;
    boolean mPendingDrag;
    private int mPosition;
    private int mScaledTouchSlop;
    boolean mScrollCompleted;
    private ScrollFade mScrollFade;
    private SectionIndexer mSectionIndexer;
    private Object[] mSections;
    private String mSectionText;
    private int mState;
    private Drawable mThumbDrawable;
    int mThumbH;
    int mThumbW;
    int mThumbY;
    private final Rect mTmpRect = new Rect();
    private Drawable mTrackDrawable;
    private int mVisibleItem;

    public FastScroller(Context context, T listView) {
        mList = listView;
        init(context);
    }

    void beginDrag() {
        setState(STATE_DRAGGING);
        if (mListAdapter == null && mList != null) {
            getSectionsFromIndexer();
        }
        if (mList != null) {
            mList.requestDisallowInterceptTouchEvent(true);
            mList.reportScrollStateChange(OnScrollListener.SCROLL_STATE_TOUCH_SCROLL);
        }
        cancelFling();
    }

    private void cancelFling() {
        MotionEvent cancelFling = MotionEvent.obtain(0, 0, MotionEvent.ACTION_CANCEL, 0, 0, 0);
        mList.onTouchEvent(cancelFling);
        cancelFling.recycle();
    }

    void cancelPendingDrag() {
        mList.removeCallbacks(mDeferStartDrag);
        mPendingDrag = false;
    }

    public void draw(Canvas canvas) {
        if (mState == STATE_NONE) {
            return;
        }
        final int y = mThumbY;
        final int viewWidth = mList.getWidth();
        final ScrollFade scrollFade = mScrollFade;
        int alpha = -1;
        if (mState == STATE_EXIT) {
            alpha = scrollFade.getAlpha();
            if (alpha < ScrollFade.ALPHA_MAX / 2) {
                mThumbDrawable.setAlpha(alpha * 2);
            }
            int left = 0;
            switch (mPosition) {
                case View.SCROLLBAR_POSITION_DEFAULT:
                case View.SCROLLBAR_POSITION_RIGHT:
                    left = viewWidth - mThumbW * alpha / ScrollFade.ALPHA_MAX;
                    break;
                case View.SCROLLBAR_POSITION_LEFT:
                    left = -mThumbW + mThumbW * alpha / ScrollFade.ALPHA_MAX;
                    break;
            }
            mThumbDrawable.setBounds(left, 0, left + mThumbW, mThumbH);
            mChangedBounds = true;
        }
        if (mTrackDrawable != null) {
            final Rect thumbBounds = mThumbDrawable.getBounds();
            final int left = thumbBounds.left;
            final int halfThumbHeight = (thumbBounds.bottom - thumbBounds.top) / 2;
            final int trackWidth = mTrackDrawable.getIntrinsicWidth();
            final int trackLeft = left + mThumbW / 2 - trackWidth / 2;
            mTrackDrawable.setBounds(trackLeft, halfThumbHeight,
                    trackLeft + trackWidth, mList.getHeight() - halfThumbHeight);
            mTrackDrawable.draw(canvas);
        }
        canvas.translate(0, y);
        mThumbDrawable.draw(canvas);
        canvas.translate(0, -y);
        if (mState == STATE_DRAGGING && mDrawOverlay) {
            if (mOverlayPosition == OVERLAY_AT_THUMB) {
                int left = 0;
                switch (mPosition) {
                    default:
                    case View.SCROLLBAR_POSITION_DEFAULT:
                    case View.SCROLLBAR_POSITION_RIGHT:
                        left = Math.max(0,
                                mThumbDrawable.getBounds().left - mThumbW - mOverlaySize);
                        break;
                    case View.SCROLLBAR_POSITION_LEFT:
                        left = Math.min(mThumbDrawable.getBounds().right + mThumbW,
                                mList.getWidth() - mOverlaySize);
                        break;
                }
                int top = Math
                        .max(0,
                                Math.min(y + (mThumbH - mOverlaySize) / 2, mList.getHeight()
                                        - mOverlaySize));
                final RectF pos = mOverlayPos;
                pos.left = left;
                pos.right = pos.left + mOverlaySize;
                pos.top = top;
                pos.bottom = pos.top + mOverlaySize;
                if (mOverlayDrawable != null) {
                    mOverlayDrawable.setBounds((int) pos.left, (int) pos.top,
                            (int) pos.right, (int) pos.bottom);
                }
            }
            mOverlayDrawable.draw(canvas);
            final Paint paint = mPaint;
            float descent = paint.descent();
            final RectF rectF = mOverlayPos;
            final Rect tmpRect = mTmpRect;
            mOverlayDrawable.getPadding(tmpRect);
            final int hOff = (tmpRect.right - tmpRect.left) / 2;
            final int vOff = (tmpRect.bottom - tmpRect.top) / 2;
            canvas.drawText(mSectionText, (int) (rectF.left + rectF.right) / 2 - hOff,
                    (int) (rectF.bottom + rectF.top) / 2 + mOverlaySize / 4 - descent - vOff,
                    paint);
        } else if (mState == STATE_EXIT) {
            if (alpha == 0) {
                setState(STATE_NONE);
            } else if (mTrackDrawable != null) {
                mList.invalidate(viewWidth - mThumbW, 0, viewWidth, mList.getHeight());
            } else {
                mList.invalidate(viewWidth - mThumbW, y, viewWidth, y + mThumbH);
            }
        }
    }

    SectionIndexer getSectionIndexer() {
        return mSectionIndexer;
    }

    Object[] getSections() {
        if (mListAdapter == null && mList != null) {
            getSectionsFromIndexer();
        }
        return mSections;
    }

    void getSectionsFromIndexer() {
        ListAdapter adapter = mList.getAdapter();
        mSectionIndexer = null;
        if (adapter instanceof HeaderViewListAdapter) {
            mListOffset = ((HeaderViewListAdapter) adapter).getHeadersCount();
        }
        if (adapter instanceof ListAdapterWrapper) {
            adapter = ((ListAdapterWrapper) adapter).getWrappedAdapter();
        }
        if (adapter instanceof WrapperListAdapter) {
            adapter = ((WrapperListAdapter) adapter).getWrappedAdapter();
        }
        if (adapter instanceof ExpandableListConnector) {
            ExpandableListAdapter expAdapter = ((ExpandableListConnector) adapter).getAdapter();
            if (expAdapter instanceof SectionIndexer) {
                mSectionIndexer = (SectionIndexer) expAdapter;
                mListAdapter = adapter;
                mSections = mSectionIndexer.getSections();
            }
        } else {
            if (adapter instanceof SectionIndexer) {
                mSectionIndexer = (SectionIndexer) adapter;
                mSections = mSectionIndexer.getSections();
                if (mSections == null) {
                    mSections = new String[] {
                            " "
                    };
                }
            } else {
                mSections = new String[] {
                        " "
                };
            }
        }
        mListAdapter = adapter;
    }

    public int getState() {
        return mState;
    }

    private int getThumbPositionForListPosition(int firstVisibleItem, int visibleItemCount,
            int totalItemCount) {
        if (mSectionIndexer == null || mListAdapter == null) {
            getSectionsFromIndexer();
        }
        if (mSectionIndexer == null || !mMatchDragPosition) {
            return (mList.getHeight() - mThumbH) * firstVisibleItem
                    / (totalItemCount - visibleItemCount);
        }
        firstVisibleItem -= mListOffset;
        if (firstVisibleItem < 0) {
            return 0;
        }
        totalItemCount -= mListOffset;
        final int trackHeight = mList.getHeight() - mThumbH;
        final int section = mSectionIndexer.getSectionForPosition(firstVisibleItem);
        final int sectionPos = mSectionIndexer.getPositionForSection(section);
        final int nextSectionPos = mSectionIndexer.getPositionForSection(section + 1);
        final int sectionCount = mSections.length;
        final int positionsInSection = nextSectionPos - sectionPos;
        final View child = mList.getChildAt(0);
        final float incrementalPos = child == null ? 0 : firstVisibleItem +
                (float) (mList.getPaddingTop() - child.getTop()) / child.getHeight();
        final float posWithinSection = (incrementalPos - sectionPos) / positionsInSection;
        int result = (int) ((section + posWithinSection) / sectionCount * trackHeight);
        if (firstVisibleItem > 0 && firstVisibleItem + visibleItemCount == totalItemCount) {
            final View lastChild = mList.getChildAt(visibleItemCount - 1);
            final float lastItemVisible = (float) (mList.getHeight() - mList.getPaddingBottom()
                    - lastChild.getTop()) / lastChild.getHeight();
            result += (trackHeight - result) * lastItemVisible;
        }
        return result;
    }

    public int getWidth() {
        return mThumbW;
    }

    private void init(Context context) {
        TypedArray ta = context.getTheme().obtainStyledAttributes(R.styleable.FastScroll);
        useThumbDrawable(context, ta.getDrawable(R.styleable.FastScroll_fastScrollThumbDrawable));
        mTrackDrawable = ta.getDrawable(R.styleable.FastScroll_fastScrollTrackDrawable);
        mOverlayDrawableLeft = ta
                .getDrawable(R.styleable.FastScroll_fastScrollPreviewBackgroundLeft);
        mOverlayDrawableRight = ta
                .getDrawable(R.styleable.FastScroll_fastScrollPreviewBackgroundRight);
        mOverlayPosition = ta.getInt(R.styleable.FastScroll_fastScrollOverlayPosition,
                OVERLAY_FLOATING);
        mScrollCompleted = true;
        getSectionsFromIndexer();
        mOverlaySize = context.getResources().getDimensionPixelSize(
                R.dimen.fastscroll_overlay_size);
        mOverlayPos = new RectF();
        mScrollFade = new ScrollFade();
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setTextAlign(Paint.Align.CENTER);
        mPaint.setTextSize(mOverlaySize / 2);
        ColorStateList textColor = ta.getColorStateList(R.styleable.FastScroll_fastScrollTextColor);
        int textColorNormal = textColor.getDefaultColor();
        mPaint.setColor(textColorNormal);
        mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        if (mList.getWidth() > 0 && mList.getHeight() > 0) {
            onSizeChanged(mList.getWidth(), mList.getHeight(), 0, 0);
        }
        mState = STATE_NONE;
        refreshDrawableState();
        ta.recycle();
        mScaledTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
        mMatchDragPosition = context.getApplicationInfo().targetSdkVersion >=
                android.os.Build.VERSION_CODES.HONEYCOMB;
        setScrollbarPosition(((FastScrollerCallback) mList).getVerticalScrollbarPosition());
    }

    public boolean isAlwaysShowEnabled() {
        return mAlwaysShow;
    }

    boolean isPointInside(float x, float y) {
        boolean inTrack = false;
        switch (mPosition) {
            default:
            case View.SCROLLBAR_POSITION_DEFAULT:
            case View.SCROLLBAR_POSITION_RIGHT:
                inTrack = x > mList.getWidth() - mThumbW;
                break;
            case View.SCROLLBAR_POSITION_LEFT:
                inTrack = x < mThumbW;
                break;
        }
        return inTrack && (mTrackDrawable != null || y >= mThumbY && y <= mThumbY + mThumbH);
    }

    boolean isVisible() {
        return !(mState == STATE_NONE);
    }

    boolean onInterceptTouchEvent(MotionEvent ev) {
        switch (MotionEventCompat.getActionMasked(ev)) {
            case MotionEvent.ACTION_DOWN:
                if (mState > STATE_NONE && isPointInside(ev.getX(), ev.getY())) {
                    if (!mList.isInScrollingContainer()) {
                        beginDrag();
                        return true;
                    }
                    mInitialTouchY = ev.getY();
                    startPendingDrag();
                }
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                cancelPendingDrag();
                break;
        }
        return false;
    }

    void onItemCountChanged(int oldCount, int newCount) {
        if (mAlwaysShow) {
            mLongList = true;
        }
    }

    void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
            int totalItemCount) {
        if (mItemCount != totalItemCount && visibleItemCount > 0) {
            mItemCount = totalItemCount;
            mLongList = mItemCount / visibleItemCount >= MIN_PAGES;
        }
        if (mAlwaysShow) {
            mLongList = true;
        }
        if (!mLongList) {
            if (mState != STATE_NONE) {
                setState(STATE_NONE);
            }
            return;
        }
        if (totalItemCount - visibleItemCount > 0 && mState != STATE_DRAGGING) {
            mThumbY = getThumbPositionForListPosition(firstVisibleItem, visibleItemCount,
                    totalItemCount);
            if (mChangedBounds) {
                resetThumbPos();
                mChangedBounds = false;
            }
        }
        mScrollCompleted = true;
        if (firstVisibleItem == mVisibleItem) {
            return;
        }
        mVisibleItem = firstVisibleItem;
        if (mState != STATE_DRAGGING) {
            setState(STATE_VISIBLE);
            if (!mAlwaysShow) {
                mHandler.postDelayed(mScrollFade, FADE_TIMEOUT);
            }
        }
    }

    public void onSectionsChanged() {
        mListAdapter = null;
    }

    void onSizeChanged(int w, int h, int oldw, int oldh) {
        if (mThumbDrawable != null) {
            switch (mPosition) {
                default:
                case View.SCROLLBAR_POSITION_DEFAULT:
                case View.SCROLLBAR_POSITION_RIGHT:
                    mThumbDrawable.setBounds(w - mThumbW, 0, w, mThumbH);
                    break;
                case View.SCROLLBAR_POSITION_LEFT:
                    mThumbDrawable.setBounds(0, 0, mThumbW, mThumbH);
                    break;
            }
        }
        if (mOverlayPosition == OVERLAY_FLOATING) {
            final RectF pos = mOverlayPos;
            pos.left = (w - mOverlaySize) / 2;
            pos.right = pos.left + mOverlaySize;
            pos.top = h / 10;
            pos.bottom = pos.top + mOverlaySize;
            if (mOverlayDrawable != null) {
                mOverlayDrawable.setBounds((int) pos.left, (int) pos.top,
                        (int) pos.right, (int) pos.bottom);
            }
        }
    }

    boolean onTouchEvent(MotionEvent me) {
        if (mState == STATE_NONE) {
            return false;
        }
        final int action = me.getAction();
        if (action == MotionEvent.ACTION_DOWN) {
            if (isPointInside(me.getX(), me.getY())) {
                if (!mList.isInScrollingContainer()) {
                    beginDrag();
                    return true;
                }
                mInitialTouchY = me.getY();
                startPendingDrag();
            }
        } else if (action == MotionEvent.ACTION_UP) {
            if (mPendingDrag) {
                beginDrag();
                final int viewHeight = mList.getHeight();
                int newThumbY = (int) me.getY() - mThumbH + 10;
                if (newThumbY < 0) {
                    newThumbY = 0;
                } else if (newThumbY + mThumbH > viewHeight) {
                    newThumbY = viewHeight - mThumbH;
                }
                mThumbY = newThumbY;
                scrollTo((float) mThumbY / (viewHeight - mThumbH));
                cancelPendingDrag();
            }
            if (mState == STATE_DRAGGING) {
                if (mList != null) {
                    mList.requestDisallowInterceptTouchEvent(false);
                    mList.reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
                }
                setState(STATE_VISIBLE);
                final Handler handler = mHandler;
                handler.removeCallbacks(mScrollFade);
                if (!mAlwaysShow) {
                    handler.postDelayed(mScrollFade, 1000);
                }
                mList.invalidate();
                return true;
            }
        } else if (action == MotionEvent.ACTION_MOVE) {
            if (mPendingDrag) {
                final float y = me.getY();
                if (Math.abs(y - mInitialTouchY) > mScaledTouchSlop) {
                    setState(STATE_DRAGGING);
                    if (mListAdapter == null && mList != null) {
                        getSectionsFromIndexer();
                    }
                    if (mList != null) {
                        mList.requestDisallowInterceptTouchEvent(true);
                        mList.reportScrollStateChange(OnScrollListener.SCROLL_STATE_TOUCH_SCROLL);
                    }
                    cancelFling();
                    cancelPendingDrag();
                }
            }
            if (mState == STATE_DRAGGING) {
                final int viewHeight = mList.getHeight();
                int newThumbY = (int) me.getY() - mThumbH + 10;
                if (newThumbY < 0) {
                    newThumbY = 0;
                } else if (newThumbY + mThumbH > viewHeight) {
                    newThumbY = viewHeight - mThumbH;
                }
                if (Math.abs(mThumbY - newThumbY) < 2) {
                    return true;
                }
                mThumbY = newThumbY;
                if (mScrollCompleted) {
                    scrollTo((float) mThumbY / (viewHeight - mThumbH));
                }
                return true;
            }
        } else if (action == MotionEvent.ACTION_CANCEL) {
            cancelPendingDrag();
        }
        return false;
    }

    private void refreshDrawableState() {
        int[] state = mState == STATE_DRAGGING ? PRESSED_STATES : DEFAULT_STATES;
        if (mThumbDrawable != null && mThumbDrawable.isStateful()) {
            mThumbDrawable.setState(state);
        }
        if (mTrackDrawable != null && mTrackDrawable.isStateful()) {
            mTrackDrawable.setState(state);
        }
    }

    private void resetThumbPos() {
        final int viewWidth = mList.getWidth();
        switch (mPosition) {
            case View.SCROLLBAR_POSITION_DEFAULT:
            case View.SCROLLBAR_POSITION_RIGHT:
                mThumbDrawable.setBounds(viewWidth - mThumbW, 0, viewWidth, mThumbH);
                break;
            case View.SCROLLBAR_POSITION_LEFT:
                mThumbDrawable.setBounds(0, 0, mThumbW, mThumbH);
                break;
        }
        mThumbDrawable.setAlpha(ScrollFade.ALPHA_MAX);
    }

    void scrollTo(float position) {
        int count = mList.getCount();
        mScrollCompleted = false;
        float fThreshold = 1.0f / count / 8;
        final Object[] sections = mSections;
        int sectionIndex;
        if (sections != null && sections.length > 1) {
            final int nSections = sections.length;
            int section = (int) (position * nSections);
            if (section >= nSections) {
                section = nSections - 1;
            }
            int exactSection = section;
            sectionIndex = section;
            int index = mSectionIndexer.getPositionForSection(section);
            int nextIndex = count;
            int prevIndex = index;
            int prevSection = section;
            int nextSection = section + 1;
            if (section < nSections - 1) {
                nextIndex = mSectionIndexer.getPositionForSection(section + 1);
            }
            if (nextIndex == index) {
                while (section > 0) {
                    section--;
                    prevIndex = mSectionIndexer.getPositionForSection(section);
                    if (prevIndex != index) {
                        prevSection = section;
                        sectionIndex = section;
                        break;
                    } else if (section == 0) {
                        sectionIndex = 0;
                        break;
                    }
                }
            }
            int nextNextSection = nextSection + 1;
            while (nextNextSection < nSections &&
                    mSectionIndexer.getPositionForSection(nextNextSection) == nextIndex) {
                nextNextSection++;
                nextSection++;
            }
            float fPrev = (float) prevSection / nSections;
            float fNext = (float) nextSection / nSections;
            if (prevSection == exactSection && position - fPrev < fThreshold) {
                index = prevIndex;
            } else {
                index = prevIndex + (int) ((nextIndex - prevIndex) * (position - fPrev)
                        / (fNext - fPrev));
            }
            if (index > count - 1) {
                index = count - 1;
            }
            if (mList instanceof ExpandableListView) {
                ExpandableListView expList = (ExpandableListView) mList;
                expList.setSelectionFromTop(expList.getFlatListPosition(
                        ExpandableListView.getPackedPositionForGroup(index + mListOffset)), 0);
            } else if (mList instanceof ListView) {
                ((ListView) mList).setSelectionFromTop(index + mListOffset, 0);
            } else {
                mList.setSelection(index + mListOffset);
            }
        } else {
            int index = (int) (position * count);
            if (index > count - 1) {
                index = count - 1;
            }
            if (mList instanceof ExpandableListView) {
                ExpandableListView expList = (ExpandableListView) mList;
                expList.setSelectionFromTop(expList.getFlatListPosition(
                        ExpandableListView.getPackedPositionForGroup(index + mListOffset)), 0);
            } else if (mList instanceof ListView) {
                ((ListView) mList).setSelectionFromTop(index + mListOffset, 0);
            } else {
                mList.setSelection(index + mListOffset);
            }
            sectionIndex = -1;
        }
        if (sectionIndex >= 0) {
            String text = mSectionText = sections[sectionIndex].toString();
            mDrawOverlay = (text.length() != 1 || text.charAt(0) != ' ') &&
                    sectionIndex < sections.length;
        } else {
            mDrawOverlay = false;
        }
    }

    public void setAlwaysShow(boolean alwaysShow) {
        mAlwaysShow = alwaysShow;
        if (alwaysShow) {
            mHandler.removeCallbacks(mScrollFade);
            setState(STATE_VISIBLE);
        } else if (mState == STATE_VISIBLE) {
            mHandler.postDelayed(mScrollFade, FADE_TIMEOUT);
        }
    }

    public void setScrollbarPosition(int position) {
        mPosition = position;
        switch (position) {
            default:
            case View.SCROLLBAR_POSITION_DEFAULT:
            case View.SCROLLBAR_POSITION_RIGHT:
                mOverlayDrawable = mOverlayDrawableRight;
                break;
            case View.SCROLLBAR_POSITION_LEFT:
                mOverlayDrawable = mOverlayDrawableLeft;
                break;
        }
    }

    public void setState(int state) {
        switch (state) {
            case STATE_NONE:
                mHandler.removeCallbacks(mScrollFade);
                mList.invalidate();
                break;
            case STATE_VISIBLE:
                if (mState != STATE_VISIBLE) {
                    resetThumbPos();
                }
            case STATE_DRAGGING:
                mHandler.removeCallbacks(mScrollFade);
                break;
            case STATE_EXIT:
                int viewWidth = mList.getWidth();
                mList.invalidate(viewWidth - mThumbW, mThumbY, viewWidth, mThumbY + mThumbH);
                break;
        }
        mState = state;
        refreshDrawableState();
    }

    void startPendingDrag() {
        mPendingDrag = true;
        mList.postDelayed(mDeferStartDrag, PENDING_DRAG_DELAY);
    }

    void stop() {
        setState(STATE_NONE);
    }

    private void useThumbDrawable(Context context, Drawable drawable) {
        mThumbDrawable = drawable;
        if (drawable instanceof NinePatchDrawable) {
            mThumbW = context.getResources().getDimensionPixelSize(
                    R.dimen.fastscroll_thumb_width);
            mThumbH = context.getResources().getDimensionPixelSize(
                    R.dimen.fastscroll_thumb_height);
        } else {
            mThumbW = drawable.getIntrinsicWidth();
            mThumbH = drawable.getIntrinsicHeight();
        }
        mChangedBounds = true;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy