31

在 AndroidListView中,如何使scrollbar左侧出现?

4

5 回答 5

57

例子:

mView.setVerticalScrollbarPosition(View.SCROLLBAR_POSITION_LEFT);
于 2012-05-31T03:20:22.787 回答
3

您可以使用View.SCROLLBAR_​​POSITION_LEFT将任何视图的滚动条位置移动到左侧。

于 2012-05-31T02:59:05.897 回答
3

正如其他两个答案所提到的,一种可能性是将View.setVerticalScrollbarPosition()SCROLLBAR_ ​​POSITION_LEFT 一起使用。然而,一个巨大的警告是,这需要 API 级别 11+,在撰写本文时占 Android 安装的不到 10%。对于大多数应用程序,这是不可接受的。

在旧版本的 Android 上实现您想要的一种可能性是做一些非常笨拙的事情:关闭滚动条,用左侧的窄布局镜像您的主布局,宽度足以容纳滚动条,并在滚动主视图时使用scrollyBy()手动滚动左视图(通过覆盖 onScrollChanged())。

也就是说,除非有非常令人信服的理由将滚动条向左移动,否则我实际上并不建议这样做。在大多数情况下,您希望您的应用程序适合设备上的任何其他应用程序并像设备上的任何其他应用程序一样运行,只需让 Android 遵循其默认设置即可。

于 2012-05-31T04:06:47.250 回答
1

试试我的 hack,似乎至少在 2.2 及更高版本上有效。

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);
    }
}
于 2012-09-21T09:36:06.973 回答
1

你可以在xml中添加这个

android:verticalScrollbarPosition="left"

像这样

<ScrollView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:verticalScrollbarPosition="left"
    android:scrollbarThumbVertical="@drawable/scrollbar"
    />

或在 Kotlin 中使用此代码

scrollView.verticalScrollbarPosition = View.SCROLLBAR_POSITION_LEFT
于 2020-12-01T13:57:04.920 回答