Switch in multiple custom preference layouts - android

I have a settings activity, HomeActivity, that is loaded on startup. The launch mode is set to singleTask, due to certain requirements, In the layout of the HomeActivity there is an element with a icon, title and a switch. The idea is that you should be able to enable/disable Call, using the switch. And if you click the row (outside the switch) you are brought to a new activity, CallPreferences, where you can set Call specific settings. At the action bar of CallPreferences a switch should also be present where the user again can enable/disable call. Switches on both activites should reflect the "reality". That is, when the switch is changed, the value is stored to shared prefs. Both switches then read from shared prefs onCreate to set their value to on or off.
In the xml of HomeActivity I have a preference screen that looks like this:
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:foo="http://schemas.android.com/apk/lib/com.xxx.yy" >
<com.xxx.yy.preferences.IconSwitchPreference
foo:icon="#drawable/call_icn"
android:title="#string/call"
android:key="callIconSwitchPreference" >
<intent
android:action="android.intent.action.VIEW"
android:targetClass="com.xxx.yy.preferences.CallPreferences"
android:targetPackage="om.xxx.yy" />
</com.xxx.yy.preferences.IconSwitchPreference>
</PreferenceScreen>
IconSwitchPreference is a custom preference layout of mine containing a linear layout, a text view for the title, an image view and a switch:
<?xml version="1.0" encoding="utf-8"?>
<!-- Layout for a Preference in a PreferenceActivity. -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:gravity="center_vertical"
android:paddingRight="?android:attr/scrollbarSize">
<Switch
android:id="#+id/menu_switch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:focusable="false"
android:focusableInTouchMode="false"
android:onClick="onMenuSwitchClicked" />
</LinearLayout>
And the class that runs the code:
public class IconSwitchPreference extends IconPreference {
public IconSwitchPreference(Context context) {
this(context, null);
}
public IconSwitchPreference(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public IconSwitchPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setLayoutResource(R.layout.preference_icon_switch);
if (attrs != null) {
int iconResId = attrs.getAttributeResourceValue(XMLNS, "icon", 0);
mIcon = context.getResources().getDrawable(iconResId);
mFilter = attrs.getAttributeValue(XMLNS, "filter");
mUrl = attrs.getAttributeValue(XMLNS, "url");
}
}
}
In CallPreferences I programmatically create the switch and add it to the action bar:
private void createActionBarSwitch() {
ActionBar actionBar = getActionBar();
Switch actionBarSwitch = new Switch(this);
actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM,
ActionBar.DISPLAY_SHOW_CUSTOM);
actionBar.setCustomView(actionBarSwitch, new ActionBar.LayoutParams(
ActionBar.LayoutParams.WRAP_CONTENT,
ActionBar.LayoutParams.WRAP_CONTENT, Gravity.CENTER_VERTICAL
| Gravity.RIGHT));
actionBarSwitch.setChecked(isSwitchOn());
}
This works and I can set the switch to the stored value, and the switch is updated to reflect the value.
In HomeActivity however the switch is not updated to reflect the value.
The following does not work:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LayoutInflater inflater = getLayoutInflater();
View view = inflater.inflate(R.layout.preference_icon_switch, null);
TextView tv = (TextView)view.findViewById(android.R.id.title);
tv.setText("Test");
Switch menuSwitch = (Switch)view.findViewById(R.id.menu_switch);
menuSwitch.setChecked(sharedPrefs.isCallhandlingEnabled());
}
Neither is the text view changed to test, nor is the switch enabled (default value is false).
The following however works:
final IconSwitchPreference ic = (IconSwitchPreference) findPreference("callIconSwitchPreference");
ic.setTitle("Test");
The title is set to "Test". The only problem is that I don't have any reference to the switch, so I can update it's value. Can IconSwitchPreference.java be updated to extract and store a reference to the switch in its used xml?
I've tried a number of solutions and code samples; but all of them have something that is not working. Another solution would be to use a standard SwitchPreference, but it doesn't differ between a click on the switch itself to change its state (without going to the new activity) and a click on the row to enter the activity (without changing the switch value).

Solved the issue by adding the following tag to the HomeActivity xml:
foo:switchPref="#string/call_enabled_pref_key"
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:foo="http://schemas.android.com/apk/lib/com.xxx.yy" >
<com.xxx.yy.preferences.IconSwitchPreference
foo:icon="#drawable/call_icn"
android:title="#string/call"
android:key="callIconSwitchPreference"
foo:switchPref="#string/call_enabled_pref_key" >
<intent
android:action="android.intent.action.VIEW"
android:targetClass="com.xxx.yy.preferences.CallPreferences"
android:targetPackage="om.xxx.yy" />
</com.xxx.yy.preferences.IconSwitchPreference>
</PreferenceScreen>
And then in IconSwitchPreference.java I extract the res id:
mSwitchPrefResId = attrs.getAttributeResourceValue(XMLNS, "switchPref", 0);
public IconSwitchPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setLayoutResource(R.layout.preference_icon_switch);
if (attrs != null) {
int iconResId = attrs.getAttributeResourceValue(XMLNS, "icon", 0);
mIcon = context.getResources().getDrawable(iconResId);
mFilter = attrs.getAttributeValue(XMLNS, "filter");
mUrl = attrs.getAttributeValue(XMLNS, "url");
mSwitchPrefResId = attrs.getAttributeResourceValue(XMLNS, "switchPref", 0);
}
}
}
onBindView in the same class (IconSwitchPreference.java) I got a reference to the Switch:
#Override
public void onBindView(View view) {
super.onBindView(view);
mSwitch = (Switch) view.findViewById(R.id.menu_switch);
updateSwitch();
}
Then I used mSwitchPrefResId to fetch the shared prefs (to know if the switch is enabled or not) and set mSwitch to the corresponding value.

Related

Android EditText in merge layout cascade copying issue

to speed up the development of an App I created this editText with a label attached.
This is the class:
public class EditTextWithLabel extends LinearLayout {
#InjectView(R.id.text_edittext_with_label)
protected TextView label;
#InjectView(R.id.edittext_edittext_with_label)
protected EditText editText;
public EditTextWithLabel(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
getAttributes(context, attrs);
}
...
private void init(Context context) {
LayoutInflater.from(context).inflate(R.layout.layout_edittext_with_label, this, true);
ButterKnife.inject(this);
setOrientation(VERTICAL);
}
private void getAttributes(Context context, AttributeSet attrs) {
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.EditTextWithLabel, 0, 0);
try {
CharSequence label = a.getText(R.styleable.EditTextWithLabel_label);
if (!TextUtils.isEmpty(label))
setLabel(label);
CharSequence text = a.getText(R.styleable.EditTextWithLabel_android_text);
if (!TextUtils.isEmpty(text))
setText(text);
CharSequence hint = a.getText(R.styleable.EditTextWithLabel_android_hint);
if (!TextUtils.isEmpty(hint))
setHint(hint);
int maxLength = a.getInt(R.styleable.EditTextWithLabel_android_maxLength, -1);
if (maxLength > 0)
setMaxLength(maxLength);
int type = a.getInt(R.styleable.EditTextWithLabel_android_inputType, InputType.TYPE_CLASS_TEXT);
setInputType(type);
} finally {
a.recycle();
}
}
...
}
And this is xml:
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<TextView
android:id="#+id/text_edittext_with_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="#dimen/edit_text_radius"
android:paddingBottom="5dp"
android:text="#string/username"
android:textColor="#color/text"
android:textSize="#dimen/text_edit_text"
/>
<EditText
android:id="#+id/edittext_edittext_with_label"
style="#style/EditText"
android:inputType="textEmailAddress"/>
</merge>
I found out that if I put more of these in a fragment, when I restore it ALL the editTexts show the text that is wrote in the last one.
I cannot explain this behavior, so I hope that somebody could enlight me.
Thank you
EDIT
Thanks to J. Dow answer I was able to solve the issue, I've added at the end of the init method this code:
label.setId((int) System.currentTimeMillis());
editText.setId((int) System.currentTimeMillis());
This randomized the ids enough to avoid the issue.
What merge is doing is basically a simple include. So your final Layout will include multiple "copies" of your EditText.
From the Android documentation:
Note: In order for the Android system to restore the state of the views in our activity, each view must have a unique ID, supplied by the android:id attribute.
http://developer.android.com/training/basics/activity-lifecycle/recreating.html
Thus, when restoring your merged layout, the Android system will encounter multiple EditTexts with the same id and therefore restore each of them with the same state.

android custom preference does not update in response to events

I have a preferences screen with on checkbox header. In response to it being checked other preferences in that screen are enabled or disabled.
One of these preferences should also change it's icon and text as well as the disabled state.
I can change the state, but the icon and text won't update.
xml layout for the custom preference:
<?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="wrap_content"
android:gravity="center_vertical"
android:minHeight="?android:attr/listPreferredItemHeight"
android:paddingRight="?android:attr/scrollbarSize" >
<ImageView
android:id="#+id/icon_wearable"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:paddingRight="5dp"
android:src="#drawable/wear_notifications_enabled" />
<TextView
android:id="#+id/txt_wearable_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="7"
android:text="#string/notifications_enabled_wearable_preferences_title"
/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:src="#drawable/actionbar_info" />
</LinearLayout>
There are image and text resources for the disabled state.
The Preference class (comments in the code show the evolution and of my attempts to get it to work):
public class WearablePreference extends Preference {
private TextView txt;
private ImageView img;
public WearablePreference(Context context, AttributeSet attrs) {
super(context, attrs);
setLayoutResource(R.layout.wearable_notification_layout);
// setWidgetLayoutResource(R.layout.wearable_notification_layout);
}
public WearablePreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setLayoutResource(R.layout.wearable_notification_layout);
// setWidgetLayoutResource(R.layout.wearable_notification_layout);
}
public WearablePreference(Context context) {
super(context);
setLayoutResource(R.layout.wearable_notification_layout);
// setWidgetLayoutResource(R.layout.wearable_notification_layout);
}
#Override
protected void onBindView(View view) {
super.onBindView(view);
if (txt == null && img == null) {
txt = (TextView) view.findViewById(R.id.txt_wearable_title);
img = (ImageView) view.findViewById(R.id.icon_wearable);
handleStateChange();
}
}
public void handleStateChange() {
final boolean enabled = super.isEnabled();
if (txt != null && img != null) {
txt.post(new Runnable() {//also tried it not as a separate runnable since the click event is caught and handled in the main thread anyway, but still worth the try...
public void run() {
int imgResource = enabled ? R.drawable.wear_notifications_enabled
: R.drawable.wear_notifications_disabled;
int txtResource = enabled ? R.string.notifications_enabled_wearable_preferences_title
: R.string.notifications_disabled_wearable_preferences_title;
txt.setText(txtResource);
img.setImageResource(imgResource);
notifyChanged();
}
});
}
}
#Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
// handleStateChange();
}
}
and finally the code that should have made this happen:
// Load the preferences from an XML resource
addPreferencesFromResource(R.xml.notification_preferences);
wearableNotificationPreferences = (WearablePreference) findPreference(PREFERENCE_WEARABLE);
private void toggleAllItems(boolean enabled)
{
if (wearableNotificationPreferences!=null) {
wearableNotificationPreferences.setEnabled(enabled);
wearableNotificationPreferences.handleStateChange();
}
}
In the last bit of code, the enabled state change happens, but that's it. The icon and text won't change.
I can't use preferences change listeners, as there is no preference change on my particular item, though I'm considering adding a stub preference just so I can get it to work.
Does anyone know why the text and icon won't update and/or what I can do to get them to change?
Thanks,
Omer.
I managed to solve it.
I removed all the event handling code, added a boolean preference entry with the preference key, and I set the value inside the "onBindView" method.
If anyone is interested, here's the code (important changes enclosed in '**'):
#Override
protected void onBindView(View view) {
super.onBindView(view);
// if (txt == null && img == null) {
txt = (TextView) view.findViewById(R.id.txt_wearable_title);
img = (ImageView) view.findViewById(R.id.icon_wearable);
**boolean enabled=MyApp.getPrefs().getUserPref(getKey(), true);**
int imgResource = enabled ? R.drawable.wear_notifications_enabled
: R.drawable.wear_notifications_disabled;
int txtResource = enabled ? R.string.notifications_enabled_wearable_preferences_title
: R.string.notifications_disabled_wearable_preferences_title;
txt.setText(txtResource);
img.setImageResource(imgResource);
}
#Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
**MyApp.getPrefs().setUserPref(enabled, getKey());**
}

android custom Switch widget for SwitchPreferenc

I search around stackoverflow and find next related topics:
How can i style an Android Switch?
Custom switch widget in Android 4
Set switchStyle - get error resource not found - why?
I also find bugreport on google group: Issue 36636: Unable to override style switchStyle
And at last find new probles with Switch widget:
I tried to make my own Preference.SwitchPreference and define layout with Switch widget
android:id="#+android:id/switchWidget"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:thumb="#drawable/switch_thumb"
android:layout_gravity="center"
android:padding="16dip"
android:focusable="false" />
but I get an compliation error: Error: Resource is not public. (at 'id' with value '#+android:id/switchWidget'). So I can't use this way.
Second way I tried to extend Switch class add set resources from code. But I find that method setThumbResource is availible only from API 16. But I still can't apply #+android:id/switchWidget because it's not public.
So, How can I get custom Switch Preference for SDK API 15 ??? Or how can I customize Switch in Preferences?
Just found an awful way to achieve this.
First, src/com/myapp/views/preference/MySwitchPreference.java
public class MySwitchPreference extends SwitchPreference {
public MySwitchPreference(Context context) {
super(context);
}
public MySwitchPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MySwitchPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onBindView(View view) {
super.onBindView(view);
if (view instanceof ViewGroup) {
setLayout((ViewGroup) view);
}
}
#SuppressLint("NewApi")
private void setLayout(ViewGroup viewGroup) {
int count = viewGroup.getChildCount();
for(int n = 0; n < count; ++n) {
View childView = viewGroup.getChildAt(n);
if(childView instanceof Switch) {
final Switch switchView = (Switch) childView;
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
switchView.setThumbResource(com.myapp.R.drawable.switch_inner);
switchView.setTrackResource(com.myapp.R.drawable.switch_track);
}
return;
}
else if (childView instanceof ViewGroup)
setLayout((ViewGroup) childView);
}
}
}
And now, res/xml/preferences.xml
<com.myapp.views.preference.MySwitchPreference
android:switchTextOff="Off"
android:switchTextOn="On"
android:title="whatever"
android:key="switch" />
A little bit tricky, and only working with Android > 16.
Don't know much about the switch issues but you could use a ToggleButton as follows:
Define the button in your layout:
<ToggleButton
android:id="#+id/your_awesome_toggle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:gravity="center_vertical|center_horizontal"
android:layout_marginRight="15dp"
android:textOn=""
android:textOff=""
android:background="#drawable/toggle_button"
/>
Create a selector:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:state_checked="false"
android:state_focused="false"
android:drawable="#drawable/switch_off_btn" />
<item
android:state_checked="true"
android:state_focused="false"
android:drawable="#drawable/switch_on_btn" />
<item
android:drawable="#drawable/switch_off_btn" />
</selector>
OnClickListener:
toggleOnOff = (ToggleButton) findViewById(R.id.your_awesome_toggle);
toggleOnOff.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
updateButtons();
if(toggleOnOff.isChecked()){
SharedPreferences emailPrefs = getSharedPreferences(rememberToggleOnOff,MODE_PRIVATE);
SharedPreferences.Editor editor = yourPrefs.edit();
editor.putBoolean("mon", true);
editor.commit();
}
else {
SharedPreferences emailPrefs = getSharedPreferences(rememberToggleOnOff,MODE_PRIVATE);
SharedPreferences.Editor editor = yourPrefs.edit();
editor.putBoolean("mon", false);
editor.commit();
}
}
});
checkToggleState();
checkToggleState method:
/**
* Checks the state of the Toggle button preferences.
* If preferences are true set the toggle to on, if false set the toggle off.
*
*/
private void checkToggleState() {
SharedPreferences yourPrefs = getSharedPreferences(rememberToggleOnOff,MODE_PRIVATE);
boolean mON = yourPrefs.getBoolean("mon", true);
if(mON) {
toggleOnOff.setChecked(true);
}
else {
toggleOnOff.setChecked(false);
}
}
Change:
android:id="#+android:id/switchWidget"
To:
android:id="#+id/switchWidget"
A simple switch example can be found here.
Switch widget supports 14 and above API level only, but if you want to use Switch Preference pre API level 14, check this.
UPDATE: If you want to style your own switch, try this
Inherit SwitchPreference class and use it in preferences.xml with layout pointing to your custom layout. Then in the onBind method of inherited SwitchPreference class you can find corresponding view by id and set listeners. Don't forget to call super in onBind().
Change:
android:id="#+android:id/switchWidget"
To:
android:id="#*android:id/switchWidget"

Save state on screen rotate when a compound component is used multiple times

I'm facing a problem where I know the root cause but don't see a way to fix it. If a custom compound component is used multiple times in an activity, the values saved from views will overwrite each other. To explain it easier I made the following example.
The xml for the new component, only an EditText to make it shorter.
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android" >
<EditText
android:id="#+id/custom_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="number" >
</EditText>
</merge>
The class implementing the new behavior, only inflating the layout.
public class CustomView extends LinearLayout {
public CustomView(Context context) {
this(context, null);
}
public CustomView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.custom_view, this, true);
}
}
And a layout using 2 of them.
<?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" >
<test.customview.CustomView
android:id="#+id/customView1"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
</test.customview.CustomView>
<test.customview.CustomView
android:id="#+id/customView2"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
</test.customview.CustomView>
</LinearLayout>
When the screen is rotated, the value from second View is also restored in the first one.
Digging into the framework's code I found out that Parcelable objects returned from onSaveInstanceState defined in View class are put in a SparseArray with the key object's id. Because I'm including CustomView multiple times the EditText with id "custom_text" is also getting added multiple times. Having the same id, values saved will overwrite each other.
I'm looking for any suggestion on how this should be actually implemented. Right now, I don't see any way to change those identifiers.
Seems like I have some solution with this problem. I try to find it for some time.
1.First you must create inner class which extends BaseSavedState, inside your CustomView.
CustomView{
String value; //some text value from edittext
EditText edittext;
...
private static class Save extends BaseSavedState{
String savedValue;
public Save(Parcel incoming) {
super(incoming);
savedValue = incoming.readString();
Log.i("Save", "Parcel");
}
public Save(Parcelable parcelable) {
super(parcelable);
Log.i("Save", "Parcelable");
}
#Override
public void writeToParcel(Parcel outcoming, int flags) {
super.writeToParcel(outcoming, flags);
outcoming.writeString(savedValue );
Log.i("Save", "writeToParcel");
}
public static final Parcelable.Creator<Save> CREATOR =
new Creator<CustomView.Save>() {
#Override
public Save[] newArray(int size) {
Log.i("Parcelable.Creator<Save>", "newArray");
return new Save[size];
}
#Override
public Save createFromParcel(Parcel incoming) {
Log.i("Parcelable.Creator<Save>", "createFromParcel");
return new Save(incoming);
}
};
}
}
2.then override this two methods in CustomView
CustomView{
String value; //some text value from edittext
EditText edittext;
...
#Override
protected Parcelable onSaveInstanceState() {
Log.i("CustomView", "onSaveInstanceState");
Parcelable p = super.onSaveInstanceState();
Save save = new Save(p);
save.savedValue = value; // value is from CustomView class
return save;
}
#Override
protected void onRestoreInstanceState(Parcelable state) {
Log.i("CustomView", "onRestoreInstanceState");
if(!(state instanceof Save)){
super.onRestoreInstanceState(state);
return;
}
Save save = (Save) state;
value = save.savedValue;
//setting in this place value to edittext will not do anything.
//instead, you have to do this in step 3
super.onRestoreInstanceState(save.getSuperState());
}
...
}
3.override onAttachedToWindow() and set to edittext "value".
CustomView{
String value; //some text value from edittext
EditText edittext;
...
#Override
protected void onAttachedToWindow() {
edittext.setText(value);
super.onAttachedToWindow();
}
...
}
and now you can have multiple instances of your Custom View 's that are resistant to change orientation - they will have the correct values.I have not tested this solution in 100% but it seems to be good.

Android preferences summary default color?

I have installed my app in a real phone, and even though in the emulator all the texts of the
preferences summaries seem to be in the same color, in the real phone the color is different (some kind of blue... but I guess it depends on the phone's model).
How can I set this color to my custom preference component?
(I have implemented my own seek bar, and its summary text color is different from all the other components text color...).
Thanks!
Preference pUpdate = findPreference("sys_setting_update");
pUpdate.setSummary(Html.fromHtml("<font color=\"#B0C4DE\">This is content</font>"));
use Html.fromHtml("<font color=\"#B0C4DE\">This is content</font>") to setSummary
I found these: android:textAppearance="?android:attr/textAppearanceLarge"
and android:textAppearance="?android:attr/textAppearanceSmall"
seem to do the trick.
I have figured out a way to retrieve the default color used by the Android device your application is running in. It is a bit tricky and requieres that you retrieve the color being shown from another Preference Summary View of your activity and store it in runtime.
Then you can use the same color code in other Views of other preferences, assuring that you will allways get the same color code Android assigned to the standard preferences. Here is how I did it:
My preferences activity has a normal CheckBoxPreference that I use to activate or deactivate a service. I have extended CheckBoxPreference as follows, so my extension retrieves in rutime the default color Android finally gave to the summary of that CheckBoxPreference:
public class MyCheckBoxPreference extends android.preference.CheckBoxPreference {
private static int sSummaryColor = Color.WHITE;
private static boolean sInitialized = false;
public MyCheckBoxPreference(Context context) {
super(context);
}
public MyCheckBoxPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyCheckBoxPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
public void onBindView(View view) {
super.onBindView(view);
if (!sInitialized) {
sSummaryColor = getSummaryColor(view);
sInitialized = true;
}
}
private int getSummaryColor(View view) {
int color = Color.WHITE;
// Gets the color android gave to the summary by default
TextView summaryView = (TextView) view.findViewById(android.R.id.summary);
if (summaryView != null) {
ColorStateList list = summaryView.getTextColors();
if (list != null) {
color = list.getDefaultColor();
}
}
return color;
}
public static int getSummaryColor() {
return sSummaryColor;
}
}
In my preferences.xml I instantiate that preference as MyCheckBoxPreference instead of just CheckBoxPreference:
<org.yourpackage.MyCheckBoxPreference
android:title="#string/preference_title_activate"
android:defaultValue="false"
android:summary="#string/preference_summary_activate_off"
android:summaryOff="#string/preference_summary_activate_off"
android:key="preference_activate">
</org.yourpackage.MyCheckBoxPreference>
The MyCheckBoxPreference has to be instantiated once before retrieving the summary color with MyCheckBoxPreference.getSummaryColor().
Now you can set the color of other customized preferences from onBindView(View):
public class MyCustmizedPreference extends Preference {
public MyCustmizedPreference (Context context) {
super(context);
setLayoutResource(R.layout.my_customized_preference);
}
#Override
public void onBindView(View view) {
super.onBindView(view);
TextView summaryView = (TextView) view.findViewById(android.R.id.summary);
if (summaryView != null) {
summaryView.setTextColor(MyCheckBoxPreference.getSummaryColor());
}
}
}
It actually works under Samsung Galaxy S. I have also tested that it doesn't break anything under the emulator.
The Samsung Galaxy S phones have their own Preference layout with the text color specified for the Summary line. Even though a TextAppearance.Small is specified the textColor attribute of the layout is overriding the text appearance.
I don't think this is possible. I am able to change the background color and the title text color, but not the summary color.
Background:
getListView().setBackgroundColor(Color.TRANSPARENT);
Title text:
Preference yourpreference = findPreference("yourpreference");
TextView tv = (TextView)yourpreference.getView(null, getListView());
tv.setTextColor(...);
Sorry I couldn't help more...
I had the same problem and I've been experimenting with my custom seekbar-preference's style. Finally these lines in onCreateView method of seekBarPreference.java show preference's summary with default text color:
TextView summaryText = new TextView(getContext());
summaryText.setText(getSummary());
summaryText.setTextAppearance(getContext(), android.R.style.TextAppearance_Small);
I use it on preference_screen.xml:
<com.asdasf.SeekBarPreferencias
android:key="#string/pref_seekBar_distance_key"
android:id="#+id/mySeekBarPreference"
android:title="#string/pref_seekBar_distance_title"
android:summary="#string/pref_seekBar_distance_summary"
android:max="50"
android:defaultValue="12"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
I hope it will be useful...(and that I have written well my first answer)
Regard!

Categories

Resources