When the numberpicker is loaded, the default value is not appearing on the screen until touched.
Once touched, everything works fine.Any help appreciated.
Also if the formatter is removed, it works fine.
dialog.xml
<NumberPicker
android:id="#+id/number_picker"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<Button
android:id="#+id/apply_button"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/number_picker"
android:text="#string/ok_string" />
Here is the activity code:
final NumberPicker np = (NumberPicker) d.findViewById(R.id.number_picker);
np.setMaxValue(50);
np.setMinValue(0);
np.setWrapSelectorWheel(true);
np.setOnValueChangedListener(this);
np.setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS);
np.setFormatter(new NumberPicker.Formatter() {
#Override
public String format(int i) {
if (i == 25)
return "0";
else
return String.valueOf(i - 25);
}
});
np.setValue(25);
Thanks in advance
#Renjith
Thank for the link, but I think you should link the code or even paste it here.
https://code.google.com/p/android/issues/detail?id=35482#c9
Field f = NumberPicker.class.getDeclaredField("mInputText");
f.setAccessible(true);
EditText inputText = f.get(mPicker);
inputText.setFilters(new InputFilter[0]);
The issue seems to a bug in NumberPicker widget.
And I have solved it using method 2 described here.
I found a solution for this bug in NumberPicker that works in APIs 18-26 without using reflection and without using setDisplayedValues() here.
Here's the accepted answer written in Kotlin in a single line:
// NOTE: workaround for a bug that rendered the selected value wrong until user scrolled, see also: https://stackoverflow.com/q/27343772/3451975
(NumberPicker::class.java.getDeclaredField("mInputText").apply { isAccessible = true }.get(this) as EditText).filters = emptyArray()
Note that I recommend to keep the comment line to document why this code is needed.
I had the same problem and I was using NumberPicker with Strings.
My problem was that after the activity was opened with a transition the the default value in the number picker was invisible, even though i was setting the picker values with picker.setDisplayedValues(list.toStringsArray())
So for me the solution was the following:
private void populatePicker(NumberPicker picker, String[] strings, int index) {
picker.setDisplayedValues(null);
picker.setMinValue(0);
picker.setMaxValue(strings.length - 1);
picker.setDisplayedValues(strings);
picker.setValue(index);
try {
Field field = NumberPicker.class.getDeclaredField("mInputText");
field.setAccessible(true);
EditText inputText = (EditText) field.get(picker);
inputText.setVisibility(View.INVISIBLE);
} catch (Exception e) {
e.printStackTrace();
}
}
Try
np.setWrapSelectorWheel(false);
Related
Recently, I migrate my android project to AndroidX and I use the EditTextPreference from AndroidX library. Now, I want to set the maximum length of the EditTextPreference to let say 50. I have tried to use:
android:maxLength="50"
but it's not working.
It seems that all android namespace won't work with the EditTextPreference and there is no code suggestion so I cannot find any related code to set the maximum length. How can I set the maximum length?
You need find your EditTextPreference by key, then set onBindEditTextListener to it and change layout attributes at the onBindEditText method:
EditTextPreference preference = findPreference("edit_text_preference_key");
preference.setOnBindEditTextListener(new EditTextPreference.OnBindEditTextListener() {
#Override
public void onBindEditText(#NonNull EditText editText) {
editText.setInputType(InputType.TYPE_CLASS_NUMBER); // set only numbers allowed to input
editText.selectAll(); // select all text
int maxLength = 2;
editText.setFilters(new InputFilter[]{new InputFilter.LengthFilter(maxLength)}); // set maxLength to 2
}
});
You can put this code to onResume() method of yout PreferencesFragment or PreferencesActivity.
You may try with java code, that will works.
Here is snipped.
EditText et = (EditText) findViewById(R.id.myeditText);
et.setFilters(new InputFilter[]{ new InputFilter.LengthFilter(50) }); // maximum length is 50
I hope that will help you.
This is the code to set maximal length (in this case 10) of EditTextPreference:
final EditTextPreference prefCustomText = findPreference(ActivityPreferences.PREF_DISPLAY_CUSTOM_TEXT);
prefCustomText.setOnBindEditTextListener(editText -> {
editText.setFilters(new InputFilter[]{new InputFilter.LengthFilter(10)});
});
And I'm adding information as wrote #Viktor Brešan:
I think you should append the new InputFilter to ones that might have
been added to EditText previously. You can get them by calling
editText.getFilters()
I'm trying to remove the day row in my spinner. I'm setting
android:calendarViewShown="false"
android:datePickerMode="spinner"
so that it uses the spinner mode. Before I was using reflection like this:
Field[] fields = DatePicker.class.getDeclaredFields();
try {
String[] s = new String[] {"01","02","03","04","05","06","07","08","09","10","11","12"};
for (Field field : fields) {
field.setAccessible(true);
if (TextUtils.equals(field.getName(), "mMonthSpinner")) {
NumberPicker monthPicker = (NumberPicker) field.get(this);
monthPicker.setDisplayedValues(s);
}
if (TextUtils.equals(field.getName(), "mShortMonths")) {
field.set(this, s);
}
if (TextUtils.equals(field.getName(), "mDaySpinner") || TextUtils.equals(field.getName(), "mDayPicker")) {
((View) field.get(this)).setVisibility(GONE);
}
}
}
but now, with Lollipop, those fields don't exist anymore.
Any idea on how to tackle this problem?
There isn't a solution for Android 5.0+ with the DatePicker for the time being. You could try doing it with the DateSlider, so you don't have to code your own DatePicker. If you use the MonthYearDateSlider, you should be able to accomplish what you need.
I found a solution by using reflection. I'm not a fan of it but well, it solves it for now. I basically found this answer: Android: how to change the color of the datepicker divider?
I build EditText dynamically. Among other things, I set 2 properties: hint(.setHint) and inputType(.setInputType). My problem: when I invoke setInputType, setHint has no effect: blank edittexts remain blank with no hint. Once I comment out setInputType, I see all hints. I need both input type and hint. What to do? My code:
private EditText buildTextBox(Property property)
{
EditText control = new EditText(this);
control.setInputType(getInputTypeByPropertyInputType(property.getType()));// android.text.InputType.
control.setHint(property.getDisplayName());
return control;
}
private int getInputTypeByPropertyInputType(String type)
{
if (type.equals("integer"))
{
return android.text.InputType.TYPE_CLASS_NUMBER;
}
else
{
return android.text.InputType.TYPE_CLASS_TEXT;
}
}
#Eugene
Ensure you call control.SetHint() just before you call the control.setGravity() and control.setInputType(); and it works for me verrry much!
column1 = new EditText(this);
column1.setId(i);
column1.setHint("Value");
column1.setInputType(InputType.TYPE_CLASS_NUMBER);
column1.setGravity(Gravity.RIGHT);
I agree with Eugene.
Remove the gravity(just don't use CENTER) and the hint texts will come back as normal.
Nice find!
I would like to see the maxLength of an EditText at run time to be able to make a text display decision.
Is that possible?
Here is a description of what I wan't to do.
I have a ListView with many rows and each row have an EditText and a TextView.
I've made a subclass of ArrayAdapter to be able to feed the String that I want to place in the EditText of each row.
I have set android:maxLength="12" in the XML file.
I want to display a number in that EditText field, but if the number I want to display has more than android:maxLength="12" I want to display an "error message" instead.
And I would prefer not to hard code that 12 in my subclass of ArrayAdapter.
There is probably a simple solution, but I haven't found it yet.
(android first time...)
Only limited parameters have their getters, so I don't think you can read it .
So write length (Say 12) in values folder and use it in xml layout and arrayAdapter .
Now its not hard-coded .
1)Create integer.xml in values *
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item type="integer" name="max_length">12</item>
</resources>
2)In layout
<TextView android:id="#+id/tv"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:maxLength="#integer/max_length"
/>
3) in ArrayAdapter :
int maxLength = getResources().getInteger(R.integer.max_length);
This should work:
editText.setFilters(new InputFilter[] { new InputFilter.LengthFilter(12) });
From api 21 you can do it like that:
for (InputFilter filter : mEditText.getFilters()) {
if (filter instanceof InputFilter.LengthFilter) {
((InputFilter.LengthFilter) filter).getMax());
}
}
I hope this helps someone.
extend the edit text and retrieve the value from the attributeset in the constructor.
public class MyEditText extends EditText {
public static final String XML_NAMESPACE_ANDROID = "http://schemas.android.com/apk/res/android";
private int mMaxLength;
public MyEditText(Context context) {
super(context, null);
}
public MyEditText(Context context, AttributeSet attrs) {
super(context, attrs);
mMaxLength = attrs.getAttributeIntValue(XML_NAMESPACE_ANDROID, "maxLength", -1);
}
Kotlin one line solution - returns max length or null if not set
view.filters.filterIsInstance<InputFilter.LengthFilter>().firstOrNull()?.max
As extension:
val TextView.maxLength: Int?
get() = filters.filterIsInstance<InputFilter.LengthFilter>().firstOrNull()?.max
You can get the Field value using the Reflection API.
Why You Shouldn't Do It
Just about everyone would advocate against it (including me) because:
It's slow
It's implementation-dependant
It's not intended to be accessed (obviously)
As of now, looking at the source code (Android API 19), the implementation depends on an
InputFilter.LengthFilter which is set in the constructor as:
if (maxlength >= 0) {
setFilters(new InputFilter[] { new InputFilter.LengthFilter(maxlength) });
} else {
setFilters(NO_FILTERS);
}
where maxLength is the Integer you're interested in finding, parsed from the xml attribute (android:maxLength="#integer/max_length").
This InputFilter.LengthFilter has only one field (private int mMax) and no accessor method.
How It Can Be Done
Declare a static method in a relevant utility class accepting a TextView and returning an int.
Iterate over each InputFilter set on the TextView and find one belonging to the InputFilter.LengthFilter implementation.
Access, get and return the mMax field's value using Reflection.
This would give you something like this:
import java.lang.reflect.Field;
// [...]
public static int getMaxLengthForTextView(TextView textView)
{
int maxLength = -1;
for (InputFilter filter : textView.getFilters()) {
if (filter instanceof InputFilter.LengthFilter) {
try {
Field maxLengthField = filter.getClass().getDeclaredField("mMax");
maxLengthField.setAccessible(true);
if (maxLengthField.isAccessible()) {
maxLength = maxLengthField.getInt(filter);
}
} catch (IllegalAccessException e) {
Log.w(filter.getClass().getName(), e);
} catch (IllegalArgumentException e) {
Log.w(filter.getClass().getName(), e);
} catch (NoSuchFieldException e) {
Log.w(filter.getClass().getName(), e);
} // if an Exception is thrown, Log it and return -1
}
}
return maxLength;
}
As mentioned earlier, this will break if the implementation that sets the maximum length of the TextView changes. You will be notified of this change when the method starts throwing. Even then, the method still returns -1, which you should be handling as unlimited length.
Kind of complicated, but I don't know of any other approach. I hope it works (not tested):
XmlResourceParser parser = getResources().getLayout(R.layout.theLayout);
String namespace = "http://schemas.android.com/apk/res/android";
int maxLength = parser.getAttributeIntValue(namespace, "maxLength", 12);
The border displays a default color (that's orange on my Nexus S) while scrolling a ListView to the limit. How to change that color?
I really don't know how to explain it. Just look at this picture:
So, how to change the highlight color when the ListView scrolling to the border? using themes or styles
The solution is to use setOverscrollFooter(null) and setOverscrollHeader(null).
The documentation is here !
You can also set it directly in the XML :
<ListView android:overScrollMode="never" />
Or specify the footer and the header :
<ListView
android:overscrollHeader="#null"
android:overscrollFooter="#null" />
N.B. : There is also a property fadingEdge that may interest you.
"Overscroll" methodes are supported starting API level 9
Finally I found the solution.
setOverscrollFooter(null) and setOverscrollHeader(null) does not work. At least on 2.3.*. Setting attributes from *.xml doesn't help too.
setOverScrollMode(View.OVER_SCROLL_NEVER) causes glitchy scrolling. At least on 2.3.*.
The only solution that really works involves the use of Java Reflection.
It works even with ugly custom Samsung listviews with bounce overscroll effect.
Here is a snippet:
#Override
protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
//onOverScrolled method must be overrided, or we will see the background of the listview when overscroll fast.
}
private void removeOverscrollEffect() {
try {
Class<?> superClass = getClass().getSuperclass().getSuperclass();
Field field = superClass.getDeclaredField("mEdgeGlowTop");
field.setAccessible(true);
Object edgeGlowTop = field.get(this);
if (edgeGlowTop != null) {
Class<? extends Object> edgeClass = edgeGlowTop.getClass();
Field edgeDrawable = edgeClass.getDeclaredField("mEdge");
edgeDrawable.setAccessible(true);
edgeDrawable.set(edgeGlowTop, new ColorDrawable(Color.TRANSPARENT));
Field glowDrawable = edgeClass.getDeclaredField("mGlow");
glowDrawable.setAccessible(true);
glowDrawable.set(edgeGlowTop, new ColorDrawable(Color.TRANSPARENT));
field.set(this, edgeGlowTop);
}
Field fieldBottom = superClass.getDeclaredField("mEdgeGlowBottom");
fieldBottom.setAccessible(true);
Object edgeGlowBottom = fieldBottom.get(this);
if (edgeGlowBottom != null) {
Class<? extends Object> edgeClassBottom = edgeGlowBottom.getClass();
Field edgeDrawableBottom = edgeClassBottom.getDeclaredField("mEdge");
edgeDrawableBottom.setAccessible(true);
edgeDrawableBottom.set(edgeGlowBottom, new ColorDrawable(Color.TRANSPARENT));
Field glowDrawableBottom = edgeClassBottom.getDeclaredField("mGlow");
glowDrawableBottom.setAccessible(true);
glowDrawableBottom.set(edgeGlowBottom, new ColorDrawable(Color.TRANSPARENT));
fieldBottom.set(this, edgeGlowBottom);
}
} catch (Exception e) {
Log.e(TAG, e.getMessage());
}
}
I hope this helps.
Here is a nice article on ListView Backgrounds Optimization.
To fix this issue, all you have to do is either disable the cache color hint optimization, if you use a non-solid color background, or set the hint to the appropriate solid color value. You can do this from code (see setCacheColorHint(int)) or preferably from XML, by using the android:cacheColorHint attribute. To disable the optimization, simply use the transparent color #00000000. The following screenshot shows a list with android:cacheColorHint="#00000000"
Use it in XML file--
<ListView ---
android:fadingEdge="none"
---</ListView>
EDITED:
Using fading edges may introduce noticeable performance degradations and should be used only when required by the application's visual design. To request fading edges with API level 14 and above, use the android:requiresFadingEdge attribute instead.
Check this API link
I used kord's answer until it stopped working in Lollipop, so I changed into this:
try {
Class<?> superClass = getClass().getSuperclass().getSuperclass();
Field field = superClass.getDeclaredField("mEdgeGlowTop");
field.setAccessible(true);
field.set(this, new NoEdgeEffect(getContext()));
Field fieldBottom = superClass.getDeclaredField("mEdgeGlowBottom");
fieldBottom.setAccessible(true);
fieldBottom.set(this, new NoEdgeEffect(getContext()));
} catch (Exception e) {
}
class NoEdgeEffect extends EdgeEffect
{
public NoEdgeEffect(Context context) {
super(context);
}
public boolean draw(Canvas canvas) {
// Do nothing
return false;
}
}
you can use android:listSelector="#002234".
In above value can be any color code that you can find on internet easily.