Android Preference Fragment Text Color-ThrowExceptions

Exception or error:

I want to change the text color in android preferences fragment. I am currently using a custom theme to change the checkbox image, background, onClick highlighting and it all works great…besides the text color. I don’t want to use a default theme, I want to have my own theme so it all looks how I want to but just change the text color, can someone please help.

styles.xml

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android">
    <style name="selectedTextStyle">  
        <item name="android:textSize">18sp</item>
    </style>
    <style name="buttonTextStyle">  
        <item name="android:textSize">20sp</item>
    </style>
    <style name="PreferencesTheme" >
        <item name="android:windowBackground">@drawable/lists_background</item>
        <item name="android:listViewStyle">@style/listViewPrefs</item>
        <item name="android:checkboxStyle">@style/MyCheckbox</item>

    </style>
    <style name="MyTextAppearance" parent="@android:style/TextAppearance">
        <item name="android:textColor">@color/black</item>
      </style>
    <style name="listViewPrefs" parent="@android:Widget.ListView">
        <item name="android:listSelector">@layout/list_selector_master</item>
        <item name="android:textAppearance">@style/MyTextAppearance</item>
    </style>
    <style name="MyCheckbox" parent="android:Widget.CompoundButton.CheckBox">
        <item name="android:button">@drawable/btn_check</item>
    </style>

</resources>

Manifest:

        <activity
            android:name="com.package.SettingsActivity"
            android:theme="@style/PreferencesTheme"
            android:configChanges="keyboard|orientation" >
        </activity>

Activity:

import android.app.Activity;
import android.os.Bundle;
import android.preference.PreferenceFragment;

public class SettingsActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Display the fragment as the main content.
        getFragmentManager().beginTransaction()
                .replace(android.R.id.content, new SettingsFragment())
                .commit();

    }
    public static class SettingsFragment extends PreferenceFragment {
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);

            // Load the preferences from an XML resource
            addPreferencesFromResource(R.xml.preferences);

        }
    }

}
How to solve:

Here are the two TextView objects from preference.xml (layout for a Preference):

    <TextView android:id="@+android:id/title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:singleLine="true"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:ellipsize="marquee"
        android:fadingEdge="horizontal" />

    <TextView android:id="@+android:id/summary"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@android:id/title"
        android:layout_alignLeft="@android:id/title"
        android:textAppearance="?android:attr/textAppearanceSmall"
        android:textColor="?android:attr/textColorSecondary"
        android:maxLines="4" />

So looks like you can override textAppearanceLarge and textColorSecondary in your theme to achieve a color change. Here’s an example:

<style name="AppTheme">
    <item name="android:textAppearanceLarge">@style/MyTextAppearance</item>
    <item name="android:checkboxStyle">@style/MyCheckBox</item>
</style>

<style name="MyCheckBox" parent="@android:style/Widget.CompoundButton.CheckBox">
    <item name="android:button">@android:drawable/btn_star</item>
</style>

<style name="MyTextAppearance" parent="@android:style/TextAppearance.Large">
    <item name="android:textColor">#ff0000</item>
</style>

###

I think an easy and clear way to do that is next:

res/values/styles.xml

<style name="SettingsFragmentStyle">

    <item name="android:textColorSecondary">#222</item>
    <item name="android:textColor">#CCC</item>
    <item name="android:background">#999</item>
    ...
</style>

In the Activity that contains PreferenceFragment subclass inside onCreate:

setTheme(R.style.SettingsFragmentStyle);

###

Just found an answer that gets the job done.

This file is default layout for the preference list item:

<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2006 The Android Open Source Project

     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at

          http://www.apache.org/licenses/LICENSE-2.0

     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-->

<!-- Layout for a Preference in a PreferenceActivity. The
     Preference is able to place a specific widget for its particular
     type in the "widget_frame" layout. -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:minHeight="?android:attr/listPreferredItemHeight"
    android:gravity="center_vertical"
    android:paddingRight="?android:attr/scrollbarSize"
    android:background="?android:attr/selectableItemBackground" >

    <ImageView
        android:id="@+android:id/icon"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        />

    <RelativeLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="15dip"
        android:layout_marginRight="6dip"
        android:layout_marginTop="6dip"
        android:layout_marginBottom="6dip"
        android:layout_weight="1">

        <TextView android:id="@+android:id/title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:singleLine="true"
            android:textAppearance="?android:attr/textAppearanceLarge"
            android:ellipsize="marquee"
            android:fadingEdge="horizontal" />

        <TextView android:id="@+android:id/summary"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@android:id/title"
            android:layout_alignLeft="@android:id/title"
            android:textAppearance="?android:attr/textAppearanceSmall"
            android:textColor="?android:attr/textColorSecondary"
            android:maxLines="4" />

    </RelativeLayout>

    <!-- Preference should place its actual preference widget here. -->
    <LinearLayout android:id="@+android:id/widget_frame"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:gravity="center_vertical"
        android:orientation="vertical" />

</LinearLayout>

You can use it as base and create your own custom layout. This layout must be applied within each Preference like this

<Preference android:key="somekey" 
android:title="Title" 
android:summary="Summary" 
android:layout="@layout/custom_preference_layout"/>

You can change the whole layout outside the list, you just need to have a layout file that contains a listview where the preferences will be populated like this:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Something" />

    <ListView
        android:id="@android:id/list"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" />

</LinearLayout>

To override the default layout for the PreferenceFragment, override the method onCreateView and change the inflated view:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    return inflater.inflate(R.layout.custom_options_layout, null);
}

Based off these answers:

Creating a custom layout for preferences

How to add a button to PreferenceScreen

Android: How to adjust Margin/Padding in Preference?

###

To me nothing of the above methods didn’t work. I ended up extending Prefernces class of the kind I used, in my case CheckBoxPrefernces:

 public class MyPreferenceCheckBox extends CheckBoxPreference {

    public MyPreferenceCheckBox(Context context) {
        super(context);
    }
    public MyPreferenceCheckBox(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    public MyPreferenceCheckBox(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    protected View onCreateView(ViewGroup parent) {
        ViewGroup root = (ViewGroup) super.onCreateView(parent);
        ((TextView)root.findViewById(android.R.id.title)).setTextColor(parent.getResources().getColor(R.color.red));
        ((TextView)root.findViewById(android.R.id.summary)).setTextColor(parent.getResources().getColor(R.color.red));
        return root;
    }
}

And the use in the prefs.xml:

 <com.my.package.name.MyPreferenceCheckBox
        android:title="@string/my_title"
        android:defaultValue="true"
        android:key="@string/my_key"
        android:summary="On/Off" />

This answer showed me that path:

###

Haven’t got enough rep to comment or upvote, but I just wanted to add that mharper’s suggestion about TextAppearanceMedium also worked for me in regards to changing the text colour. If somebody knows why this is, please do explain it.

So just adjust the accepted answer like so:

<style name="AppTheme">
     <item name="android:textAppearanceMedium">@style/MyTextAppearance</item>
</style>

<style name="MyTextAppearance" parent="@android:style/TextAppearance.Medium">
     <item name="android:textColor">#ff0000</item>
</style>

At least if nobody can explain why this is, it might stop somebody having the same difficulty I did trying to change the text colour.

###

I was able to change text color in PreferenceFragment with this:

styles.xml

<resources>

    <style name="SettingsTheme" parent="android:Theme.Holo">
        <item name="android:textColorPrimary">@color/light_blue_font_color</item>
        <item name="android:textColorSecondary">@color/white_font_color</item>
        <item name="android:textColorTertiary">@color/white_font_color</item>
    </style>

</resources>

colors.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="light_blue_font_color">#33b5e5 </color>
    <color name="white_font_color">#ffffff </color>
</resources>

AndroidManifest.xml

<activity
    android:name="xx.yy.zz.SettingsActivity"
    android:theme="@style/SettingsTheme" >
</activity>

###

If you’re using compat library, just add:

<item name="colorAccent">#ff0000</item>

to your style

###

I work with min API 11 and compile whith 23.
set theme and after set background for this theme.
if you work with > API 14 you can use Theme_DeviceDefault.

This is the simplest solution I find :

public static class SettingsFragment extends PreferenceFragment {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        getActivity().setTheme(android.R.style.Theme_Holo);
        // Load the preferences from an XML resource
        addPreferencesFromResource(R.xml.settings);
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        if(view != null){
            view.setBackgroundColor(ContextCompat.getColor(getActivity(), android.R.color.background_dark));
        }
    }
}

Leave a Reply

Your email address will not be published. Required fields are marked *