How to make the `scrollbar` appear on the left side?

安稳与你 提交于 2019-11-30 07:58:02

example:

mView.setVerticalScrollbarPosition(View.SCROLLBAR_POSITION_LEFT);

You can move the scrollbar position to the left for any View using View.SCROLLBAR_POSITION_LEFT.

As the other two answers have mentioned, one possibility is using View.setVerticalScrollbarPosition() with SCROLLBAR_POSITION_LEFT. However, one giant caveat is that this requires API level 11+, which at time of writing accounts for fewer than 10% of Android installations. For most applications, that's not acceptable.

One possibility that comes to mind to accomplish what you want on older versions of Android would be to do something very kludgy: turn off the scroll bar, mirror your main layout with a narrow layout to the left of it, just wide enough to fit a scroll bar, and manually scroll the left view with scrollyBy() as your main view is scrolled (by overriding onScrollChanged()).

That said, I wouldn't actually recommend that unless there's a very compelling reason to move the scroll bar to the left. In most cases, you want your app to fit in and behave like any other app on the device by just letting Android follow its defaults.

Try my hack, seems to work at least on 2.2 and above.

import java.lang.reflect.Field;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.ListView;

/**
 * This class fixes the lack of setVerticalScrollbarPosition(View.SCROLLBAR_POSITION_LEFT) before API level 11
 * @author Genadz Batsyan
 */

public class ListViewWithLeftScrollBar extends ListView {
    private static final String LOG_TAG = ListViewWithLeftScrollBar.class.getSimpleName();
    private static final boolean DEBUG = true;

    private boolean patchInvalidate;

    public ListViewWithLeftScrollBar(Context context) {
        super(context);
        moveVerticalScrollbarToTheLeft();
    }

    public ListViewWithLeftScrollBar(Context context, AttributeSet attrs) {
        super(context, attrs);
        moveVerticalScrollbarToTheLeft();
    }

    public ListViewWithLeftScrollBar(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        moveVerticalScrollbarToTheLeft();
    }

    @Override
    public void invalidate(Rect r) {
        invalidate(r.left, r.top, r.right, r.bottom);
    }

    @Override
    public void invalidate(int left, int top, int right, int bottom) {
        int width = right - left;
        if (DEBUG) log("invalidate original w:"+ getWidth() +" h:"+ getHeight()+"  rect:"+left+", "+top+", "+right+", "+bottom);
        if (patchInvalidate && right == getWidth() && top == 0 && bottom == getHeight() && width < 30) {
            // The above condition should ensure that ListView is VERY likely to be invalidating the scrollbar.
            // In fact ListView appears to not invalidate anything except the scrollbar, ever.
            left = 0;
            right = left + width;
            if (DEBUG) log("invalidate patched  w:"+ getWidth() +" h:"+ getHeight()+"  rect:"+left+", "+top+", "+right+", "+bottom);
        }
        super.invalidate(left, top, right, bottom);
    }

    private void moveVerticalScrollbarToTheLeft() {
        try {
            if (DEBUG) log("moveVerticalScrollbarToTheLeft: Trying API Level >=11");
            tryApiLevel11();
            if (DEBUG) log("moveVerticalScrollbarToTheLeft: API Level >=11 success");
        } catch (Throwable t1) {
            if (DEBUG) {
                log("moveVerticalScrollbarToTheLeft: API Level >=11 FAILED");
                t1.printStackTrace();
            }
            try {
                if (DEBUG) log("moveVerticalScrollbarToTheLeft: Trying hack for API Level <11");
                tryApiLevelPre11();
                patchInvalidate = true;
                if (DEBUG) log("moveVerticalScrollbarToTheLeft: API Level <11 hack success");
            } catch (Throwable t2) {
                if (DEBUG) {
                    log("moveVerticalScrollbarToTheLeft: API Level <11 hack FAILED");
                    t2.printStackTrace();
                }
            }
        }
    }

    @SuppressLint("NewApi")
    private void tryApiLevel11() {
        setVerticalScrollbarPosition(View.SCROLLBAR_POSITION_LEFT);
    }

    private void tryApiLevelPre11() throws Exception {
        Class<?> viewClass = View.class;

        Field scrollCacheField = viewClass.getDeclaredField("mScrollCache");
        scrollCacheField.setAccessible(true);
        Object scrollCache = scrollCacheField.get(this);
        if (DEBUG) log("scrollCache: "+ scrollCache);

        Field scrollBarField = scrollCache.getClass().getDeclaredField("scrollBar");
        scrollBarField.setAccessible(true);
        Object scrollBar = scrollBarField.get(scrollCache);
        if (DEBUG) log("scrollBar: "+ scrollBar);

        Field verticalThumbField = scrollBar.getClass().getDeclaredField("mVerticalThumb");
        verticalThumbField.setAccessible(true);
        Object verticalThumb = verticalThumbField.get(scrollBar);
        if (DEBUG) log("verticalThumb: "+ verticalThumb);

        Drawable verticalThumbDrawable = (Drawable) verticalThumb;
        Drawable replacementVerticalThumbDrawable = new LayerDrawable(new Drawable[]{ verticalThumbDrawable }) {
            @Override
            public void setBounds(int left, int top, int right, int bottom) {
                if (DEBUG) log("setBounds original: "+left+", "+top+", "+right+", "+bottom);
                int width = right - left;
                left = 0;
                right = left + width;
                if (DEBUG) log("setBounds patched:  "+left+", "+top+", "+right+", "+bottom);
                super.setBounds(left, top, right, bottom);
            }       
        };
        verticalThumbField.set(scrollBar, replacementVerticalThumbDrawable);
    }

    private static void log(String msg) {
        Log.d(LOG_TAG, msg);
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!