【问题标题】:Can't make spinner's scrollbar always visible (Android)无法使微调器的滚动条始终可见(Android)
【发布时间】:2012-04-18 08:38:01
【问题描述】:

我有这样一个问题 - 我想让微调器的滚动条始终可见。 但是对于微调功能

setScrollbarFadingEnabled(false);

在绘制 GUI 期间导致 NullExceptionPointer 崩溃。

XML 标签也不能解决这个问题 - 似乎微调器只是忽略它们。

也许还有其他移动方式?例如,使用自定义滚动条?如果是,我该怎么做?

感谢您的回答, 德米特里。

正如我被问到的,这里是简单项目的 LogCat 错误消息,其中只有一个微调器:

AndroidRuntime(2252): FATAL EXCEPTION: main
AndroidRuntime(2252): java.lang.NullPointerException
AndroidRuntime(2252): at android.view.View.onDrawScrollBars(View.java:5836)
AndroidRuntime(2252): at android.view.View.draw(View.java:6799)
AndroidRuntime(2252): at android.view.ViewGroup.drawChild(ViewGroup.java:1640)
AndroidRuntime(2252): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367)
AndroidRuntime(2252): at android.view.ViewGroup.drawChild(ViewGroup.java:1638)
AndroidRuntime(2252): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367)
AndroidRuntime(2252): at android.view.View.draw(View.java:6796)
AndroidRuntime(2252): at android.widget.FrameLayout.draw(FrameLayout.java:352)
AndroidRuntime(2252): at android.view.ViewGroup.drawChild(ViewGroup.java:1640)
AndroidRuntime(2252): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367)
AndroidRuntime(2252): at android.view.ViewGroup.drawChild(ViewGroup.java:1638)
AndroidRuntime(2252): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367)
AndroidRuntime(2252): at android.view.View.draw(View.java:6796)
AndroidRuntime(2252): at android.widget.FrameLayout.draw(FrameLayout.java:352)
AndroidRuntime(2252): at com.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:2078)
AndroidRuntime(2252): at android.view.ViewRoot.draw(ViewRoot.java:1433)
AndroidRuntime(2252): at android.view.ViewRoot.performTraversals(ViewRoot.java:1175)
AndroidRuntime(2252): at android.view.ViewRoot.handleMessage(ViewRoot.java:1753)
AndroidRuntime(2252): at android.os.Handler.dispatchMessage(Handler.java:99)
AndroidRuntime(2252): at android.os.Looper.loop(Looper.java:123)
AndroidRuntime(2252): at android.app.ActivityThread.main(ActivityThread.java:4632)
AndroidRuntime(2252): at java.lang.reflect.Method.invokeNative(Native Method)
AndroidRuntime(2252): at java.lang.reflect.Method.invoke(Method.java:521)
AndroidRuntime(2252): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:871)
AndroidRuntime(2252): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:629)
AndroidRuntime(2252): at dalvik.system.NativeStart.main(Native Method)

【问题讨论】:

  • 我们能看到一些 LogCat 吗?谢谢。
  • 所有 api 级别都会发生这种情况吗?
  • @nandeesh 我知道自 API 15 以来会发生这种情况。不确定次要级别。

标签: android scrollbar spinner


【解决方案1】:

经过初步调查,我认为无法在 Spinner 中调用 setScrollbarFadingEnabled(false);

我已经阅读了 Class Spinner.javaView.java 的实现(这最后一个实现了 API16 的 setScrollbarFadingEnabled(boolean),问题出在这行:

cache.scrollBar.setAlpha(255);

此时cache.scrollBar 可能为空,我没有找到任何方法来强制对该属性进行一些初始化。

管理这个属性的大多数方法都是受保护的或私有的,所以我们不能只调用它们。

我将继续研究这个问题以找到可能的解决方案,但目前,考虑到还没有人回答这个问题,我认为这是不可能的。

【讨论】:

    【解决方案2】:

    Spinner 没有滚动条,因此您得到 NullPointerException。

    微调器显示的弹出窗口有一个滚动条。所以需要修改 spinner 显示的 ListView 的属性。但是 ListView 本身并没有被 Spinner 通过任何公共方法公开。

    即使你通过反射得到ListPopupWindow,也会出现另一个问题,即ListPopupWindow的ListView只有在你点击Spinner之后才会创建。

    但是Spinner的OnClickListener不能注册,显示后设置ListView属性。

    您可以创建一个覆盖 performClick 的自定义微调器,然后通过反射获取 mPopup。并使用mPopup.getListView().setScrollbarFadingEnabled(false)

    但是,如果您要创建自定义 Spinner,我相信实现整个弹出窗口以满足您的需要比使用反射更容易。

    【讨论】:

    • 好的,谢谢你的回答,这和我想的差不多。很伤心。
    【解决方案3】:

    感谢@nandeesh 的回答,也感谢@Eng.Fouadhis/her answer on another page

    public class VisibleScrollbarSpinner extends Spinner {
        @Override public boolean performClick() {
            final boolean superResult = super.performClick();
    
            try {
                final Field mPopupField = Spinner.class.getDeclaredField("mPopup");
                mPopupField.setAccessible(true);
                //noinspection ConstantConditions
                ((ListPopupWindow) mPopupField.get(this)).getListView().setScrollbarFadingEnabled(false);
                mPopupField.setAccessible(false);
            } catch (NoSuchFieldException | IllegalAccessException e) {
                Log.e(TAG, e.toString(), e);
            }
    
            return superResult;
        }
    
        public VisibleScrollbarSpinner(Context context) { super(context); } 
        public VisibleScrollbarSpinner(Context context, int mode) { super(context, mode); } 
        public VisibleScrollbarSpinner(Context context, AttributeSet attrs) { super(context, attrs); } 
        public VisibleScrollbarSpinner(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } 
        public VisibleScrollbarSpinner(Context context, AttributeSet attrs, int defStyleAttr, int mode) { super(context, attrs, defStyleAttr, mode); }
    }
    

    【讨论】:

      【解决方案4】:

      我注意到“setScrollbarFadingEnabled”java 方法和“fadeScrollbar”xml 方法都不会对 spinner 产生任何影响,因为 spinner 的列表视图被包装在一个对话框(弹出)中,所以这些属性不会到达列表视图。

      但实际上到达微调器列表视图的是主题。

      所以只需像这样创建一个自定义主题:

      <style name="App_SpinnerStyle" >
              <item name="android:fadeScrollbars">false</item>
      </style>
      

      然后像这样将它添加到微调器中:

      android:popupTheme="@style/App_SpinnerStyle"
      

      久经考验!

      【讨论】:

        【解决方案5】:

        在您的应用主题或活动中:

          <item name="android:dropDownListViewStyle">@style/SpinnerStyle1</item>
        

        声明 SpinnerStyle1:

        <style name="SpinnerStyle1" parent="Widget.AppCompat.ListView.DropDown">
                <item name="android:divider">@color/blackText</item>
                <item name="android:dividerHeight">1px</item>
                  <item name="android:scrollbarAlwaysDrawVerticalTrack">true</item>
        </style>
        

        【讨论】:

          【解决方案6】:

          由于访问微调器的底层ListView 并不容易,我为此找到了一个简单的解决方案。

          在styles.xml 中创建一个样式,并将scrollbarFadeDuration 设置为某个无穷大的值。

          <style name="AlwaysEnableScrollBar" parent="Widget.AppCompat.ListView.DropDown">
              <item name="android:scrollbarFadeDuration">10000000</item>
          </style>
          

          然后在微调器主题中设置它:

          <Spinner
              ...
              android:theme="@style/AlwaysEnableScrollBar"/>
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2018-05-22
            • 2010-11-15
            • 1970-01-01
            • 2023-02-01
            • 2021-06-20
            • 2013-10-19
            • 2011-09-15
            • 2012-11-21
            相关资源
            最近更新 更多