FileDocCategorySizeDatePackage
AbsSeekBar.javaAPI DocAndroid 5.1 API25849Thu Mar 12 22:22:10 GMT 2015android.widget

AbsSeekBar

public abstract class AbsSeekBar extends ProgressBar

Fields Summary
private final android.graphics.Rect
mTempRect
private android.graphics.drawable.Drawable
mThumb
private android.content.res.ColorStateList
mThumbTintList
private PorterDuff.Mode
mThumbTintMode
private boolean
mHasThumbTint
private boolean
mHasThumbTintMode
private int
mThumbOffset
private boolean
mSplitTrack
float
mTouchProgressOffset
On touch, this offset plus the scaled value from the position of the touch will form the progress value. Usually 0.
boolean
mIsUserSeekable
Whether this is user seekable.
private int
mKeyProgressIncrement
On key presses (right or left), the amount to increment/decrement the progress.
private static final int
NO_ALPHA
private float
mDisabledAlpha
private int
mScaledTouchSlop
private float
mTouchDownX
private boolean
mIsDragging
Constructors Summary
public AbsSeekBar(android.content.Context context)


       
        super(context);
    
public AbsSeekBar(android.content.Context context, android.util.AttributeSet attrs)

        super(context, attrs);
    
public AbsSeekBar(android.content.Context context, android.util.AttributeSet attrs, int defStyleAttr)

        this(context, attrs, defStyleAttr, 0);
    
public AbsSeekBar(android.content.Context context, android.util.AttributeSet attrs, int defStyleAttr, int defStyleRes)

        super(context, attrs, defStyleAttr, defStyleRes);

        TypedArray a = context.obtainStyledAttributes(
                attrs, com.android.internal.R.styleable.SeekBar, defStyleAttr, defStyleRes);

        final Drawable thumb = a.getDrawable(com.android.internal.R.styleable.SeekBar_thumb);
        setThumb(thumb);

        if (a.hasValue(R.styleable.SeekBar_thumbTintMode)) {
            mThumbTintMode = Drawable.parseTintMode(a.getInt(
                    R.styleable.SeekBar_thumbTintMode, -1), mThumbTintMode);
            mHasThumbTintMode = true;
        }

        if (a.hasValue(R.styleable.SeekBar_thumbTint)) {
            mThumbTintList = a.getColorStateList(R.styleable.SeekBar_thumbTint);
            mHasThumbTint = true;
        }

        // Guess thumb offset if thumb != null, but allow layout to override.
        final int thumbOffset = a.getDimensionPixelOffset(
                com.android.internal.R.styleable.SeekBar_thumbOffset, getThumbOffset());
        setThumbOffset(thumbOffset);

        mSplitTrack = a.getBoolean(com.android.internal.R.styleable.SeekBar_splitTrack, false);
        a.recycle();

        a = context.obtainStyledAttributes(attrs,
                com.android.internal.R.styleable.Theme, 0, 0);
        mDisabledAlpha = a.getFloat(com.android.internal.R.styleable.Theme_disabledAlpha, 0.5f);
        a.recycle();

        applyThumbTint();

        mScaledTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
    
Methods Summary
private voidapplyThumbTint()

        if (mThumb != null && (mHasThumbTint || mHasThumbTintMode)) {
            mThumb = mThumb.mutate();

            if (mHasThumbTint) {
                mThumb.setTintList(mThumbTintList);
            }

            if (mHasThumbTintMode) {
                mThumb.setTintMode(mThumbTintMode);
            }

            // The drawable (or one of its children) may not have been
            // stateful before applying the tint, so let's try again.
            if (mThumb.isStateful()) {
                mThumb.setState(getDrawableState());
            }
        }
    
private voidattemptClaimDrag()
Tries to claim the user's drag motion, and requests disallowing any ancestors from stealing events in the drag.

        if (mParent != null) {
            mParent.requestDisallowInterceptTouchEvent(true);
        }
    
voiddrawThumb(android.graphics.Canvas canvas)
Draw the thumb.

        if (mThumb != null) {
            canvas.save();
            // Translate the padding. For the x, we need to allow the thumb to
            // draw in its extra space
            canvas.translate(mPaddingLeft - mThumbOffset, mPaddingTop);
            mThumb.draw(canvas);
            canvas.restore();
        }
    
voiddrawTrack(android.graphics.Canvas canvas)

        final Drawable thumbDrawable = mThumb;
        if (thumbDrawable != null && mSplitTrack) {
            final Insets insets = thumbDrawable.getOpticalInsets();
            final Rect tempRect = mTempRect;
            thumbDrawable.copyBounds(tempRect);
            tempRect.offset(mPaddingLeft - mThumbOffset, mPaddingTop);
            tempRect.left += insets.left;
            tempRect.right -= insets.right;

            final int saveCount = canvas.save();
            canvas.clipRect(tempRect, Op.DIFFERENCE);
            super.drawTrack(canvas);
            canvas.restoreToCount(saveCount);
        } else {
            super.drawTrack(canvas);
        }
    
public voiddrawableHotspotChanged(float x, float y)

        super.drawableHotspotChanged(x, y);

        if (mThumb != null) {
            mThumb.setHotspot(x, y);
        }
    
protected voiddrawableStateChanged()

        super.drawableStateChanged();

        final Drawable progressDrawable = getProgressDrawable();
        if (progressDrawable != null) {
            progressDrawable.setAlpha(isEnabled() ? NO_ALPHA : (int) (NO_ALPHA * mDisabledAlpha));
        }

        final Drawable thumb = mThumb;
        if (thumb != null && thumb.isStateful()) {
            thumb.setState(getDrawableState());
        }
    
public intgetKeyProgressIncrement()
Returns the amount of progress changed via the arrow keys.

By default, this will be a value that is derived from the max progress.

return
The amount to increment or decrement when the user presses the arrow keys. This will be positive.

        return mKeyProgressIncrement;
    
private floatgetScale()

        final int max = getMax();
        return max > 0 ? getProgress() / (float) max : 0;
    
public booleangetSplitTrack()
Returns whether the track should be split by the thumb.

        return mSplitTrack;
    
public android.graphics.drawable.DrawablegetThumb()
Return the drawable used to represent the scroll thumb - the component that the user can drag back and forth indicating the current value by its position.

return
The current thumb drawable

        return mThumb;
    
public intgetThumbOffset()

see
#setThumbOffset(int)

        return mThumbOffset;
    
public android.content.res.ColorStateListgetThumbTintList()
Returns the tint applied to the thumb drawable, if specified.

return
the tint applied to the thumb drawable
attr
ref android.R.styleable#SeekBar_thumbTint
see
#setThumbTintList(ColorStateList)

        return mThumbTintList;
    
public PorterDuff.ModegetThumbTintMode()
Returns the blending mode used to apply the tint to the thumb drawable, if specified.

return
the blending mode used to apply the tint to the thumb drawable
attr
ref android.R.styleable#SeekBar_thumbTintMode
see
#setThumbTintMode(PorterDuff.Mode)

        return mThumbTintMode;
    
public voidjumpDrawablesToCurrentState()

        super.jumpDrawablesToCurrentState();

        if (mThumb != null) {
            mThumb.jumpToCurrentState();
        }
    
protected synchronized voidonDraw(android.graphics.Canvas canvas)

        super.onDraw(canvas);
        drawThumb(canvas);

    
public voidonInitializeAccessibilityEvent(android.view.accessibility.AccessibilityEvent event)

        super.onInitializeAccessibilityEvent(event);
        event.setClassName(AbsSeekBar.class.getName());
    
public voidonInitializeAccessibilityNodeInfo(android.view.accessibility.AccessibilityNodeInfo info)

        super.onInitializeAccessibilityNodeInfo(info);
        info.setClassName(AbsSeekBar.class.getName());

        if (isEnabled()) {
            final int progress = getProgress();
            if (progress > 0) {
                info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
            }
            if (progress < getMax()) {
                info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
            }
        }
    
voidonKeyChange()
Called when the user changes the seekbar's progress by using a key event.

    
public booleanonKeyDown(int keyCode, android.view.KeyEvent event)

        if (isEnabled()) {
            int progress = getProgress();
            switch (keyCode) {
                case KeyEvent.KEYCODE_DPAD_LEFT:
                    if (progress <= 0) break;
                    setProgress(progress - mKeyProgressIncrement, true);
                    onKeyChange();
                    return true;

                case KeyEvent.KEYCODE_DPAD_RIGHT:
                    if (progress >= getMax()) break;
                    setProgress(progress + mKeyProgressIncrement, true);
                    onKeyChange();
                    return true;
            }
        }

        return super.onKeyDown(keyCode, event);
    
protected synchronized voidonMeasure(int widthMeasureSpec, int heightMeasureSpec)

        Drawable d = getCurrentDrawable();

        int thumbHeight = mThumb == null ? 0 : mThumb.getIntrinsicHeight();
        int dw = 0;
        int dh = 0;
        if (d != null) {
            dw = Math.max(mMinWidth, Math.min(mMaxWidth, d.getIntrinsicWidth()));
            dh = Math.max(mMinHeight, Math.min(mMaxHeight, d.getIntrinsicHeight()));
            dh = Math.max(thumbHeight, dh);
        }
        dw += mPaddingLeft + mPaddingRight;
        dh += mPaddingTop + mPaddingBottom;

        setMeasuredDimension(resolveSizeAndState(dw, widthMeasureSpec, 0),
                resolveSizeAndState(dh, heightMeasureSpec, 0));
    
voidonProgressRefresh(float scale, boolean fromUser)

        super.onProgressRefresh(scale, fromUser);

        final Drawable thumb = mThumb;
        if (thumb != null) {
            setThumbPos(getWidth(), thumb, scale, Integer.MIN_VALUE);

            // Since we draw translated, the drawable's bounds that it signals
            // for invalidation won't be the actual bounds we want invalidated,
            // so just invalidate this whole view.
            invalidate();
        }
    
public voidonResolveDrawables(int layoutDirection)

hide

        super.onResolveDrawables(layoutDirection);

        if (mThumb != null) {
            mThumb.setLayoutDirection(layoutDirection);
        }
    
public voidonRtlPropertiesChanged(int layoutDirection)

        super.onRtlPropertiesChanged(layoutDirection);

        final Drawable thumb = mThumb;
        if (thumb != null) {
            setThumbPos(getWidth(), thumb, getScale(), Integer.MIN_VALUE);

            // Since we draw translated, the drawable's bounds that it signals
            // for invalidation won't be the actual bounds we want invalidated,
            // so just invalidate this whole view.
            invalidate();
        }
    
protected voidonSizeChanged(int w, int h, int oldw, int oldh)

        super.onSizeChanged(w, h, oldw, oldh);

        updateThumbAndTrackPos(w, h);
    
voidonStartTrackingTouch()
This is called when the user has started touching this widget.

        mIsDragging = true;
    
voidonStopTrackingTouch()
This is called when the user either releases his touch or the touch is canceled.

        mIsDragging = false;
    
public booleanonTouchEvent(android.view.MotionEvent event)

        if (!mIsUserSeekable || !isEnabled()) {
            return false;
        }

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                if (isInScrollingContainer()) {
                    mTouchDownX = event.getX();
                } else {
                    setPressed(true);
                    if (mThumb != null) {
                        invalidate(mThumb.getBounds()); // This may be within the padding region
                    }
                    onStartTrackingTouch();
                    trackTouchEvent(event);
                    attemptClaimDrag();
                }
                break;

            case MotionEvent.ACTION_MOVE:
                if (mIsDragging) {
                    trackTouchEvent(event);
                } else {
                    final float x = event.getX();
                    if (Math.abs(x - mTouchDownX) > mScaledTouchSlop) {
                        setPressed(true);
                        if (mThumb != null) {
                            invalidate(mThumb.getBounds()); // This may be within the padding region
                        }
                        onStartTrackingTouch();
                        trackTouchEvent(event);
                        attemptClaimDrag();
                    }
                }
                break;

            case MotionEvent.ACTION_UP:
                if (mIsDragging) {
                    trackTouchEvent(event);
                    onStopTrackingTouch();
                    setPressed(false);
                } else {
                    // Touch up when we never crossed the touch slop threshold should
                    // be interpreted as a tap-seek to that location.
                    onStartTrackingTouch();
                    trackTouchEvent(event);
                    onStopTrackingTouch();
                }
                // ProgressBar doesn't know to repaint the thumb drawable
                // in its inactive state when the touch stops (because the
                // value has not apparently changed)
                invalidate();
                break;

            case MotionEvent.ACTION_CANCEL:
                if (mIsDragging) {
                    onStopTrackingTouch();
                    setPressed(false);
                }
                invalidate(); // see above explanation
                break;
        }
        return true;
    
public booleanperformAccessibilityAction(int action, android.os.Bundle arguments)

        if (super.performAccessibilityAction(action, arguments)) {
            return true;
        }
        if (!isEnabled()) {
            return false;
        }
        final int progress = getProgress();
        final int increment = Math.max(1, Math.round((float) getMax() / 5));
        switch (action) {
            case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: {
                if (progress <= 0) {
                    return false;
                }
                setProgress(progress - increment, true);
                onKeyChange();
                return true;
            }
            case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: {
                if (progress >= getMax()) {
                    return false;
                }
                setProgress(progress + increment, true);
                onKeyChange();
                return true;
            }
        }
        return false;
    
private voidsetHotspot(float x, float y)

        final Drawable bg = getBackground();
        if (bg != null) {
            bg.setHotspot(x, y);
        }
    
public voidsetKeyProgressIncrement(int increment)
Sets the amount of progress changed via the arrow keys.

param
increment The amount to increment or decrement when the user presses the arrow keys.

        mKeyProgressIncrement = increment < 0 ? -increment : increment;
    
public synchronized voidsetMax(int max)

        super.setMax(max);

        if ((mKeyProgressIncrement == 0) || (getMax() / mKeyProgressIncrement > 20)) {
            // It will take the user too long to change this via keys, change it
            // to something more reasonable
            setKeyProgressIncrement(Math.max(1, Math.round((float) getMax() / 20)));
        }
    
public voidsetSplitTrack(boolean splitTrack)
Specifies whether the track should be split by the thumb. When true, the thumb's optical bounds will be clipped out of the track drawable, then the thumb will be drawn into the resulting gap.

param
splitTrack Whether the track should be split by the thumb

        mSplitTrack = splitTrack;
        invalidate();
    
public voidsetThumb(android.graphics.drawable.Drawable thumb)
Sets the thumb that will be drawn at the end of the progress meter within the SeekBar.

If the thumb is a valid drawable (i.e. not null), half its width will be used as the new thumb offset (@see #setThumbOffset(int)).

param
thumb Drawable representing the thumb

        final boolean needUpdate;
        // This way, calling setThumb again with the same bitmap will result in
        // it recalcuating mThumbOffset (if for example it the bounds of the
        // drawable changed)
        if (mThumb != null && thumb != mThumb) {
            mThumb.setCallback(null);
            needUpdate = true;
        } else {
            needUpdate = false;
        }

        if (thumb != null) {
            thumb.setCallback(this);
            if (canResolveLayoutDirection()) {
                thumb.setLayoutDirection(getLayoutDirection());
            }

            // Assuming the thumb drawable is symmetric, set the thumb offset
            // such that the thumb will hang halfway off either edge of the
            // progress bar.
            mThumbOffset = thumb.getIntrinsicWidth() / 2;

            // If we're updating get the new states
            if (needUpdate &&
                    (thumb.getIntrinsicWidth() != mThumb.getIntrinsicWidth()
                        || thumb.getIntrinsicHeight() != mThumb.getIntrinsicHeight())) {
                requestLayout();
            }
        }

        mThumb = thumb;

        applyThumbTint();
        invalidate();

        if (needUpdate) {
            updateThumbAndTrackPos(getWidth(), getHeight());
            if (thumb != null && thumb.isStateful()) {
                // Note that if the states are different this won't work.
                // For now, let's consider that an app bug.
                int[] state = getDrawableState();
                thumb.setState(state);
            }
        }
    
public voidsetThumbOffset(int thumbOffset)
Sets the thumb offset that allows the thumb to extend out of the range of the track.

param
thumbOffset The offset amount in pixels.

        mThumbOffset = thumbOffset;
        invalidate();
    
private voidsetThumbPos(int w, android.graphics.drawable.Drawable thumb, float scale, int offset)
Updates the thumb drawable bounds.

param
w Width of the view, including padding
param
thumb Drawable used for the thumb
param
scale Current progress between 0 and 1
param
offset Vertical offset for centering. If set to {@link Integer#MIN_VALUE}, the current offset will be used.

        int available = w - mPaddingLeft - mPaddingRight;
        final int thumbWidth = thumb.getIntrinsicWidth();
        final int thumbHeight = thumb.getIntrinsicHeight();
        available -= thumbWidth;

        // The extra space for the thumb to move on the track
        available += mThumbOffset * 2;

        final int thumbPos = (int) (scale * available + 0.5f);

        final int top, bottom;
        if (offset == Integer.MIN_VALUE) {
            final Rect oldBounds = thumb.getBounds();
            top = oldBounds.top;
            bottom = oldBounds.bottom;
        } else {
            top = offset;
            bottom = offset + thumbHeight;
        }

        final int left = (isLayoutRtl() && mMirrorForRtl) ? available - thumbPos : thumbPos;
        final int right = left + thumbWidth;

        final Drawable background = getBackground();
        if (background != null) {
            final Rect bounds = thumb.getBounds();
            final int offsetX = mPaddingLeft - mThumbOffset;
            final int offsetY = mPaddingTop;
            background.setHotspotBounds(left + offsetX, top + offsetY,
                    right + offsetX, bottom + offsetY);
        }

        // Canvas will be translated, so 0,0 is where we start drawing
        thumb.setBounds(left, top, right, bottom);
    
public voidsetThumbTintList(android.content.res.ColorStateList tint)
Applies a tint to the thumb drawable. Does not modify the current tint mode, which is {@link PorterDuff.Mode#SRC_IN} by default.

Subsequent calls to {@link #setThumb(Drawable)} will automatically mutate the drawable and apply the specified tint and tint mode using {@link Drawable#setTintList(ColorStateList)}.

param
tint the tint to apply, may be {@code null} to clear tint
attr
ref android.R.styleable#SeekBar_thumbTint
see
#getThumbTintList()
see
Drawable#setTintList(ColorStateList)

        mThumbTintList = tint;
        mHasThumbTint = true;

        applyThumbTint();
    
public voidsetThumbTintMode(PorterDuff.Mode tintMode)
Specifies the blending mode used to apply the tint specified by {@link #setThumbTintList(ColorStateList)}} to the thumb drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}.

param
tintMode the blending mode used to apply the tint, may be {@code null} to clear tint
attr
ref android.R.styleable#SeekBar_thumbTintMode
see
#getThumbTintMode()
see
Drawable#setTintMode(PorterDuff.Mode)

        mThumbTintMode = tintMode;
        mHasThumbTintMode = true;

        applyThumbTint();
    
private voidtrackTouchEvent(android.view.MotionEvent event)

        final int width = getWidth();
        final int available = width - mPaddingLeft - mPaddingRight;
        final int x = (int) event.getX();
        float scale;
        float progress = 0;
        if (isLayoutRtl() && mMirrorForRtl) {
            if (x > width - mPaddingRight) {
                scale = 0.0f;
            } else if (x < mPaddingLeft) {
                scale = 1.0f;
            } else {
                scale = (float)(available - x + mPaddingLeft) / (float)available;
                progress = mTouchProgressOffset;
            }
        } else {
            if (x < mPaddingLeft) {
                scale = 0.0f;
            } else if (x > width - mPaddingRight) {
                scale = 1.0f;
            } else {
                scale = (float)(x - mPaddingLeft) / (float)available;
                progress = mTouchProgressOffset;
            }
        }
        final int max = getMax();
        progress += scale * max;

        setHotspot(x, (int) event.getY());
        setProgress((int) progress, true);
    
private voidupdateThumbAndTrackPos(int w, int h)

        final Drawable track = getCurrentDrawable();
        final Drawable thumb = mThumb;

        // The max height does not incorporate padding, whereas the height
        // parameter does.
        final int trackHeight = Math.min(mMaxHeight, h - mPaddingTop - mPaddingBottom);
        final int thumbHeight = thumb == null ? 0 : thumb.getIntrinsicHeight();

        // Apply offset to whichever item is taller.
        final int trackOffset;
        final int thumbOffset;
        if (thumbHeight > trackHeight) {
            trackOffset = (thumbHeight - trackHeight) / 2;
            thumbOffset = 0;
        } else {
            trackOffset = 0;
            thumbOffset = (trackHeight - thumbHeight) / 2;
        }

        if (track != null) {
            track.setBounds(0, trackOffset, w - mPaddingRight - mPaddingLeft,
                    h - mPaddingBottom - trackOffset - mPaddingTop);
        }

        if (thumb != null) {
            setThumbPos(w, thumb, getScale(), thumbOffset);
        }
    
protected booleanverifyDrawable(android.graphics.drawable.Drawable who)

        return who == mThumb || super.verifyDrawable(who);