11

So I have an Android library that I want others to be able to easily customize its color when using it. The problem is that the color is not just a single property (like the view background), but it's more like a theme color (the view background, the text color, the stroke for the button, etc...) so I'm not able to just pass it as a view attribute. So I ended up using a color reference and use it in styles, layout and drawables:

colors.xml:

<resources>
    <attr name="color" format="reference" />
</resources>

layout.xml:

<LinearLayout
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="?attr/color">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="?attr/color"/>
    <android.support.design.widget.TextInputLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:theme="@style/LibraryTheme.TextAppearance"/>
</LinearLayout>

styles.xml in library project:

<style name="LibraryTheme.TextAppearance">
    <item name="android:textColor">?attr/color</item>
    <item name="colorControlNormal">?attr/color</item>
    <item name="android:textColorHint">?attr/color</item>
    <item name="colorControlActivated">?attr/color</item>
    <item name="colorControlHighlight">?attr/color</item>
</style>

That works great, and when someone is using my lib he must declare the color he wants you use in his theme:

styles.xml in app project:

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="color">@color/my_color</item>
</style>

The problem is this: I want to deliver this library with a default color scheme. It can be performed now with 2 options:

  1. Declare my own theme with the default color sets and the user will need to inherit his theme from mine.
  2. Put some default_color in my color.xml so that the user will be able to use that as the color in his theme.

The first one is really bad, because I can't force the user to use specific app theme (like AppCompact.Light). The second one is not that great either, because I want the user to be able to use the default seamlessly and I have a couple of colors in the theme that he needs to set.

Is there any other way that you think I will be able to let other users play with the colors easily?

Thanks.

Daniel Beck
  • 20,653
  • 5
  • 38
  • 53
shem
  • 4,686
  • 2
  • 32
  • 43
  • You can check [SublimePicker](https://github.com/vikramkakkar/SublimePicker) project's [theme](https://github.com/vikramkakkar/SublimePicker/blob/master/sublimepickerlibrary/src/main/res/values/themes.xml) setup. It is quite complex since I had to provide a lot of theming options. From your categorization, this setup would fall under **1**, I think. `The first one is really bad, cause I can't force the user to use specific app theme (like AppCopact.Light)` --- No, you would be asking the user to override _your_ theme, like `parent="MyLibrarysDefaultTheme"`. This is okay. – Vikram Jan 30 '16 at 20:47
  • @Vikram looks like you used all the style attribute as single properties and just set them in the code (like `iconColor`), what if I have color in multiple places that some of them can't be set in code? – shem Jan 31 '16 at 12:52
  • 1
    What you need is control over what attributes are set, and what to do when they are not present/invalid. This control can only be afforded when you create custom components. In your specific case, you would check whether `attr/color` has been set, and if not, use a default value - at _runtime_. Another thing that you should keep in mind is that users (or rather clients) of your product will be developers - not end users. It is alright to impose a requirement if it does not take anything away from the library's core functionality. – Vikram Jan 31 '16 at 20:39

3 Answers3

9

The problem is that you are using a color reference, in your case I would use a regular color property- those can be overridden by the user in colors.xml.

So in you library project:

colors.xml:

<resources>
    <color name="color">#FFFFFF</color>
</resources>

layout.xml:

<LinearLayout
            android:orientation="vertical"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@color/color">
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textColor="@color/color"/>
            <android.support.design.widget.TextInputLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                app:theme="@style/LibraryTheme.TextAppearance"/>
</LinearLayout>

styles.xml:

<style name="LibraryTheme.TextAppearance">
    <item name="android:textColor">@color/color</item>
    <item name="colorControlNormal">@color/color</item>
    <item name="android:textColorHint">@color/color</item>
    <item name="colorControlActivated">@color/color</item>
    <item name="colorControlHighlight">@color/color</item>
</style>

And if the user wants to use different colors, he can declare his own color in his app's colors.xml:

<resources>
    <color name="color">#000000</color>
</resources>
Mati Bot
  • 797
  • 6
  • 13
  • Thank you so much, the color is kinda overriden for the one specified in the app resources file. – sgelves Oct 18 '17 at 14:59
  • I have been doing this but I got into a situation where one of my user has requirement to change the theme based on logged in user type. Now color cannot be changed in runtime. – Prashant Dec 13 '19 at 07:00
0

I am not sure If I get the point correctly but I guess you have the following option:

Declare in your Strings.xml file something like this:

<!-- Colors-->
    <color name="color1">#55000000</color>
    <color name="color2">#FFFFFF</color>
    <color name="color3">#000000</color>

And then customize your template objects passing this reference. If the user wants to change all the app colors, he needs just to set new values in String.xml

  <TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textColor="@color/color1"/>
Victor Viola
  • 575
  • 1
  • 4
  • 14
  • 1
    The TextView is in the library, so the user can't put the color there – shem Jan 21 '16 at 17:55
  • Man, I did not get you. This user that you refer is a programmer or someone with the app installed? – Victor Viola Jan 21 '16 at 18:03
  • 1
    Sorry, will try to make it more clear- the user is a programmer that want to use the library. But the only thing he needs to do is the put the in his layout (the text view and all is inside the library code) – shem Jan 21 '16 at 18:08
0

I'd stick to option 1. As a theme is only a collection of attributes, I don't see how you "force" the user to inherit your theme - he only needs to supply the list of attributes, plus he has something working to start with...

Ofer
  • 127
  • 1
  • 10