DatePicker spinner Lollipop remove day row - android

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?

Related

Is there any way to enable disable YEAR from date picker in android kotlin [duplicate]

I'm using a basic DatePicker and I'm trying to figure out how to hide the Year field on the DatePickerDialog so that only the Month and Day are visible. I don't mind that the underlying code for the year would still be there, I'd just like to hide the Year Field in the Dialog. You know with something like:
((View) myYear).setVisibility(View.GONE);
which I know doesn't work because myYear is a int not a View, but something along those lines. Is it possible?
A super easy way that I found to implement a DatePicker is to call it in xml:
<DatePicker
android:id="#+id/thePicker"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
and then hide whichever field you want (in this case the year) in java:
picker = (DatePicker) findViewById(R.id.thePicker);
try {
Field f[] = picker.getClass().getDeclaredFields();
for (Field field : f) {
if (field.getName().equals("mYearPicker")) {
field.setAccessible(true);
Object yearPicker = new Object();
yearPicker = field.get(picker);
((View) yearPicker).setVisibility(View.GONE);
}
}
}
catch (SecurityException e) {
Log.d("ERROR", e.getMessage());
}
catch (IllegalArgumentException e) {
Log.d("ERROR", e.getMessage());
}
catch (IllegalAccessException e) {
Log.d("ERROR", e.getMessage());
}
Be really careful with this solution. you are using reflexion to access a field and change the visibility. This will not work with Android 5.0 ! Google have changed the implementation of the TimePicker and DatePicker and the classes are no longer exposing any fields appart from the delegate.
I don't know the solution yet for Android 5.0+.I will let you know as soon I found something interesting.
As an idea, you could use the Build.VERSION.SDK_INT to check the Android version and then try to access the DatePickerSpinnerDelegate using reflexion and set the field you want.
Again, this is not the ideal solution as Google are free to change this again and again...
Easy way to disable Year field in date picker
DatePicker dp = findDatePicker((ViewGroup) dialog.getWindow().getDecorView());
if(dp != null)
{
((ViewGroup) ((ViewGroup) dp.getChildAt(0)).getChildAt(0)).getChildAt(2).setEnabled(false);
((ViewGroup) ((ViewGroup) dp.getChildAt(0)).getChildAt(0)).getChildAt(2).setAlpha(0.4f);
}
if you want to remove year field just setvisibility of result view to View.GONE like below
dp.getChildAt(0)).getChildAt(0)).getChildAt(2).setVisibility(View.GONE)
private DatePicker findDatePicker(ViewGroup group) {
if (group != null) {
for (int i = 0, j = group.getChildCount(); i < j; i++) {
View child = group.getChildAt(i);
if (child instanceof DatePicker) {
return (DatePicker) child;
} else if (child instanceof ViewGroup) {
DatePicker result = findDatePicker((ViewGroup) child);
if (result != null)
return result;
}
}
}
return null;
}
I have refered below link for reference
Remove year from DatePickerDialog
Recently managed to hide the year part of the dialog by setting the datepicker width too small.
<DatePicker
android:id="#+id/month_day_datepicker"
android:layout_width="140dp"
android:datePickerMode="spinner"
style="?android:attr/borderlessButtonStyle"/>
Let me know if this works, obviously, there is an accessible year in the binding but you can just not pick that up when calculating the date.
You can set range of the year by using this function
datePicker.setYearRange(1950,2017);

Android NumberPicker change text color

I'm new to Android and I'm implementing NumberPicker to one of my activities in my app. Below is the excerpt of my code:
picker = (NumberPicker)findViewById(R.id.order_confirm_bring_time_minute_picker);
picker.setMinValue(15);
picker.setMaxValue(120);
picker.setWrapSelectorWheel(false);
setNumberPickerTextColor(picker, android.R.color.black);
public boolean setNumberPickerTextColor(NumberPicker numberPicker, int color)
{
final int count = numberPicker.getChildCount();
for(int i = 0; i < count; i++){
View child = numberPicker.getChildAt(i);
if(child instanceof EditText){
try{
Field selectorWheelPaintField = numberPicker.getClass()
.getDeclaredField("mSelectorWheelPaint");
selectorWheelPaintField.setAccessible(true);
((Paint)selectorWheelPaintField.get(numberPicker)).setColor(color);
((EditText)child).setTextColor(color);
numberPicker.invalidate();
return true;
}
catch(NoSuchFieldException e){
Log.d("setNumberPickerTextColor", "NoSuchFieldException");
}
catch(IllegalAccessException e){
Log.d("setNumberPickerTextColor", "IllegalAccessException");
}
catch(IllegalArgumentException e){
Log.d("setNumberPickerTextColor", "IllegalArgumentException");
}
}
}
return false;
}
I've looked into this post for the setNumberPickerTextColor method. But it does not seem to work as I set my color to be changed to black, but it is not visible anymore. If I do not use the setNumberPickerTextColor method, then my default color is white, which can be seen when I highlight the text in the EditText field of the NumberPicker.
This is a screenshot of the NumberPicker when the color is not changed.
This is a screenshot of the NumberPicker when the color is changed to black or any other color (I have tested and they give the same result).
Would there be a way to customize the text color in my NumberPicker? Also, I know it is a different question, but the colors of the top and bottom 'bar' as well because they do not fit the color theme of my app. Thanks in advance for help.
You need to pass the resolved color to the setTextColor method, not the resource id.
((EditText)child).setTextColor(getResources().getColor(color));

Android Numberpicker default value not coming

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);

How to Get EditText maxLength setting in code

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);

ListView top highlight on scrolling

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.

Categories

Resources