I feel like I must be missing something, but I just don't see what it is... I have a PreferenceActivity with a bunch of various preferences (some are lists, some are just text fields) and it all works fine, but unless I explicitly write each item's value to the summary (which is obviously not intended for this purpose) I don't see how (or where) the items display what they are currently set to. When I click on them the various views show up with the correct settings, but that's clearly not the intention.
Do I have to create my own custom List item of some sort that has a field that displays the currently populated value of each element?
Unfortunately the default PreferencesActivity doesn't display the values: what you're doing is really the way to go if you care to have all the preferences displayed at a glance.
If you still want to go down the programming direction then look at this thread: How do I display the current value of an Android Preference in the Preference summary?
Has everything there.
Create another preference field: summary.
Update it whenever a preference field is updated, or when displaying the preferences screen.
The user will be able to "update" the summary value, but whenever he/she enters preferences, the correct value will be displayed.
For ListPreferences, this is built-in and you can use
android:summary="Actual value: %s"
For EditTextPreferences, you can easily create your own class:
package your.package.preference;
import android.content.Context;
import android.util.AttributeSet;
public class EditTextPreference extends android.preference.EditTextPreference{
public EditTextPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public EditTextPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public EditTextPreference(Context context) {
super(context);
}
#Override
public CharSequence getSummary() {
String summary = super.getSummary().toString();
return String.format(summary, getText());
}
}
And use this in your xml:
<your.package.EditTextPreference
android:key="pref_alpha"
android:summary="Actual value: %s"
android:title="Title"
android:defaultValue="default"
/>
Related
When I'm trying to set summary when the users select a preference item, it normally saved. But when my app is restarted, the summary is gone.
Here is my code to set the summary for ListPreference and EditTextPreference:
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key){
Preference pref = findPreference(key);
// I feel the problem is happened here
if (pref instanceof ListPreference) {
ListPreference listPref = (ListPreference) pref;
pref.setSummary(listPref.getEntry());
}
// Same problem here
if (pref instanceof EditTextPreference) {
EditTextPreference editText = (EditTextPreference) pref;
pref.setSummary(editText.getEntry().toString());
}
}
Is there something wrong?
if you only want to show the current entry, try to set the summary in your xml:
android:summary="%s"
This works only for the ListPreference (see Doc):
If the summary has a String formatting marker in it (i.e. "%s" or "%1$s"), then the current entry value will be substituted in its place.
The problem might be that the listener is not called on startup (the value is not changed). But you can set the summary dynamically in the XML. For a ListPreference, this is built-in and #FreshD's answer is the way to go. To extend to an EditTextPreference, you need to create your own class. For example
package your.package;
import android.content.Context;
import android.util.AttributeSet;
public class EditTextPreference extends android.preference.EditTextPreference{
public EditTextPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public EditTextPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public EditTextPreference(Context context) {
super(context);
}
#Override
public CharSequence getSummary() {
String summary = super.getSummary().toString();
return String.format(summary, getText());
}
}
And use this in your xml:
<your.package.EditTextPreference
android:key="pref_alpha"
android:summary="Actual value: %s"
android:title="Title"
android:defaultValue="default"
/>
ListPreference listPref = (ListPreference) findPreference("listkey");
listPref.setSummary(listPref.getEntry());
EditTextPreference editText = (EditTextPreference) findPreference("edittextkey");
editText.setSummary(editText.getEntry().toString());
If you have the key then set the summary like above, in oncreate after addpreferences in your preferenceFragment or Activity
I struggled so much to make summaries dynamic. Not exactly sure if this answers the question but wanted to post somewhere so if someone searches they don't have to struggle like i did.
This is the simple solution useSimpleSummaryProvider="true"
I have an EditTextPreference in the PreferenceActivity. When user click the EditTextPreference will show a dialog. In the dialog, user can input a value, and the dialog has "OK" and "Cancel" buttons. I want to call the click event of ok button to check the value, but I do not know how to call the click even.
I know I can use EditTextPreference.setOnPreferenceChangeListener(), but I want to know if I can use OK button click event.
You can extend EditTextPreference to get control over the click handler.
package myPackage;
public class CustomEditTextPreference extends EditTextPreference {
public CustomEditTextPreference(Context context) {
super(context);
}
public CustomEditTextPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomEditTextPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
public void onClick(DialogInterface dialog, int which) {
if (which == DialogInterface.BUTTON_POSITIVE) {
// add Handler here
}
super.onClick(dialog, which);
}
}
In the Xml instead of <EditTextPreference/> reference it like this:
<myPackage.CustomEditTextPreference android:dialogTitle="Registration Key" android:key="challengeKey" android:title="Registration Key" android:summary="Click here to enter the registration key you received by email."/>
Actually you can't since the preference is using an internal AlertDialog.Builder and creates a new dialog every time you click the preference. The next problem is that the dialog builder sets the click listener for you and if you override them you might destroy the close behavior of the button click.
This bothered me since I wanted a preference which only closes on valid input (otherwise a toast is shown and user should press cancel if he can't get it right).
(If you really need a solution for exactly this problem) You can find general solution of a validating DialogPreference here and a validating EditTextPreference here which I wrote myself.
Your preference activity doesn't appear to be implementing a
OnSharedPreferenceChangeListener
You may want to read over the excellent answer to the question: Updating EditPreference
I am using this TimePickerPreference implementation: http://www.ebessette.com/d/TimePickerPreference
It works nice. But I do not know how to set a default value for it. So if the preference is called the first time, it should show the current time.
I also would like to extend it, to show the chosen time in the title.
In my preference.xml:
<com.example.preference.TimePickerPreference
android:key="quit_time"
android:dialogTitle="Quit"
android:title="Quit"/>
Maybe this code helps you TimePickerPreference.java
Firstly, I apologize for my English, I'm pulling translators . I know the thread is old, but I searched for information on this problem today and nadia had put no solution . What if it happens to anyone else here I leave . This component out there also has the bug that if you cancel the insertion of the time this is always stored . Also comment on your solution.
Let's start with the main thing, is not exactly why he never throws the setter of the default value and the quickest solution would be to manually control element builders. I personally have decided to create a new attribute called "timeByDefault" that is responsible for conducting the functionality of "defaultValue".
/**
* #param context
* #param attrs
*/
public TimePickerPreference(Context context, AttributeSet attrs) {
super(context, attrs);
handleCustomAttributes(context, attrs);
initialize();
}
/**
* #param context
* #param attrs
* #param defStyle
*/
public TimePickerPreference(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
handleCustomAttributes(context, attrs);
initialize();
}
private void handleCustomAttributes(Context context, AttributeSet attrs){
TypedArray arr = context.obtainStyledAttributes(attrs, R.styleable.TimePickerPreference);
CharSequence timeByDefaultCS = arr.getString(R.styleable.TimePickerPreference_timeByDefault);
if (null != timeByDefaultCS){
setTimeByDefault(timeByDefaultCS.toString());
}
}
public void setTimeByDefault(Object defaultValue) {
setDefaultValue(defaultValue);
}
Now we create the attribute in "attrs.xml" file in the folder "/res/values/", and add the following resource:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="TimePickerPreference">
< attr name="timeByDefault" format="string" />
</declare-styleable>
</resources>
It will be very important for the new attribute can be accessed from xml will declare xmlns:custom="http://schemas.android.com/apk/res-auto" at the beginning of our xml file in the manner indicated below.
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res-auto"
>
<PreferenceCategory android:title="Notifications">
<com.mypackage.TimePickerPreference
android:key="KEY_TO_SAVE_THE_TIME_IN_PREFERENCE"
android:title="My custom title"
android:summary="My detail"
android:dialogTitle="My dialog title"
custom:timeByDefault="07:30"
/>
</PreferenceCategory>
</PreferenceScreen>
Now I will explain the issue of canceling the date change:
Opening the dialog box allows us to accept or cancel the new time. This component accepts always time whatever you do. So I created a variable to temporarily store intermediate private time really introduced until accept that value.
private String tmpPersistString = "";
Replace the following function to leave as follows:
#Override
public void onTimeChanged(TimePicker view, int hour, int minute) {
tmpPersistString = hour + ":" + minute;
}
Similarly we control when we pressed one of two buttons, that when we are pressing to accept it then that we store the value of the new time:
#Override
public void onClick(DialogInterface dialog, int which) {
super.getDialog().getCurrentFocus().clearFocus();
super.onClick(dialog, which);
if (which != -2){
persistString(tmpPersistString);
tmpPersistString = "";
}
}
And although it is not entirely necessary to initialize the temporary variable ground when the dialog if the ESC key is pressed to close if you have physical keyboard, or the return button or clicks outside the window.
#Override
public void onDismiss(DialogInterface dialog) {
super.onDismiss(dialog);
tmpPersistString = "";
}
I can only hope that you have understood enough to make this component a good choice at the time to develop and it will be of use to more people. A greeting!
I'm extending PreferenceActivity for my settings screen. In this preference activity i have a couple of preferences one of which is custom made. The problem is as follows:
in this custom preference (which extends from ListPreference) i want to be able to set the default value, so i override the setDefaultValue() method. In this method i do some parsing so it'll take the correct value. When i'm trying to read this value with the getValue() function it just returns null.
So i figured, what happens when i just put some hardcoded value in there (you know, maybe i did something wrong, wouldn't be the first time). Well, i still get null back.
Any ideas what i'm doing wrong?
Edit:
Setting the defaultValue in the xml file isn't really an option because the values aren't known until i retrieve them.
I made a workaround:
When app is started for the first time: get data
Set the values in the preference.
This way i set the default preference when i'm collection the data
I finally found the solution (somewhere besides StackOverflow, for once).
When you create a custom Preference class,
You need to implement onSetInitialValue as XåpplI'-I0llwlg'I - pointed out
You also need to implement onGetDefaultValue(TypedArray a, int index)
For example, if the custom preference is saved as an int,
#Override
protected void onSetInitialValue(boolean restore, Object defaultValue) {
setValue(restore ? getPersistedInt(FALLBACK_DEFAULT_VALUE) : (Integer) defaultValue);
}
#Override
protected Object onGetDefaultValue(TypedArray a, int index) {
return a.getInteger(index, FALLBACK_DEFAULT_VALUE);
}
Now PreferenceManager.setDefaultValues() finally loads the android:defaultValue for the custom preferences too. Still no fix for nulls and false, but there are workarounds for those posted elsewhere.
If you want to call getValue() after calling setDefaultValue() to retrieve a default value the first time your PreferenceActivity opens, you need to override onSetInitialValue() in your Preference subclass. Otherwise, the default value will not be set when you call getValue() and it will return a null (as you experienced).
For example, if your default value is an integer, your onSetInitialValue() might look like this:
#Override
protected void onSetInitialValue(boolean restore, Object defaultValue)
{
setValue(restore ? getPersistedInt(DEFAULT_VALUE) : (Integer) defaultValue);
}
DEFAULT_VALUE is just a private constant inside the Preference to be used in case the persisted int cannot be retrieved. setValue() is the public setter to complement your getValue() public getter, and should look something like this:
public int getValue()
{
return mValue;
}
public void setValue(int value)
{
if (value != mValue)
{
mValue = value;
persistInt(value);
}
}
For more information about onSetInitialValue(), refer to the API documentation here.
It's also a good idea to look at the source code of the Preference class (here) to understand why onSetInitialValue() needs to be implemented. In particular, have a look at setDefaultValue(), and then look at dispatchSetInitialValue().
setDefaultValue doesn't work the way you think it does. Look at the source of Preference.java and you'll the logic behind it all.
The preferred way to set a default is to specify the android:defaultValue attribute in the preferences.xml file of your app.
I converted preferences .xml to code. All setDefaultValues works well there.
val screen = preferenceManager.createPreferenceScreen(context)
val editText = EditTextPreference(context).apply {
setIcon(R.drawable.lobat_cloud)
key = "key"
title = "MyPreferences"
...
setDefaultValue("My Default Value")
}
screen.addPreference(editText)
// add other preferences
preferenceScreen = screen
more info
P.S: I found this way more smaller and clear than customizing all preferences or other answers.
You can extend preference and set the default value during constructing like this:
package com.example.package.preference;
public class CustomPreference extends ListPreference{
public CustomPreference(Context context) {
super(context);
init();
}
public CustomPreference(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
Object anyDefaultValueFromCode = ...
setDefaultValue(anyDefaultValueFromCode );
}
}
then you can use it from XML like this:
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
android:key="alarm_prefs_screen"
android:title="#string/set_alarm" >
<com.example.package.preference.CustomPreference
android:key="custom_preference"
android:title="#string/any_title" />
</PreferenceScreen>
This is what I did and worked for me:
class DefaultValueEditTextPreference : androidx.preference.EditTextPreference {
#Suppress("unused")
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes)
#Suppress("unused")
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
#Suppress("unused")
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
#Suppress("unused")
constructor(context: Context?) : super(context)
init {
text = ... //the default, dynamic text that you want to have
}
}
I think this works too at anytime.
Preference aaa = (Preference) findPreference("xxx");
aaa.setOnPreferenceClickListener(new OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference preference) {
// For edit text preference
((EditTextPreference)preference).getEditText().setText("foobar");
// for list preference
(ListPreference)preference).setValue("foobar");
// etc ...
return true;
}
});
This code will detect when the dialog is about to launch and populate the EditText or List in the dialog with your default value.
I would like to be able to assign a xml attribute or style to a TextView that will make whatever text it has in ALL CAPITAL LETTERS.
The attributes android:inputType="textCapCharacters" and android:capitalize="characters" do nothing and look like they are for user inputed text, not a TextView.
I would like to do this so I can separate the style from the content. I know I could do this programmically but again I want keep style out of the content and the code.
I though that was a pretty reasonable request but it looks like you cant do it at this time. What a Total Failure. lol
Update
You can now use
textAllCaps
to force all caps.
What about android:textAllCaps?
By using AppCompat textAllCaps in Android Apps supporting older API's (less than 14)
There is one UI widgets that ships with AppCompat named CompatTextView is a Custom TextView extension that adds support for textAllCaps
For newer android API > 14 you can use :
android:textAllCaps="true"
A simple example:
<android.support.v7.internal.widget.CompatTextView
android:id="#+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:textAllCaps="true"/>
Source:developer.android
Update:
As it so happens CompatTextView was replaced by AppCompatTextView in
latest appcompat-v7 library ~ Eugen Pechanec
It is really very disappointing that you can't do it with styles (<item name="android:textAllCaps">true</item>) or on each XML layout file with the textAllCaps attribute, and the only way to do it is actually using theString.toUpperCase() on each of the strings when you do a textViewXXX.setText(theString).
In my case, I did not wanted to have theString.toUpperCase() everywhere in my code but to have a centralized place to do it because I had some Activities and lists items layouts with TextViews that where supposed to be capitalized all the time (a title) and other who did not... so... some people may think is an overkill, but I created my own CapitalizedTextView class extending android.widget.TextView and overrode the setText method capitalizing the text on the fly.
At least, if the design changes or I need to remove the capitalized text in future versions, I just need to change to normal TextView in the layout files.
Now, take in consideration that I did this because the App's Designer actually wanted this text (the titles) in CAPS all over the App no matter the original content capitalization, and also I had other normal TextViews where the capitalization came with the the actual content.
This is the class:
package com.realactionsoft.android.widget;
import android.content.Context;
import android.util.AttributeSet;
import android.view.ViewTreeObserver;
import android.widget.TextView;
public class CapitalizedTextView extends TextView implements ViewTreeObserver.OnPreDrawListener {
public CapitalizedTextView(Context context) {
super(context);
}
public CapitalizedTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CapitalizedTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
public void setText(CharSequence text, BufferType type) {
super.setText(text.toString().toUpperCase(), type);
}
}
And whenever you need to use it, just declare it with all the package in the XML layout:
<com.realactionsoft.android.widget.CapitalizedTextView
android:id="#+id/text_view_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
Some will argue that the correct way to style text on a TextView is to use a SpannableString, but I think that would be even a greater overkill, not to mention more resource-consuming because you'll be instantiating another class than TextView.
I've come up with a solution which is similar with RacZo's in the fact that I've also created a subclass of TextView which handles making the text upper-case.
The difference is that instead of overriding one of the setText() methods, I've used a similar approach to what the TextView actually does on API 14+ (which is in my point of view a cleaner solution).
If you look into the source, you'll see the implementation of setAllCaps():
public void setAllCaps(boolean allCaps) {
if (allCaps) {
setTransformationMethod(new AllCapsTransformationMethod(getContext()));
} else {
setTransformationMethod(null);
}
}
The AllCapsTransformationMethod class is not (currently) public, but still, the source is also available. I've simplified that class a bit (removed the setLengthChangesAllowed() method), so the complete solution is this:
public class UpperCaseTextView extends TextView {
public UpperCaseTextView(Context context) {
super(context);
setTransformationMethod(upperCaseTransformation);
}
public UpperCaseTextView(Context context, AttributeSet attrs) {
super(context, attrs);
setTransformationMethod(upperCaseTransformation);
}
public UpperCaseTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setTransformationMethod(upperCaseTransformation);
}
private final TransformationMethod upperCaseTransformation =
new TransformationMethod() {
private final Locale locale = getResources().getConfiguration().locale;
#Override
public CharSequence getTransformation(CharSequence source, View view) {
return source != null ? source.toString().toUpperCase(locale) : null;
}
#Override
public void onFocusChanged(View view, CharSequence sourceText,
boolean focused, int direction, Rect previouslyFocusedRect) {}
};
}
Basically, write this in TextView of XML file:
android:textAllCaps="true"
It seems like there is permission on mobile keypad setting, so the easiest way to do this is:
editText.setFilters(new InputFilter[]{new InputFilter.AllCaps()});
hope this will work
PixlUI project allows you to use textAllCaps in any textview or subclass of textview including:
Button,
EditText
AutoCompleteEditText
Checkbox
RadioButton
and several others.
You will need to create your textviews using the pixlui version rather than the ones from the android source, meaning you have to do this:
<com.neopixl.pixlui.components.textview.TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/hello_world"
pixlui:textAllCaps="true" />
PixlUI also allows you to set a custom typeface/font which you put in your assets folder.
I'm working on a Gradle fork of the PixlUI framework which uses gradle and allows one to specify textAllCaps as well as the typeface from styles rather than requiring them inline as the original project does.