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"
Related
I cant get this to work I want the sign out Button on this preferences screen to have a ClickListener
This is how it looks like:
Here´s the code and the buttonView is always NULL:
class PreferencesFragment : PreferenceFragmentCompat() {
lateinit var activity: Context
private var prefs: SharedPreferences = BleApplication.getInstance().getDefaultSharedPreferences()
override fun onAttach(context: Context?) {
super.onAttach(context)
activity = requireActivity()
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val buttonView = view.findViewById<View>(R.id.btn_sign_out)
if (buttonView != null) {
buttonView.setOnClickListener {
Toast.makeText(getActivity(), "You clicked me.", Toast.LENGTH_SHORT).show()
}
}
// Hide the divider
/* setDivider(ColorDrawable(Color.TRANSPARENT))
setDividerHeight(0)*/
}
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
addPreferencesFromResource(R.xml.app_prefs)
}
}
I also tried the kotlinx.android.synthetic but same problem there
Here´s the xml
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory
android:layout="#layout/pref_category_text"
android:title="#string/pref_category_remote_battery_title">
<SwitchPreferenceCompat
android:key="#string/pref_key_category_remote_battery_switch"
android:title="#string/pref_category_remote_battery_switch_title"
android:summary="#string/pref_category_remote_battery_switch_summ"/>
</PreferenceCategory>
<PreferenceCategory
android:layout="#layout/pref_category_text"
android:title="#string/pref_category_sign_out_title">
<Preference
android:key="#string/pref_key_category_signed_out"
android:widgetLayout="#layout/pref_category_sign_out_button"
android:title="#string/pref_category_sign_out_button_title"
android:summary="#string/pref_category_sign_out_buttom_summ"/>
</PreferenceCategory>
</PreferenceScreen>
Here is the "#layout/pref_category_sign_out_button" layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<Button
android:id="#+id/btn_sign_out"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/buttonshape"
android:text="#string/pref_category_sign_out_title" />
</LinearLayout>
Since your Fragment extends from PreferenceFragmentCompat, you should not try to set a View.OnClickListener but override PreferenceFragmentCompat.onPreferenceTreeClick() instead. According to the documentation, this method is ...
Called when a preference in the tree rooted at this PreferenceScreen has been clicked.
Code example in Java:
#Override
onPreferenceTreeClick(Preference preference){
if(preference.getKey().equals(getContext().getString(R.string.pref_key_category_signed_out))){
// user clicked signout "button"
// take appropriate actions
// return "true" to indicate you handled the click
return true;
}
return false;
}
Code example in Kotlin (I hope I can trust Android Studio :P)
override fun onPreferenceTreeClick(preferenceScreen: PreferenceScreen, preference: Preference): Boolean {
return if (preference.key == context.getString(R.string.pref_key_category_signed_out)) {
// user clicked signout "button"
// take appropriate actions
// return "true" to indicate you handled the click
true
} else false
}
This will enable you to catch click events for the Preference but not for the Button.
In order to do that as well, one can use a custom Preference and override onBindViewHolder(PreferenceViewHolder). Since PreferenceViewHolder - similar to RecyclerView.ViewHolder - has a field itemView which contains the inflated layout, here is a good opportunity to set our own View.OnClickListener.
SignOutPreference extends from TwoStatePreference (in the com.android.support:preference-v7 library) because replacing the CheckBox widget with your custom Button requires only to set the android:widgetLayout attribute, just like you do in your code snippet:
<PreferenceCategory
android:layout="#layout/pref_category_text"
android:title="#string/pref_category_sign_out_title">
<your.package.name.SignOutPreference
android:key="#string/pref_key_category_signed_out"
android:widgetLayout="#layout/pref_category_sign_out_button"
android:title="#string/pref_category_sign_out_button_title"
android:summary="#string/pref_category_sign_out_buttom_summ"/>
</PreferenceCategory>
SignOutPreference.java
public class SignOutPreference extends TwoStatePreference {
public SignOutPreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public SignOutPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SignOutPreference(Context context) {
super(context);
}
#Override
public void onBindViewHolder(final PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
Button button = holder.itemView.findViewById(R.id.btn_sign_out);
if(button != null){
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(holder.itemView.getContext(), "CLICKED!", Toast.LENGTH_SHORT).show();
}
});
}
}
}
As #0X0nosugar mentioned you can use the onPreferenceTreeClicked method to handle all clicks in a convenient way like this:
#Override
onPreferenceTreeClick(Preference preference){
if ((preference.getKey().equals(getContext().getString(R.string.pref_key_category_signed_out))){
// user clicked signout "button"
// take appropriate actions
// return "true" to indicate you handled the click
return true;
}
return false;
}
The problem when using a custom button via widgetLayout is that when the button click is not a Preference click, so the handler doesn't catch it. One way to circumvent this problem is to just disable the built-in click for the button, like this:
<Button
android:id="#+id/btn_sign_out"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/buttonshape"
android:text="#string/pref_category_sign_out_title"
android:clickable="false"/>
See the last line. This way you don't need to create an extra class just for the button and you can easily access whatever methods and variables you have in your PreferencesFragment class.
I'm sure there's a better way to somehow trigger the Preference click from the button click, but at least this works as pretty well.
I was looking for a simple answer and found a way. Just set the onClick attribute for the button in the xml file, and implement the method in the parent activity of the preference fragment. (It's important to implement it in the Activity, not in the Preference Fragment. Or else it will give you crashes)
I wanted to make my onClick method to work only when the button is touched(clicked), and not respond to clicks in the area outside of the button. So far this is the only way that works just like I wanted it to.
My code is in Kotlin, but the logic is simple so it won't be hard to write it in java.
This is my button.xml used for the preference's widgetLayout. Look at how I set the android:onClick= attribute.
<?xml version="1.0" encoding="utf-8"?>
<Button
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/btn"
android:text="reset"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="#style/rippleEffect" //my custom ripple effect
android:onClick="onClickMethod">
</Button>
Then I implemented the onClickMethod in the parent activity of the preference fragment. This callback method should be public, and have View as input parameter.
(For more info read this -> How exactly does the android:onClick XML attribute differ from setOnClickListener? )
fun onClickMethod(view: View) {
//do something
}
Below is my preference.xml.
<Preference
android:key="pref_key"
android:title="Reset"
android:summary="summary.."
app:iconSpaceReserved="false"
android:widgetLayout="#layout/button"/>
Also I tried to set the ClickListener programmatically, but the only way that worked without errors was when I set the button's ClickListener inside the PreferenceClickListener. This only worked half way, since I need to touch(click) the preference item first to init the button's ClickListener.
val view = findPreference<androidx.preference.Preference>("pref_key")
var isFirst = true
view?.setOnPreferenceClickListener {
if (isFirst) {
btn.setOnClickListener {
Toast.makeText(requireContext(), "button clicked!", Toast.LENGTH_SHORT).show()
}
isFirst = false
it.summary = "unlocked"
} else {
isFirst = true
it.summary = "locked - tap to unlock"
}
true
}
Anyway this answer is working well for me, but I'm still looking for a way to use my preference key since this method does not fully uses the preference attribute, but just as a layout. But for now I hope this is helpful for those who want to use buttons in android preference.
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.
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());**
}
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.
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!