Styling SeekBarPreference to be consistent with SwitchPreference
Asked Answered
F

2

7

I have the following preferences in my preferences.xml:

<SwitchPreference
    android:summary="Lorum ipsum dolor sit amet"
    android:title="Frobulate" />
<SeekBarPreference android:title="Marglins"/>
<SwitchPreference android:title="Bromzuling" />

The problem with this is that this renders Marglins with a very different style as the titles of the SwitchPreferences:

1]

Is there something I can put in my styles.xml to make the titles look the same in font size, color, alignment etc.?

Forras answered 5/7, 2018 at 14:56 Comment(2)
Check this and thisInhere
I'm going to shamelessly plug my library where all the half-baked stuff should work out of the box.Obtrusive
R
4

In your theme, try setting

<item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>

In my mock-up, this shows the following:

enter image description here

This is using com.android.support:preference-v7:27.1.1. Since this is the look that you are looking for, use this library if you can.

Make sure that you are consistently using the preference support library and not mixing things up; otherwise, things make not look/work as expected.

Here is a small app that demonstrates styling of the SeekBar preference. The app doesn't really do anything other than display the preferences. This app show the same display as shown above.

AndroidManifest.xml
Nothing fancy here.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.preferencecustomlayout">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name="com.example.preferencecustomlayout.MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

styles.xml

<resources>
        <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
            <item name="colorPrimary">@color/colorPrimary</item>
            <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
            <item name="colorAccent">@color/colorAccent</item>
            <!-- Theme for the preferences -->
            <item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>
        </style>
    </resources>

app_preferences.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">

    <android.support.v7.preference.SwitchPreferenceCompat
        android:key="switchPreference1"
        android:summary="Lorum ipsum dolor sit amet"
        android:title="Frobulate" />

    <android.support.v7.preference.SeekBarPreference
        android:key="seekBarPreference"
        android:title="Marglins" />

    <android.support.v7.preference.SwitchPreferenceCompat
        android:key="switchPreference1"
        android:title="Bromzuling" />

</android.support.v7.preference.PreferenceScreen>

MainActivity.java
Notice all the "v7" imports at the top. Don't let these get away. If things aren't working, check that you are still using the support library.

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.preference.PreferenceFragmentCompat;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if (savedInstanceState == null) {
            Fragment preferenceFragment = new PrefsFragment();
            FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
            ft.add(R.id.prefContainer, preferenceFragment);
            ft.commit();
        }
    }

    public static class PrefsFragment extends PreferenceFragmentCompat {

        @Override
        public void onCreatePreferences(Bundle bundle, String s) {
            addPreferencesFromResource(R.xml.app_preferences);
        }
    }
}

activity_main.xml
Just a home for the preference fragment.

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/prefContainer"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.preferencecustomlayout.MainActivity" />

As for eliminating the numeric display from the seekbar, that is going to be a little more involved. According to the SeekBarPreference documentation:

The seekbar value view can be shown or disabled by setting showSeekBarValue attribute to true or false, respectively.

Unfortunately, setting this value in the app_preferences.xml file gives an "is private" error. There is also no public method, that I have seen, to set the internal variable that controls this. You could subclass SeekBarPreference, override onBindViewHolder() as follows:

MySeekBarPreference.java

import android.content.Context;
import android.support.v7.preference.PreferenceViewHolder;
import android.support.v7.preference.SeekBarPreference;
import android.util.AttributeSet;
import android.view.View;
import android.widget.TextView;


public class MySeekBarPreference extends SeekBarPreference {
    public MySeekBarPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    public MySeekBarPreference(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public MySeekBarPreference(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public MySeekBarPreference(Context context) {
        super(context);
    }

    @Override
    public void onBindViewHolder(PreferenceViewHolder view) {
        super.onBindViewHolder(view);
        TextView seekBarValueTextView = (TextView) view.findViewById(R.id.seekbar_value);
        seekBarValueTextView.setVisibility(View.GONE);
    }
}

The above custom seek bar preference class will just get rid of the seek bar value. Change the seek bar definition in app_preferences.xml to:

<com.example.preferencestyleseekbar.MySeekBarPreference
    android:key="seekBarPreference"
    android:title="Marglins" />

and you will see that the value is no longer shown.

Preferences are generally a mess. I have found a very good series of articles by Jakob Ulbrich regarding preferences and getting them to work and look like material design. You may find it helpful to check them out.

Reger answered 2/8, 2018 at 22:26 Comment(2)
Currently it doesn't show a numeric value, only a slider, and I'd like to keep it that way; is that possible with this theme you recommend?Forras
I tried adding the preferenceTheme item to the style that is specified in my manifest for the preference activity, and it doesn't seem to change anything. Can you show a styles.xml and AndroidManifest.xml fragment showing how it should all hang together?Forras
R
0

For me, the solution was to use com.android.support:preference-v14 instead of v7. This allowed me to use PreferenceThemeOverlay.v14.Material, which otherwise was not accessible.

Realpolitik answered 11/8, 2018 at 10:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.