【问题标题】:Changing NumberPicker divider color更改 NumberPicker 分隔线颜色
【发布时间】:2014-08-05 16:19:03
【问题描述】:

在最近的 android 版本中,number pickers 在绘制时使用蓝色分隔线(参见下图)。

我想改变这个颜色。有可行的解决方案吗?或者可能是一个包含允许自定义分隔线颜色的 NumberPicker 更新版本的库?

我已经尝试过android-numberpicker,但由于库中的一些代码尝试访问不存在的资源 ID,因此在运行时出现错误(见下文)。

android.content.res.Resources$NotFoundException: Resource ID #0x0
        at android.content.res.Resources.getValue(Resources.java:1123)
        at android.content.res.Resources.loadXmlResourceParser(Resources.java:2309)
        at android.content.res.Resources.getLayout(Resources.java:939)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:395)
        at net.simonvt.numberpicker.NumberPicker.<init>(NumberPicker.java:635)
        at net.simonvt.numberpicker.NumberPicker.<init>(NumberPicker.java:560)
        at net.simonvt.numberpicker.NumberPicker.<init>(NumberPicker.java:550)

【问题讨论】:

  • 这能回答你的问题吗?:stackoverflow.com/questions/18804762/…
  • 不,它不起作用。旨在创建自定义样式的第一个答案不起作用,因为无法解析符号“@style/Holo.NumberPicker”。对于第二个答案,结果是一样的:在反射检索到的字段 mSelectionDivider 上调用 set(numberPicker, color) 没有效果。

标签: android android-styles numberpicker


【解决方案1】:

科特林

您可以通过这种方式更改分隔符编号,而无需版本控制。本例设置透明颜色:

private fun setDividerColor(picker: NumberPicker) {
    val dividerField = NumberPicker::class.java.declaredFields.firstOrNull { it.name == "mSelectionDivider" } ?: return
    try {
        val colorDrawable = ColorDrawable(android.graphics.Color.TRANSPARENT)
        dividerField.isAccessible = true
        dividerField.set(picker, colorDrawable)
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

【讨论】:

    【解决方案2】:

    其实你可以写一个自定义主题来改变分隔线的颜色。

    作为示例将其添加到您的主题.xml

    <style name="NumberPickerTheme" parent="Theme.AppCompat.Light">
            <item name="colorAccent">@android:color/white</item>
            
            <!-- Edit this colorControlNormal value as you need -->
            <item name="colorControlNormal">@android:color/holo_green_dark</item>
            
            <item name="android:textColorPrimary">@android:color/black</item>
            <item name="android:background">@android:color/white</item>
            <item name="android:textSize">30sp</item>
        </style>
    

    并将这个主题添加到您的 Numberpicker

    <NumberPicker
            android:id="@+id/index_picker1"
            android:layout_width="match_parent"
            android:layout_height="200dp"
            android:theme="@style/NumberPickerTheme"
             />
    

    如果你想摆脱分隔线,只需使用

    <item name="colorControlNormal">@android:color/transparent</item>
    

    【讨论】:

      【解决方案3】:

      基于此(https://stackoverflow.com/a/20291416/2915480 虽然是关于 DatePicker)有几种方法:

      1. 在没有 mSelectionDivider 及其附属机构的情况下编写您自己的 NumberPicker,或使用 Vikram 的反向移植。最后一种情况:
      2. github的lib下载
      3. 更改 res/drawable-xxx/np_numberpicker_selection_divider.9.png 中的可绘制对象:
      • 透明(或其他).9.png * 在 res/drawable 中创建 np_numberpicker_selection_divider.xml 形状线资源(带有0dp 高度或透明颜色)。
      1. 或从NumberPicker.java 中的onDraw(Canvas) 方法中删除if (mSelectionDivider != null) 分支,例如here

      2. 使用反射访问private final field mSelectionDivider(详细信息:https://github.com/android/platform_frameworks_base/blob/master/core/java/android/widget/NumberPicker.java) - 例如见修改here。 我使用了反射,但这不是最好的解决方案。

      3. 在 API 21+ 中使用主题来覆盖数字选择器的分隔线颜色:?attr/colorControlNormal 确定材料编号选择器中分隔线的颜色,因此在小部件的主题中更改此颜色即可,例如对于日期选择器:

          <style name="MyAppTheme.NumberPicker" parent=" MyAppTheme">
              <item name="android:colorControlNormal"> ?colorAccent </item>
          </style>
      

      在小部件中:

       <DatePicker
              android:id="@+id/question_date"
              android:layout_width="match_parent"
              android:layout_height="wrap_content" 
              android:calendarViewShown="false"
              android:datePickerMode="spinner"
              android:gravity="center"
              android:theme="@style/MyAppTheme.NumberPicker" />
      

      【讨论】:

      • 感谢您的帮助。解决方案 2 完美运行,但我未能使解决方案 1 工作。最后,与 NumberPicker.java 中的变量 DEFAULT_LAYOUT_RESOURCE_ID 关联的资源 ID 似乎不再有效。最后但同样重要的是,我的目标是将颜色更改为自定义颜色,而不是隐藏分隔线。为了实现这个目标,我没有将mSelectionDivider 设置为null,但等于一个drawable,它是一个简单的九个补丁PNG,加载了getResources().getDrawable(R.drawable.np_numberpicker_selection_divider)
      【解决方案4】:

      我正在使用解决方法 Java 方法:

        private void setDividerColor (NumberPicker picker) {   
      
              java.lang.reflect.Field[] pickerFields = NumberPicker.class.getDeclaredFields();
              for (java.lang.reflect.Field pf : pickerFields) {
                  if (pf.getName().equals("mSelectionDivider")) {
                      pf.setAccessible(true);
                      try {
                          //pf.set(picker, getResources().getColor(R.color.my_orange));
                          //Log.v(TAG,"here");
                          pf.set(picker, getResources().getDrawable(R.drawable.dot_orange));
                      } catch (IllegalArgumentException e) {
                          e.printStackTrace();
                      } catch (NotFoundException e) {
                          e.printStackTrace();
                      } 
                      catch (IllegalAccessException e) {
                          e.printStackTrace();
                      }
                      break;
                  }
              }
              //}
           }
      

      或 Kotlin 方法:

      private fun NumberPicker.setDividerColor(color: Int) {
          val dividerField = NumberPicker::class.java.declaredFields.firstOrNull { it.name == "mSelectionDivider" } ?: return
          try {
             dividerField.isAccessible = true
             dividerField.set(this,getResources().getDrawable(R.drawable.dot_orange))
          } catch (e: Exception) {
              e.printStackTrace()
          }
      }
      

      并应用其

        setDividerColor(yourNumberPicker); // for java method
        yourNumberPicker.setDividerColor(Color.RED) // for kotlin method
      

      【讨论】:

        【解决方案5】:

        使用我的library 很容易(我也推出了自己的 NumberPicker)。

        <com.github.tomeees.scrollpicker.ScrollPicker
            ...
            app:selectorColor="..."
            />
        

        【讨论】:

        • com.github.tomeees.scrollpicker.ScrollPicker 及其 app:selectorColor 运行良好,感谢您制作 Tamás Sajti
        【解决方案6】:

        如果您将来要更改分隔线颜色,最好存储一个私有字段。像这样:

        @Nullable private Field dividerField;
        
        public void setDivider(@Nullable Drawable divider) {
            try {
                if (dividerField == null) {
                    dividerField = NumberPicker.class.getDeclaredField("mSelectionDivider");
                    dividerField.setAccessible(true);
                }
        
                dividerField.set(this, divider);
            } catch (Exception ignore) {}
        }
        

        【讨论】:

          【解决方案7】:

          这在不使用反射的情况下对我有用。

          my_layout.xml

          <NumberPicker
             ...
             android:theme="@style/DefaultNumberPickerTheme" />
          

          Styles.xml(AppTheme是我在应用中的应用主题)

          <style name="DefaultNumberPickerTheme" parent="AppTheme">
                  <item name="colorControlNormal">@color/dividerColor</item>
          </style>
          

          【讨论】:

          • 只是一个友好的提醒。 'colorControlNormal',仅适用于 API 21 及更高版本。
          • 如果存在“colorControlNormal”,请提出替代方案
          • 只是想指出使用colorControlNormal 对我不起作用,我必须明确添加android: 前缀,就像&lt;item name="android:colorControlNormal"&gt;#ffffff&lt;/item&gt;
          【解决方案8】:

          我对 Android 还很陌生,所以请记住,这种解决方案可能不是一个好的做法,但我找到了一种(hacky)方法来获得这种效果,只使用 XML/不使用反射。

          通过向 ViewGroup 添加 2 个薄的水平视图,并为它们提供负布局边距和我想要的背景颜色,我能够“更改”LinearLayout 内 NumberPickers 上分隔线的颜色:

          <?xml version="1.0" encoding="utf-8"?>
          <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="horizontal"
              android:layout_gravity="center_horizontal"
              android:gravity="center"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              >
              <NumberPicker
                  android:layout_width="70dip"
                  android:layout_height="wrap_content"
                  android:focusable="true"
                  android:focusableInTouchMode="true"
                  android:layout_gravity="center"
                  android:layout_margin="5dp"
                  />
          
              <View
                  android:layout_height="2dp"
                  android:layout_width="70dp"
                  android:background="@color/myColor"
                  android:layout_gravity="center_vertical"
                  android:layout_marginLeft="-75dp"
                  android:layout_marginBottom="-25dp">
          
              </View>
          
              <View
                  android:layout_height="2dp"
                  android:layout_width="70dp"
                  android:background="@color/myColor"
                  android:layout_gravity="center_vertical"
                  android:layout_marginLeft="-70dp"
                  android:layout_marginBottom="25dp">
          
              </View>
          
          </LinearLayout>
          

          诚然,我实际上并没有改变颜色,而是在内置分隔线的顶部添加了我想要的颜色的新线条。希望这对某人有所帮助!

          您可能不得不使用边距,但这些设置非常适合我的自定义对话框。

          【讨论】:

            【解决方案9】:

            最简单的方法是在 xml 中的 NumberPicker 选择器中添加此属性

            android:selectionDivider="@colors/your_color"
            

            【讨论】:

              【解决方案10】:

              您可以使用反射来解决问题。这是我的解决方案

              public class ColorChangableNumberPicker extends NumberPicker {
              
                  public ColorChangableNumberPicker(Context context) {
                      super(context);
                      init();
                  }
              
                  public ColorChangableNumberPicker(Context context, AttributeSet attrs) {
                      super(context, attrs);
                      init();
                  }
              
                  public ColorChangableNumberPicker(Context context, AttributeSet attrs, int defStyleAttr) {
                      super(context, attrs, defStyleAttr);
                      init();
                  }
              
                  @TargetApi(Build.VERSION_CODES.LOLLIPOP)
                  public ColorChangableNumberPicker(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
                      super(context, attrs, defStyleAttr, defStyleRes);
                      init();
                  }
              
                  private void init() {
                      setDividerColor(Color.RED);
                  }
              
              
                  public void setDividerColor(@ColorInt int color) {
                      try {
                          Field fDividerDrawable = NumberPicker.class.getDeclaredField("mSelectionDivider");
                          fDividerDrawable.setAccessible(true);
                          Drawable d = (Drawable) fDividerDrawable.get(this);
                          d.setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
                          d.invalidateSelf();
                          postInvalidate(); // Drawable is dirty
                      }
                      catch (Exception e) {
              
                      }
                  }
              }
              

              【讨论】:

              • 我认为这是最好的答案。另外,我认为这对于仅自定义一条线来说太过分了……但那是系统故障。你帮了我很多。谢谢
              【解决方案11】:

              将此代码用于您想用分隔符做的所有事情

              Field[] pickerFields = NumberPicker.class.getDeclaredFields();
                          for (Field pf : pickerFields) {
                              if (pf.getName().equals("mSelectionDivider")) {
                                  pf.setAccessible(true);
                                  try {
                                      pf.set(picker, getResources().getDrawable(R.drawable.divider));
                                  } catch (IllegalArgumentException e) {
                                      e.printStackTrace();
                                  } catch (NotFoundException e) {
                                      e.printStackTrace();
                                  } catch (IllegalAccessException e) {
                                      e.printStackTrace();
                                  }
                                  break;
                              }
                          }
              

              【讨论】:

                【解决方案12】:

                如果您只想更改颜色(基于 stannums 答案):

                private void setDividerColor(NumberPicker picker, int color) {
                
                    java.lang.reflect.Field[] pickerFields = NumberPicker.class.getDeclaredFields();
                    for (java.lang.reflect.Field pf : pickerFields) {
                        if (pf.getName().equals("mSelectionDivider")) {
                            pf.setAccessible(true);
                            try {
                                ColorDrawable colorDrawable = new ColorDrawable(color);
                                pf.set(picker, colorDrawable);
                            } catch (IllegalArgumentException e) {
                                e.printStackTrace();
                            } catch (Resources.NotFoundException e) {
                                e.printStackTrace();
                            }
                            catch (IllegalAccessException e) {
                                e.printStackTrace();
                            }
                            break;
                        }
                    }
                }
                

                然后

                setDividerColor(mNumberPicker, Color.GREEN);
                

                【讨论】:

                • 不错的变化。我注意到的一件事是确保使用 'newColorDrawable(ctx.getResources().getColor(R.color.whatevercolor))' 而不是 'new ColorDrawable(R.color.whatevercolor)'
                • 我真的认为,它应该标记为尝试答案!它真的很简单而且很有效!
                • 可能会更好:ColorDrawable colorDrawable = new ColorDrawable(ContextCompat.getColor(getContext(), R.color.primaryColor));
                • 谢谢伙计!我把它翻译成一个 Kotlin 扩展,它工作得很好。
                【解决方案13】:

                我使用下面的代码来改变分隔线,而不是直接改变颜色,但你可以用 png like this 来做到这一点。

                我给你带来的这个解决方案来自here,但是我的代码是一个简单的简化来改变分隔符,仅此而已。

                    // change divider
                    java.lang.reflect.Field[] pickerFields = NumberPicker.class
                            .getDeclaredFields();
                    for (java.lang.reflect.Field pf : pickerFields) {
                        if (pf.getName().equals("mSelectionDivider")) {
                            pf.setAccessible(true);
                            try {
                                pf.set(spindle, getResources().getDrawable(R.drawable.np_numberpicker_selection_divider_green));
                            } catch (IllegalArgumentException e) {
                                e.printStackTrace();
                            } catch (NotFoundException e) {
                                e.printStackTrace();
                            } catch (IllegalAccessException e) {
                                e.printStackTrace();
                            }
                            break;
                        }
                    }
                

                【讨论】:

                  猜你喜欢
                  • 2013-09-19
                  • 2021-03-14
                  • 1970-01-01
                  • 1970-01-01
                  • 2014-09-21
                  • 1970-01-01
                  • 1970-01-01
                  • 2016-03-06
                  • 2014-05-22
                  相关资源
                  最近更新 更多