0

I would like to change a SeekBar's behaviour. Therefore I need to edit two methods in AbsSeekBar, one of them is protected the other is

How can I do it? Now I can't simply copy said methods from the AbsSeekbar and override them in my custom SeekBar class - I end up missing all field parameters. I also can't just edit the AbsSeekBar class itself, since it is not part of my project. Any help is appreciated. These are the two methods:

public abstract class AbsSeekBar extends ProgressBar {
.
.
.
@Override
public boolean onTouchEvent(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;


private void trackTouchEvent(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);
}
Jan Bibber
  • 53
  • 4
  • Can you list the method names? And post what code you already have? – petey May 12 '15 at 21:06
  • added said two methods and I have no idea how to approach this problem or if it's even possible. i want to add a time delay in the seekbar, so if i move my finger down the progress bar moves slower. I have the code ready but I just don't know how to make Android Studio use my edited two modified methods instead of the default ones. – Jan Bibber May 12 '15 at 21:20

2 Answers2

0

I'm not sure I understand 'I end up missing all field parameters'

The only way you can edit a method's functionality in Java is by extending the class.

Example:

public class CustomSeekbar extends AbsSeekBar {
    public CustomSeekbar(Context context) {
        super(context);
    }

    @Override
    protected boolean verifyDrawable(Drawable who) {
        //Do your own method functionality
        //Return your own true/false
        return super.verifyDrawable(who);
    }
}

In this case you don't have to return super.verifyDrawable if you don't want to, and you can supply your own response.

This is true for all protected or public methods in the AbsSeekBar class.

By reflection, you can modify fields of the class if you so please.

For example:

    Field drawableField = absSeekBarInstance.getClass().getField("mThumb");
    drawableField.setAccessible(true);
    drawableField.set(absSeekBarInstance, someDrawable);

Or to GET the field values, you just say

    drawableField.get(absSeekBarInstance);

To go even further, you'll need to provide me more information.

Private methods cannot be changed. It's just not possible.

Aspect-oriented programming in android

AspectJ comes close, but you can't do what you're describing. Thats just how Java works. In Objective-c you can do this, it is called 'swizzling'.

But yes, in Java, you cannot change the functionality of compiled methods.

Your best bet would be to copy AbsSeekBar and all of its required classes into your own project.

Community
  • 1
  • 1
Vic Vuci
  • 6,993
  • 6
  • 55
  • 90
  • "This is true for all protected or public methods in the AbsSeekBar class." What do I do with private methods? – Jan Bibber May 12 '15 at 21:27
  • Read my edits. You can't change the functionality of private methods. That is why they are private. – Vic Vuci May 12 '15 at 21:40
0

If you absolutely have to change how a private method works, you'll need to copy the entire class into your project, edit that copy, and use that version of the class instead of the original. Its something that should probably be avoided if possible.

Gabe Sechan
  • 90,003
  • 9
  • 87
  • 127
  • I tried to do that and it resulted in lots errors in super calls. – Jan Bibber May 12 '15 at 22:49
  • Shouldn't be any problems with super, although you may have problem if its using protected functions in its package and you don't have it in the same package. – Gabe Sechan May 12 '15 at 22:59