Android:在自定义视图中启用滚动条

6
我已经实现了一个自定义的布局,它扩展了RelativeLayout。它显示了许多在运行时创建的不同元素,并且可以在两个方向上使用scrollTo()和scrollBy()进行滚动。滚动已经起作用了,现在我想添加标准的Android滚动条。
使用ScrollView是不可能的,因为我需要Layout在2个维度上可滚动,所以我尝试按照这里描述的方式来做:Android: Enable Scrollbars on Canvas-Based View 我已经使用一些(虚假的)值实现了所有的compute*方法并启用了滚动条。但我仍然无法让它们显示出来。有什么想法可能是问题吗?
在各种邮件列表和SO中有大量类似的问题,但无论何处,答案似乎都是“1.调用setHorizontalScrollbarEnabled(true),2.实现所有的compute*方法,3.调用awakenScrollbars()”。据我所知,我已经做到了这一点,甚至尝试使用initializeScrollbars(),但什么也没有发生,文档也没有提供任何帮助。
public NodeLayout(Context context) {
    super(context);

    setVerticalScrollBarEnabled(true);
    setHorizontalScrollBarEnabled(true);

    TypedArray a = context.obtainStyledAttributes(R.styleable.View);
    initializeScrollbars(a);
    a.recycle();
}

@Override
protected int computeHorizontalScrollExtent() {
    return 5;
}

@Override
protected int computeHorizontalScrollOffset() {
    return 10;
}

@Override
protected int computeHorizontalScrollRange() {
    return 50;
}

@Override
protected int computeVerticalScrollExtent() {
    return getHeight() / 2;
}

@Override
protected int computeVerticalScrollOffset() {
    return getHeight() / 2;
}

@Override
protected int computeVerticalScrollRange() {
    return getHeight();
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    awakenScrollBars();
    invalidate();
    return true;
}

这是我的 attrs.xml 文件的样子:

<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="View">
<attr name="android:background"/>
<attr name="android:clickable"/>
<attr name="android:contentDescription"/>
<attr name="android:drawingCacheQuality"/>
<attr name="android:duplicateParentState"/>
<attr name="android:fadeScrollbars"/>
<attr name="android:fadingEdge"/>
<attr name="android:fadingEdgeLength"/>
<attr name="android:fitsSystemWindows"/>
<attr name="android:focusable"/>
<attr name="android:focusableInTouchMode"/>
<attr name="android:hapticFeedbackEnabled"/>
<attr name="android:id"/>
<attr name="android:isScrollContainer"/>
<attr name="android:keepScreenOn"/>
<attr name="android:longClickable"/>
<attr name="android:minHeight"/>
<attr name="android:minWidth"/>
<attr name="android:nextFocusDown"/>
<attr name="android:nextFocusLeft"/>
<attr name="android:nextFocusRight"/>
<attr name="android:nextFocusUp"/>
<attr name="android:onClick"/>
<attr name="android:padding"/>
<attr name="android:paddingBottom"/>
<attr name="android:paddingLeft"/>
<attr name="android:paddingRight"/>
<attr name="android:paddingTop"/>
<attr name="android:saveEnabled"/>
<attr name="android:scrollX"/>
<attr name="android:scrollY"/>
<attr name="android:scrollbarAlwaysDrawHorizontalTrack"/>
<attr name="android:scrollbarAlwaysDrawVerticalTrack"/>
<attr name="android:scrollbarDefaultDelayBeforeFade"/>
<attr name="android:scrollbarFadeDuration"/>
<attr name="android:scrollbarSize"/>
<attr name="android:scrollbarStyle"/>
<attr name="android:scrollbarThumbHorizontal"/>
<attr name="android:scrollbarThumbVertical"/>
<attr name="android:scrollbarTrackHorizontal"/>
<attr name="android:scrollbarTrackVertical"/>
<attr name="android:scrollbars"/>
<attr name="android:soundEffectsEnabled"/>
<attr name="android:tag"/>
<attr name="android:visibility"/>
</declare-styleable>
</resources>

我正在开发 Android 3.0。


我也遇到了同样的问题。到目前为止,我已经按照你在问题中描述的一切做了,但结果都一样(没有出现滚动条)。我也是在> 3.0上开发...自从发布问题以来,你有什么进展吗? - ashughes
不好意思,最后我放弃了滚动条。 - Frederic
好的,如果你还感兴趣的话,我终于弄清楚了。我在下面添加了一个答案。我简直不敢相信我找不到其他有同样问题/解决方案的人...肯定有更多的人正在制作自定义ViewGroups并需要滚动条。 - ashughes
2个回答

10

我遇到了同样的问题并最终找到解决办法。

问题在于你正在扩展RelativeLayout,而它是ViewGroup的子类。我发现通过在你所描述的问题中使用自定义View来显示滚动条没有问题,但当我扩展ViewGroup或其子类时,没有出现滚动条。

最后我记得默认情况下ViewGroup不会自行绘制,因此我在我的自定义ViewGroup构造函数中添加了一行代码:setWillNotDraw(false);

结果滚动条出现了!

希望这可以帮到你。


哇... setWillNotDraw(false)。你是怎么发现的?现在(通过实现compute*方法),我可以看到滚动条了,但它不动,现在我需要真正实现这些方法(我只是像上面那样使用硬编码的值)...谢谢你,希望我现在能搞明白。 - Informatic0re

2
请注意,在Android 3.2 / Google TV和Android 3.2.1 /平板电脑上,如果扩展ViewGroup,则<declare-styleable/>的部分不是可选的。问题似乎在于,除非设置了<declare-styleable/>中所有对应的滚动条属性,否则View用于绘制滚动条的所有滚动条绘制和大小都不会加载。未能设置其中一些重要属性会导致在3.2上布局期间出现空指针异常。我还怀疑GridView / ListView / AbsListView / AdapterView系列类不设置水平滚动条属性,如果您正在追逐这个问题。

一般步骤如下:

  • 使用<declare-styleable/>(如上所述)。
  • 在构造函数中尽早调用initScrollbars(如上所述)。
  • 在调用initScrollbars之后调用setHorizontalScrollbarEnabled/setrVerticalScrollBarEnbled。
  • 根据需要实现三个computeHorizontalScrollXXX和computeVerticalScrollXXX。
  • 根据需要频繁调用awakenScrollBars()以显示滚动条。
  • 很可能必须在构造函数中调用setWillNotDraw(false)。滚动条绘制是在View中实现的;但是我确实自己调用了此方法。
  • 考虑调用setScrollBarStyle来控制滚动条的放置。大多数有用的自定义视图将滚动到填充边缘,这将破坏View对滚动条的绘制,如果它们放置在填充矩形外部,因为我们无法访问与View中的股票Android视图相同的隐藏方法。

我想那就是全部内容了。在Android 6.0上所有这些是否都能正常工作...可能性很小。 :-/


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接