The PreferenceScreen isn't good enough for me, since I've to add items to a Spinner. Those items need to come from a data list.
I've got a custom ArrayAdapter that returns the name of the item, and when I click it. It returns the data that is contained within the item.
I want to use that same ArrayAdapter in a ListPreference (that's the spinner in the PreferenceScreen) but the ListPreference doesn't allow me to use a Adapter.
So, I want to recreate the look of the PreferenceScreen (with the PreferenceCategory's) without the use of the actual PreferenceScreen (and PreferenceCategory's)
Is this possible with a library? I haven't found one.
Thanks,
Tim
I tried to collect my first method - I hope I didn't forget to include some parts (aapart color definitions or statelist drawables, which is a trivial task to make your own)
Customizing the standard Preferences
/res/xml/prefs.xml
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
>
<!-- ... -->
<PreferenceCategory android:title="@string/pref_vibrate_cat">
<CheckBoxPreference
android:persistent="true"
android:key="vibrate"
android:title="@string/pref_vibrate_title"
android:summary="@string/pref_vibrate_summ"
android:defaultValue="true"
android:layout="@layout/prefs"
/>
</PreferenceCategory>
<!-- ... -->
<!-- Just to show how to use a custom preference (you must have the corresponding java Class in your project) -->
<PreferenceCategory android:title="@string/pref_tts_cat">
<com.dergolem.abc.CLS_Prefs_Multi
android:persistent="true"
android:key="tts"
android:title="@string/pref_tts_title"
android:summary="@string/nothing"
android:dialogTitle="@string/pref_tts_dlg"
android:dialogIcon="@android:drawable/sym_action_chat"
android:entries="@array/prefs_tts_titles"
android:entryValues="@array/prefs_tts_values"
android:defaultValue="@array/prefs_tts_defaults"
android:layout="@layout/prefs"
android:widgetLayout="@layout/arr_dn"
/>
</PreferenceCategory>
<!-- ... -->
</PreferenceScreen>
/res/layout/prefs.xml
<?xml version="1.0" encoding="utf-8"?>
<!-- Layout for a visually child-like Preference in a PreferenceActivity. -->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:baselineAligned="false"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:gravity="center_vertical"
android:paddingStart="16dp"
android:paddingEnd="?android:attr/scrollbarSize"
>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:minWidth="16dp"
android:gravity="center"
android:orientation="horizontal"
>
<ImageView
android:id="@+android:id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
/>
</LinearLayout>
<RelativeLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:layout_weight="1"
>
<TextView
android:id="@+android:id/displayTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textStyle="bold"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
/>
<TextView
android:id="@+android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textStyle="bold"
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_alignStart="@android:id/title"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorSecondary"
android:shadowColor="@color/white"
android:shadowDx="1"
android:shadowDy="1"
android:shadowRadius="1"
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:minWidth="48dp"
android:gravity="center"
android:orientation="vertical"
/>
</LinearLayout>
/src/ACT_Prefs
package com.dergolem.abc;
/* ---------------------------------- Imports ------------------------------- */
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.content.res.Configuration;
import android.graphics.PixelFormat;
import android.os.Bundle;
import android.preference.PreferenceActivity;
import android.preference.PreferenceManager;
import android.widget.ListView;
public final class ACT_Prefs // NO_UCD (use default)
extends PreferenceActivity
implements OnSharedPreferenceChangeListener
{
/* ------------------------------ Objects ------------------------------- */
private Context ctx = null;
/* ----------------------------- Overrides ------------------------------ */
// Reload the Activity on rotation.
@Override
public final void onConfigurationChanged(final Configuration cfg)
{
super.onConfigurationChanged(cfg);
reStart();
}
/*
Load the Preference Activity if the API LEvel is less than 11 or else load
the PreferenceFragment.
Needed workaround, since unfortunately Google didn't include the
PreferenceFragment in the support library
*/
@Override
public final void onCreate(final Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
ctx = getApplicationContext();
if (Build.VERSION.SDK_INT < 11)
{
createPreference_Activity();
}
else
{
createPreference_Fragment();
}
}
@Override
protected void onPause()
{
// Unregister OnSharedPreferenceChangeListener
PreferenceManager.getDefaultSharedPreferences(ctx).
unregisterOnSharedPreferenceChangeListener(this);
// Call the base method
super.onPause();
}
@Override
protected void onResume()
{
// Register OnSharedPreferenceChangeListener
PreferenceManager.getDefaultSharedPreferences(ctx).
registerOnSharedPreferenceChangeListener(this);
// Fire the base method
super.onResume();
}
/* ------------------------------ Methods ------------------------------- */
@SuppressWarnings("deprecation")
private final void createPreference_Activity()
{
// Set the Activity layout
addPreferencesFromResource(R.xml.prefs);
// Get the PreferenceScreen ListView
final ListView lvw = getListView();
// Set the horizontal separator
lvw.setDivider(getResources().getDrawable(R.drawable.list_divider));
lvw.setDividerHeight((1));
// Set the statelist selector
lvw.setSelector(R.drawable.list_item_colors);
// Remove the top and bottom fadings
lvw.setVerticalFadingEdgeEnabled(false);
}
@SuppressLint("NewApi")
private final void createPreference_Fragment()
{
// Create the fragment.
getFragmentManager().beginTransaction().replace
(android.R.id.content, new FRG_Prefs()).commit();
getFragmentManager().executePendingTransactions();
}
}
/src/FRG_Prefs
package com.dergolem.abc;
/* ---------------------------------- Imports ------------------------------- */
import android.annotation.SuppressLint;
import android.graphics.PixelFormat;
import android.preference.PreferenceFragment;
import android.view.View;
import android.widget.ListView;
@SuppressLint("NewApi")
public final class FRG_Prefs
extends PreferenceFragment
{
/* ----------------------------- Overrides ------------------------------ */
@Override
public final void onResume()
{
super.onResume();
addPreferencesFromResource(R.xml.prefs);
init();
}
@Override
public final void onStop()
{
super.onStop();
// Kill the prefence screen, so that it won't be recreated DUPLICATE.
// HORRIBLE, but it's the only way to avoid the PreferenceScreen copycat.
getActivity().finish();
}
/* ------------------------------ Methods ------------------------------- */
private final void init()
{
final View v = getView();
v.setPadding(paddingSize, 0, paddingSize, 0);
// Get the PreferenceScreen ListView
final ListView lvw = (ListView) v.findViewById(android.R.id.list);
// Set the horizontal separator
lvw.setDivider(getResources().getDrawable(R.drawable.list_divider));
lvw.setDividerHeight((1));
// Set the state selector
lvw.setSelector(R.drawable.list_item_colors);
// Remove top and bottom fading
lvw.setVerticalFadingEdgeEnabled(false);
}
}
To show my Preferences:
startActivity(new Intent(ctx, ACT_Prefs.class));
ctx is defined as
Context ctx = getApplicationContext();
since I use it a lot, I define it once and for all.
[EDIT]
By request, I could add a method to make a Fake PreferenceScreen
.
The answer above is to difficult to implement, so I've designed my own version.
The layout xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:ads="http://schemas.android.com/apk/res-auto"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:minHeight="?android:attr/listPreferredItemHeight"
android:gravity="center_vertical">
<include layout="@layout/toolbar"/> <!-- This is a custom toolbar (or actionbar), and not necessary -->
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_below="@+id/toolbar"
android:paddingRight="?android:attr/scrollbarSize">
<ScrollView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_below="@layout/toolbar"
android:id="@+id/scrollView" >
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="@string/category_battery"
android:id="@+id/category_misc"
android:layout_marginLeft="@dimen/activity_settings_header_margin" />
<ImageView
android:layout_width="fill_parent"
android:layout_height="2dp"
android:id="@+id/divider"
android:layout_marginLeft="@dimen/activity_settings_margin"
android:layout_below="@+id/category_misc"
android:contentDescription="divider"
android:scaleType="matrix"
android:background="@android:drawable/divider_horizontal_bright"
android:src="@android:drawable/divider_horizontal_bright" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="@dimen/activity_settings_margin">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/textView"/>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/textView"/>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/textView"/>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/textView"/>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/textView"/>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/textView"/>
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/category_calibration"
android:textAppearance="?android:attr/textAppearanceSmall"
android:id="@+id/category_subjects"
android:layout_marginLeft="@dimen/activity_settings_header_margin"
android:layout_below="@+id/batteryChargeState" />
<ImageView
android:layout_width="fill_parent"
android:layout_height="2dp"
android:id="@+id/divider2"
android:layout_marginLeft="@dimen/activity_settings_margin"
android:layout_below="@+id/category_subjects"
android:contentDescription="divider"
android:scaleType="matrix"
android:background="@android:drawable/divider_horizontal_bright"
android:src="@android:drawable/divider_horizontal_bright" />
<LinearLayout android:layout_width="match_parent"
android:layout_below="@+id/category_subjects"
android:layout_centerVertical="true"
android:layout_height="match_parent"
android:padding="@dimen/activity_settings_margin"
android:orientation="vertical"
android:id="@+id/nextLayout">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/textView"/>
</LinearLayout>
</LinearLayout>
</ScrollView>
</RelativeLayout>
</RelativeLayout>
Toolbar xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/toolbar"
app:theme="@style/ThemeOverlay.AppCompat.ActionBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize"
android:background="?attr/colorPrimary"/>
Dimens xml:
<resources>
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
<dimen name="activity_settings_margin">24dp</dimen>
<dimen name="activity_settings_header_margin">18dp</dimen>
</resources>
Colors xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="orange">#FDA432</color>
<color name="orange_dark">#ffd17731</color>
</resources>
Just use the your way to store the Preferences. I've created a custom preference class that contains private keys so I can't post the code here without breaking it.
The advantage of using a custom layout like this is that you can add your own toolbar with this line as the first element of the first RelativeLayout.
To use the custom toolbar use this piece of code in your onCreate()
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTitle = mDrawerTitle = getTitle(); // This is for the title when you use a drawer
mToolbar = (Toolbar) findViewById(R.id.toolbar); // This finds the toolbar you've specified using the <include> in the xml
setSupportActionBar(mToolbar); // This sets the toolbar to be used
mToolbar.setBackgroundColor(getResources().getColor(R.color.orange)); // This sets the color of the toolbar
if (Build.VERSION.SDK_INT >= 21) {
getWindow().setStatusBarColor(getResources().getColor(R.color.orange_dark)); // This sets the color of the navigation bar to a darker orange as used for the toolbar, only when this is supported!
}
mToolbar.setNavigationIcon(R.mipmap.ic_launcher); // This makes the icon clickable, to open and close a drawer if you have one
}