In this post, we will make Android app settings with new Style.
We use PreferenceFragmentCompat.
Why Preference fragment compact?
Because by using this we can show toolbar on settings activity easily.
Before starting to take a look at documentation
click here.
So we need a separate fragment class. Settings is an activity just like others but we implement fragment here.
Ok, that's our today goal.
Let's start.
Create an Activity name Settings Activity -
public class SettingsActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_settings);
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
}
Now set it on Manifest.XML
<activity
android:name=".settings.SettingActivity"
android:label="@string/action_settings" />
Note: don't set-
android:parentActivityName=".MainActivity"
if you set this, after pressing the back arrow button on the toolbar it's launch MainActivity again. Now add dependencies to your build.gradle file
compile 'com.android.support:preference-v7:25.3.1'
After that Create a Fragment Class Name SettingFragment.java and extend it to PreferenceFragmentCompat and implements. SharedPreferences.OnSharedPreferenceChangeListener Let me Show-
public class SettingsFragment extends PreferenceFragmentCompat implements
SharedPreferences.OnSharedPreferenceChangeListener{
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
}
Now add a method on this class name setPreferenceSummery. If we use ListPreference then we set to list selected value. for doing this, add this code-
private void setPreferenceSummery(Preference preference,Object value){
String stringValue = value.toString();
if (preference instanceof ListPreference){
// For list preferences, look up the correct display value in
// the preference's 'entries' list (since they have separate labels/values).
ListPreference listPreference = (ListPreference) preference;
int prefIndex = listPreference.findIndexOfValue(stringValue);
//same code in one line
//int prefIndex = ((ListPreference) preference).findIndexOfValue(value);
//prefIndex must be is equal or garter than zero because
//array count as 0 to ....
if (prefIndex >= 0){
listPreference.setSummary(listPreference.getEntries()[prefIndex]);
}
} else {
// For other preferences, set the summary to the value's simple string representation.
preference.setSummary(stringValue);
}
}
Note: For understanding code, you see comment on the code.
Now time the fulfill the methods onCreatePreferences.
In this methods, we add our XML file for settings option. But we don't create yet. So it's show error status. But don't worry we will add this later. Code-
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
// Add 'general' preferences, defined in the XML file
addPreferencesFromResource(R.xml.pref_general);
SharedPreferences sharedPreferences = getPreferenceScreen().getSharedPreferences();
PreferenceScreen preferenceScreen = getPreferenceScreen();
int count = preferenceScreen.getPreferenceCount();
for (int i = 0; i < count ; i++) {
Preference p = preferenceScreen.getPreference(i);
if (!(p instanceof CheckBoxPreference)) {
String value = sharedPreferences.getString(p.getKey(), "");
setPreferenceSummery(p, value);
}
}
}
Now time to work with onSharedPreferenceChanged-
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
Preference preference = findPreference(key);
if (preference != null) {
if (!(preference instanceof CheckBoxPreference)) {
String value = sharedPreferences.getString(preference.getKey(), "");
setPreferenceSummery(preference, value);
}
}
}
Optional code:
if you want to use the content provider to access database then you set a notification for change value-
Activity activity = getActivity();
activity.getContentResolver().notifyChange(CONTENT_URI, null);
After doing that we should register and unregister the shared preference listener with activity life cycle.
Let's do this-
//register and unregister on lifecycle
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getPreferenceScreen().getSharedPreferences()
.registerOnSharedPreferenceChangeListener(this);
}
@Override
public void onDestroy() {
super.onDestroy();
getPreferenceScreen().getSharedPreferences()
.unregisterOnSharedPreferenceChangeListener(this);
}
ok. our fragment is ready to use.(don't worry about the error, we will fix this letter, for now just ignore it.)
Now we add the toolbar back arrow code.
so that it's come back the previous activity. For more details use code comment-
@Override
public boolean onOptionsItemSelected(MenuItem item) {
/*
* Normally, calling setDisplayHomeAsUpEnabled(true)
* (we do so in onCreate here) as well as
* declaring the parent activity in the
* AndroidManifest is all that is required to get the
* up button working properly. However, in this case,
* we want to navigate to the previous
* screen the user came from when the up
* button was clicked, rather than a single
* designated Activity in the Manifest.
*
* We use the up button's ID (android.R.id.home)
* to listen for when the up button is
* clicked and then call onBackPressed
* to navigate to the previous Activity when this happens.
*/
int id = item.getItemId();
if (id == android.R.id.home){
NavUtils.navigateUpFromSameTask(this);
}
return super.onOptionsItemSelected(item);
}
Now in this part, we create XML code.
Are you tired of seeing the error?
Now time to fix it. we create an XML file name pref_general.xml.
Let's add-
In our settings screen, we just add two preference,
- List Preference,
- Checkbox preference.
our list preference for text size. so we need to create two arrays on
arrays.XML one is for label and others is for value. but we need to add string first (I provide all string for both preferences).
Strings-
<!-- for settings -->
<!-- ***************START************* -->
<!-- text size -->
<string name="sTextSmallLabel">Small</string>
<string name="sTextMediumLabel">Medium</string>
<string name="sTextModerateLabel">Moderate</string>
<string name="sTextLargeLabel">Large</string>
<string name="sTextExtraLargeLabel">Extra Large</string>
<!-- text size value-->
<string name="sTextSmallValue">15</string>
<string name="sTextMediumValue">17</string>
<string name="sTextModerateValue">20</string>
<string name="sTextLargeValue">23</string>
<string name="sTextExtraLargeValue">26</string>
<string name="textSizeKey" translatable="false">textSize</string>
<string name="textSizeLabel">Text Size</string>
<string name="switchKey">SwitchKey</string>
<string name="switchLabel">Night Mode</string>
<string name="switchON">Night Mode ON</string>
<string name="switchOFF">Night Mode OFF</string>
<!-- ***************FINISH************* -->
Now add arrays-
<resources>
<string-array name="textSizeLabel">
<item>@string/sTextSmallLabel</item>
<item>@string/sTextMediumLabel</item>
<item>@string/sTextModerateLabel</item>
<item>@string/sTextLargeLabel</item>
<item>@string/sTextExtraLargeLabel</item>
</string-array>
<string-array name="textSizeValue">
<item>@string/sTextSmallValue</item>
<item>@string/sTextMediumValue</item>
<item>@string/sTextModerateValue</item>
<item>@string/sTextLargeValue</item>
<item>@string/sTextExtraLargeValue</item>
</string-array>
</resources>
Note my full arrays.xml. Ok, that's enough waiting now add
pref_general.xml
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListPreference
android:defaultValue="@string/sTextModerateValue"
android:entries="@array/textSizeLabel"
android:entryValues="@array/textSizeValue"
android:key="@string/textSizeKey"
android:title="@string/textSizeLabel"/>
<CheckBoxPreference
android:defaultValue="false"
android:key="@string/switchKey"
android:summaryOff="@string/switchOFF"
android:summaryOn="@string/switchON"
android:title="@string/switchLabel"/>
</PreferenceScreen>
Just one more work to do left to complete Settings-
we need to update activity_settings. we need to set a fragment to on this XML file. Let's add this and this fragment will show our new settings in the settings.
<fragment
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/weather_settings_fragment"
android:name="packageName.settings.SettingFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
Ok, that's . we finish our settings.
oh! I just forget to change the theme of
styles.XML. Let's add on your main app theme.
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.DayNight.DarkActionBar">
<!-- must add this line or app will crash -->
<item name="preferenceTheme">@style/PreferenceThemeOverlay</item>
</style>
Note: if you don't add this line your app will crash. Be careful. Now you launch this
SettingsActivity.java class with intent from your desired class.
See-
It is single preference screen app. But If you want to add multiple screens, follow this post-
Android Settings Series
That's all today.
Hope you can use this option for your app.
Happy coding