如何使“滚动条”出现在左侧?
Posted
技术标签:
【中文标题】如何使“滚动条”出现在左侧?【英文标题】:How to make the `scrollbar` appear on the left side? 【发布时间】:2012-06-05 07:31:31 【问题描述】:在android ListView
中,如何使scrollbar
出现在左侧?
【问题讨论】:
【参考方案1】:示例:
mView.setVerticalScrollbarPosition(View.SCROLLBAR_POSITION_LEFT);
【讨论】:
也可以通过 xml:android:verticalScrollbarPosition="left" 很遗憾不能在 NavigationView (API 23) 中工作。【参考方案2】:您可以使用View.SCROLLBAR_POSITION_LEFT 将任何视图的滚动条位置向左移动。
【讨论】:
【参考方案3】:正如其他两个答案所提到的,一种可能性是将View.setVerticalScrollbarPosition() 与SCROLLBAR_POSITION_LEFT 一起使用。然而,一个巨大的警告是,这需要 API 级别 11+,在撰写本文时占 Android 安装的不到 10%。对于大多数应用程序来说,这是不可接受的。
想到在旧版本的 Android 上实现您想要的一种可能性是做一些非常笨拙的事情:关闭滚动条,用左侧的窄布局镜像您的主布局,刚好足够宽以适应滚动条,并在滚动主视图时使用 scrollyBy() 手动滚动左视图(通过覆盖 onScrollChanged())。
也就是说,除非有非常令人信服的理由将滚动条向左移动,否则我实际上并不建议这样做。在大多数情况下,您希望您的应用能够适应设备上的任何其他应用并像设备上的任何其他应用一样运行,只需让 Android 遵循其默认设置即可。
【讨论】:
【参考方案4】:试试我的 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);
【讨论】:
好吧,如果我在if(Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB)
的正文中调用 tryApiLevelPre11()
就可以了。【参考方案5】:
你可以在xml中添加这个
android:verticalScrollbarPosition="left"
喜欢这个
<ScrollView
android:layout_
android:layout_
android:verticalScrollbarPosition="left"
android:scrollbarThumbVertical="@drawable/scrollbar"
/>
或在 Kotlin 中使用此代码
scrollView.verticalScrollbarPosition = View.SCROLLBAR_POSITION_LEFT
【讨论】:
以上是关于如何使“滚动条”出现在左侧?的主要内容,如果未能解决你的问题,请参考以下文章
如何让背景图片不随着上下滚动条滚动,但是可以随着左右滚动条滚动呢?