25

Pre-API Level 14 there is no switch preference. If I use preferences.xml to create my preference screen is there some way to distinguish between the API levels? So having a check box for old releases and a switch for API 14?

What would be the best way?

AndyAndroid
  • 4,039
  • 14
  • 44
  • 71

5 Answers5

47

If I use preferences.xml to create my preference screen is there some way to distinguish between the API levels? So having a check box for old releases and a switch for API 14?

Create a res/xml-v14/ directory that contains a preferences.xml that has your SwitchPreference. Create a res/xml/ directory that contains a preferences.xml file that replaces the SwitchPreference with a CheckBoxPreference. Android will load the right preferences.xml file edition based on the device version the app is running on.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • 1
    Is there an equivalent to the "include" tag of lauout files, yet for preferences files? This way, only minimal text would be needed as the delta would be located in the v14 folder, right? – android developer Apr 06 '13 at 20:06
  • @androiddeveloper: Sorry, not that I am aware of. – CommonsWare Apr 07 '13 at 12:12
  • I've made a nice workaround of this problem, which wraps the switchPreference when possible, and use the checkbox if not possible. Can you please check it out and see if it seems ok? according to my tests, it works fine, but maybe i've missed some functionality. – android developer Apr 27 '13 at 09:59
  • @androiddeveloper: IMHO, you need to override *all* methods and route *all* of them to your `_switchPreference`, not just the ones shown. Otherwise, the other methods will work on the base `CheckBoxPreference` contents, and you could get out of sync. – CommonsWare Apr 27 '13 at 11:17
  • yes i thought so too, but i also think that since it only uses the switchPreference view in the onCreateView , it might use it all the time for a reference in the other methods. i don't really use the switchPreference, only its view. i think the rest of the implementation of android just uses the view in all of the methods, which is also indicated from the reason it works (at least in my test cases). – android developer Apr 27 '13 at 11:47
  • @androiddeveloper: It's still scary. :-) – CommonsWare Apr 27 '13 at 11:53
  • you mean dangerous? i do assume a lot, but i think that if it works, even at the basic level, people could use it, and it's also quite a short code. if there is a problem, i think it could be easy to fix it. adding multiple xml files based on version is more annoying. i hoped there is an equivalent to "include" tag as shown in layout files, but i don't think there is. – android developer Apr 27 '13 at 12:01
  • @androiddeveloper: "you mean dangerous?" -- I mean risky. You are making assumptions about the implementations of these classes, based on your reading of some source code. Not only does that source code change with Android releases, but device manufacturers tinker with this stuff as well. You are certainly welcome to use whatever you want. I'll take "annoying" over "risky" any day of the week (and twice on Sundays). – CommonsWare Apr 27 '13 at 12:03
  • so i guess the best thing is to copy the android source code for the switchPreference (if i want to avoid the multiple folders&files)? but then it won't have the same look and feel of the device, no? – android developer Apr 27 '13 at 12:12
  • @androiddeveloper: This is why I recommended making your preference be a complete facade in my initial comment on today's thread. While internal implementations may differ, the public API doesn't, except in very controlled updates. Hence, if you route *all* public methods to your contained `SwitchPreference`, rather than a subset, you are pretty much guaranteed to be safe (modulo any Android API changes that have happened -- I don't have those memorized). Leastways, I wouldn't be nearly as worried about it. – CommonsWare Apr 27 '13 at 12:20
  • i wonder if there is another solution, one that will minimize the amount of code and files and will work without any risks. – android developer Apr 27 '13 at 12:25
  • If you think Android 2.x users will recognize a `Switch` when they see one, use the backport mentioned in another answer on this question. – CommonsWare Apr 27 '13 at 12:44
  • it's the same idea i've suggested , to copy the code of android of the switchPreference, no? – android developer Apr 27 '13 at 12:47
  • @androiddeveloper: There are likely things beyond just code, like resources, to make the backport. But otherwise, yes. Usually, it's better to reuse somebody else's backport than to roll your own, though. – CommonsWare Apr 27 '13 at 13:25
  • can you think of any other possible solution? btw, the "@" in the beginning of each comment is not needed if we are the only ones that write. only if another person joins, it will matter. – android developer Apr 27 '13 at 13:31
  • Copying preference.xml from `xml` folder to `res/values-v14` give lint error *Invalid start tag PreferenceScreen*? – Muhammad Babar Oct 03 '14 at 04:46
  • @MuhammadBabar: The answer tells you to copy to `res/xml-v14/`, not `res/values-v14/`. – CommonsWare Oct 03 '14 at 10:24
17

You could also use the android-switch-backport library which has a SwitchPreference which works on Android 2.1+.

https://github.com/BoD/android-switch-backport

Intrications
  • 16,782
  • 9
  • 50
  • 50
2

There is a workaround which i'm not sure how full it is, by wrapping which view to use in the CheckBoxPreference (might miss some functions, but in general use, it works) .

The workaround will use the CheckBoxPreference for pre-API-14 and the SwitchPreference for API 14 and above.

Here's the code:

public class SwitchPreference extends CheckBoxPreference
  {
  android.preference.SwitchPreference _switchPreference =null;

  public SwitchPreference(final Context context)
    {
    super(context);
    if(VERSION.SDK_INT>=VERSION_CODES.ICE_CREAM_SANDWICH)
      _switchPreference=new android.preference.SwitchPreference(context);
    }

  public SwitchPreference(final Context context,final AttributeSet attrs)
    {
    super(context,attrs);
    if(VERSION.SDK_INT>=VERSION_CODES.ICE_CREAM_SANDWICH)
      _switchPreference=new android.preference.SwitchPreference(context,attrs);
    }

  public SwitchPreference(final Context context,final AttributeSet attrs,final int defStyle)
    {
    super(context,attrs,defStyle);
    if(VERSION.SDK_INT>=VERSION_CODES.ICE_CREAM_SANDWICH)
      _switchPreference=new android.preference.SwitchPreference(context,attrs,defStyle);
    }

  @Override
  protected View onCreateView(final ViewGroup parent)
    {
    final View view;
    if(VERSION.SDK_INT>=VERSION_CODES.ICE_CREAM_SANDWICH)
      {
      view=_switchPreference.getView(null,parent);
      // set as checked the view and the view's children, each in case it extend from Checkable
      ViewUtil.setChecked(view,isChecked());
      // set as non-clickable the view and the view's children
      ViewUtil.setClickable(view,false);
      }
    else view=super.onCreateView(parent);
    return view;
    }
android developer
  • 114,585
  • 152
  • 739
  • 1,270
  • @3c71 sorry, but you are wrong and i think you haven't tried it out. it's ok to declare any type of class even if you don't have access to it because of different API . you will get crashes only if you use the methods (including CTOR) of the class, since you don't have access to them. – android developer May 01 '13 at 07:09
  • Actually this IS a clever and working solution. Make sure the SwitchPreference is just in your own package and also the XML is not using the original SwitchP but the new one. Also, you may need to override some more methods, e.g. isChecked etc. In other words, the item works as CheckBoxPreference but looks like a SwitchPreference. – digitalfootmark Sep 11 '14 at 07:35
  • @digitalfootmark I'm not sure. Till now it worked fine for me. This is why I wrote it's not "full", as I'm not sure which functions should be added. Are you sure "isChecked" doesn't work? I mean, I even use it in this code itself... – android developer Sep 11 '14 at 11:58
1

you can use SwitchCompat:

<android.support.v7.widget.SwitchCompat
    android:id="@+id/switch_compat"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentRight="true"
    android:checked="true"
    android:textOff="OFF"
    android:textOn="ON"
    app:showText="false"
    android:focusable="false"
    android:focusableInTouchMode="false"/>

on setOnCheckedChangeListener:

SwitchCompat switchCompat = (SwitchCompat)convertView.findViewById(R.id.switch_compat);
        switchCompat.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                if (isChecked) {
                    textView.setText("check");
                } else {
                    textView.setText("unCheck");
                }
            }
        });

i hope help you.

tvtruong
  • 99
  • 1
  • 4
0

Try this code:

public class SettingsActivity extends PreferenceActivity {

    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // setContentView(R.layout.activity_settings);
        PreferenceScreen rootScreen = getPreferenceManager()
                .createPreferenceScreen(this);
        setPreferenceScreen(rootScreen);
        Preference NotifCheck=null;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
            NotifCheck = new SwitchPreference(this);

        } else {
            NotifCheck = new CheckBoxPreference(this);

        }
        NotifCheck.setKey("ShowNotification");
        NotifCheck.setTitle(R.string.ShowNotification);
        NotifCheck.setEnabled(true);
        rootScreen.addPreference(NotifCheck);
        // Show the Up button in the action bar.
        setupActionBar();
    }
}
Im0rtality
  • 3,463
  • 3
  • 31
  • 41
Vladislav
  • 1,236
  • 13
  • 22