I'm using Android SharedPreferences API to build a settings screen.
I've one setting which I need a long text to explain the user its meaning (I would like to have something like main title and smaller subtitle,but i think it would require to much customization)
the settings.xml is like:
<EditTextPreference
android:defaultValue="15"
android:inputType="number"
android:icon="#drawable/ic_timer"
android:key="#string/pref_comment_interval"
android:persistent="true"
android:lines="2"
android:title="#string/time_between_comments" />
but even setting lines=2 and breaking the line with \n at time_between_comments the text is getting wrapped.
<string name="time_between_comments">Time between comments (in seconds)\nLower is faster</string>
like:
how can i make the text to break the line?
By default, the title of EditTextPreference is singleLine="true"
So we should custom it as below
public class MultiLineTitleEditTextPreference extends EditTextPreference {
public MultiLineTitleEditTextPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public MultiLineTitleEditTextPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MultiLineTitleEditTextPreference(Context context) {
super(context);
}
#Override
protected void onBindView(View view) {
super.onBindView(view);
TextView textView = (TextView) view.findViewById(your_package.R.id.title);
if (textView != null) {
textView.setSingleLine(false);
}
}
}
This doesn't work for all Preference types, but it works for EditTextPreference.
Add <![CDATA[ \n]]> around the first line of your title like in this example:
<string name="pref_title_special_with_note"><![CDATA[Special Title\n]]><small><i> ** followed by second line note</i></small></string>
This will display the second line in smaller text size and italic, but that's just decoration.
Related
I've created a SettingsActivity with the template and put an EditTextPreference in my root_preferences.xml. It should contain a password, so I edited it like this:
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="#color/colorBackground">
<EditTextPreference
android:id="#+id/etPassword"
android:dialogTitle="Passwort"
android:inputType="textPassword"
android:key="pref_password"
android:selectAllOnFocus="true"
android:singleLine="true"
android:title="Passwort" />
My problem is that neither inputType, singleLine nor setAllOnFocus is working. Do you know what's the problem?
In my case, InputType doesn't hide the password on input and also in the summary.
Here's how I got around the problem
XML file
<PreferenceScreen
xmlns:app="http://schemas.android.com/apk/res-auto">
<EditTextPreference
app:key="pref_password"
app:title="Password"
app:dialogTitle="Set password"
app:useSimpleSummaryProvider="true"
/>
</PreferenceScreen>
In the PreferenceFragmentCompat set in your XML, find your EditTextPreference in the onCreatePreferences section and add an OnBindEditTextListener on it.
public static class YourFragment extends PreferenceFragmentCompat {
#Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
// Find the password EditText
EditTextPreference etpPassword = getPreferenceManager().findPreference("pref_password");
etpPassword.setOnBindEditTextListener(new EditTextPreference.OnBindEditTextListener() {
#Override
public void onBindEditText(#NonNull EditText editText) {
// Set keyboard layout and some behaviours of the field
editText.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
// Replace -> android:singleLine="true"
// Not needed for password field, or set it before setTransformationMethod
// otherwise the password will not be hidden
//editText.setSingleLine(true);
// Replace -> android:inputType="textPassword"
// For hiding text
editText.setTransformationMethod(PasswordTransformationMethod.getInstance());
// Replace -> android:selectAllOnFocus="true"
// On password field, you cannot make a partial selection with .setSelection(start, stop)
editText.selectAll();
// Replace -> android:maxLength="99"
editText.setFilters(new InputFilter[]{new InputFilter.LengthFilter(99)});
}
});
}
}
You also can create your own EditTextPreference class and set other things.
public class YourEditTextPreference extends EditTextPreference {
// Add some preferences, which can be used later for checking
private Integer mPasswordMinSize = 6;
public EditTextPreferencePassword(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
public EditTextPreferencePassword(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public EditTextPreferencePassword(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public EditTextPreferencePassword(Context context) {
super(context);
init();
}
private void init(){
// Set Dialog button text
this.setNegativeButtonText("RETURN");
this.setPositiveButtonText("CHECK");
this.setOnBindEditTextListener(new OnBindEditTextListener() {
#Override
public void onBindEditText(#NonNull EditText editText) {
// Put field parameters here
}
});
}
public void setMinSize(int minSize) { mPasswordMinSize = minSize; }
public Integer getMinSize(){ return mPasswordMinSize; }
// Hide password by stars
#Override
public CharSequence getSummary() {
return getText().equals("") ? super.getSummary() : "*******";
}
}
And in your XML, change <EditTextPreference to <complet.path.to.YourEditTextPreference
As pointed out in a previous answer, inputType is not understood by EditTextPreference and it seems it's not able to pass it to the underlying EditText object by itself, as one would expect.
Adding to the problem, there seems to be a lack of consistency depending on which libraries you are using. The accepted answer doesn't seem to work with AndroidX because there's no such getEditText() method in that EditTextPreference implementation. There's a way, though, by adding a listener that's exactly there for that (Kotlin example):
val myPref = findPreference<EditTextPreference>(
"my_pref_key"
)
myPref?.setOnBindEditTextListener {
it.inputType = InputType.TYPE_CLASS_NUMBER
}
Finally does the trick, but I have wasted a good hour trying to figure out a solution for this, mostly reading outdated questions and answers on the matter.
I see it's been awhile but setting this inside the SettingsFragment onViewCreated() worked for me...
val pw = preferenceScreen.preferenceManager.findPreference<EditTextPreference>("password")
pw?.setOnBindEditTextListener {
it.inputType = InputType.TYPE_CLASS_TEXT + InputType.TYPE_TEXT_VARIATION_PASSWORD
}
You can't do it from XML, but EditTextpreference exposes the EditText so you can do it programmatically. After you load the preferences in your Activity/Fragment, you can do:
EditTextPreference pref = (EditTextPreference)
PreferenceManager.findPreference("edit");
EditText prefEditText = pref.getEditText();
prefEditText.setInputType(InputType.TYPE_CLASS_TEXT); // set properties here
prefEditText.setSingleLine(true);
Background
I have an App with multiple custom TextViews in it.
These four Custom TextViews are all set up like this:
public class TextView_Light extends android.support.v7.widget.AppCompatTextView {
public TextView_Light(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public TextView_Light(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public TextView_Light(Context context) {
super(context);
init();
}
public void init() {
Typeface tf = Typeface.createFromAsset(getContext().getAssets(), "fonts/Roboto-Light.ttf");
setTypeface(tf ,1);
}}
I do have TextView_Bold, TextView_Light, TextView_Regular and TextView_Thin. Each of them uses another font which is saved in assets/fonts
I use the TextViews like that:
<de.mayr.wap.app.helper.TextView_Light
android:id="#+id/textView_Light7"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:text="#string/overviewViaBarcode"
android:textSize="16sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
When the App is started and a view shows up for the first time everything looks great, like that:
The Problem
In this view the user klicks on one of the tablerows, an Dialog appears where the user types in some data. On save the onResume method of the view is called, which calls an Webservice etc. like that:
#Override
public void onResume() {
super.onResume();
callSerNrWS();
}
public void callSerNrWS() {
if (CheckNetwork.isNetworkAvailable(getContext())) {
final AsyncResponseFortschritt<ResponseObject<PruefauftraegeVO>> response = new AsyncResponseFortschritt<ResponseObject<PruefauftraegeVO>>() {
#Override
public void processFinishSerNr(ResponseObject<PruefauftraegeVO> output) {
anw = createPruefAnwArraylist();
seriennummerVO = findDataToSerNr();
adapt = new PruefAnwAdapter(getContext(), anw, seriennummerVO);
pruefListView.setAdapter(adapt);
setVisibilityLoadAnimation(View.GONE);
if (output.getException() != null && !output.getException().isEmpty())
AlertCreator.makeFailAlert(R.string.titelKeinFortschritt, R.string.textKeinFortschritt,getContext());
}
#Override
public void processStartSerNr() {
setVisibilityLoadAnimation(View.VISIBLE);
}
};
AsyncCallSerNrWS ws = new AsyncCallSerNrWS(response, pruefauftraegeVO);
ws.execute();
}
}
And after that, theres in 90% of cases one or more TextView which changed its looking from eg. TextView_Light to TextView_Thin. Like in the following picture: The appearence of the 'Anzugstrom [A]' in the third row now looks like a TextView_Thin and the '9/48' in the fifth row looks like a TextView_Light
What I know
This doesnt happen when the view is shown for the first time
There isn't any system behind it. It's totally random.
It happens in activitys and fragments
It happens in every view i have whatever the TextView contains 'hard-coded' text or text that comes from an Webservice
Its not just in lists, also in 'normal' views
Is there a way to change how the detection of autoLink TextView finds phone numbers?
Thing is, it detects international format quite well, like +49123456789 but it fails on local formatted numbers like 0699777666555 (without a preceeding "+" character).
We need to have those numbers available too.
The TextView is set up with autoLink="all"
<TextView
android:id="#+id/chat_message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
... some other settings ...
android:autoLink="all"
android:linksClickable="true"
android:textColorLink="#color/darkblue"
android:textColor="#color/black"/>
We have internal numbers (like 5532) and local phone numbers without any prefixes like 12345678. It would be great, if they can be highlighted too, without any, or at least without too much coding involved.
Any solutions to this?
Thanks in advance!
Try to do this programatically:
public class AutoLinkifyTextView extends TextView {
public AutoLinkifyTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public AutoLinkifyTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
public void setText(String text) {
super.setText(text);
parseLinks();
}
#Override
public void setText(int stringRes) {
super.setText(stringRes);
parseLinks();
}
private void parseLinks() {
Linkify.addLinks(this, Linkify.ALL);
}
}
and then use AutoLinkifyTextView instead of TextView
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.
When a user want to paste text in MultiAutoCompleteTextView I want to overwrite it.
Means whatever he copies it must paste in my MultiAutoCompleteTextView as "Java is rocket".
I may achieve it from previous question here but I don't know how to hook the class MonitoringEditText to my MultiAutoCompleteTextView.
Can I achieve it or it is impossible.
You can do this using the same concept provided in the code from the link you provided. Extend the MultiAutoCompleteTextView and override the onTextContextMenuItem method.
Something along the lines of:
public class MonitoringMultiAutoCompleteTextView extends MultiAutoCompleteTextView {
public MonitoringMultiAutoCompleteTextView(Context context) {
super(context);
}
public MonitoringMultiAutoCompleteTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MonitoringMultiAutoCompleteTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
//based on http://stackoverflow.com/a/14981376/1566836
#Override
public boolean onTextContextMenuItem(int id) {
// Do your thing:
boolean consumed = super.onTextContextMenuItem(id);
// React:
if (android.R.id.paste == id) {
setText("Java is rocket");
}
return consumed;
}
}
Then change your MultiAutoCompleteTextView in your layout file to whatever.your.full.package.is.MonitoringMultiAutoCompleteTextView.
After that, any attempt to paste into your MultiAutoCompleteTextView will result in the text being changed to "Java is rocket"