I'm trying to extract the value set on this attribut <item name="android:textStyle">bold</item>
According to the documentation the return values for this attribut are
Normal: 0
Bold: 1
Italic: 2
But I'm always getting 0 for styleVal no matter what is passed in the textStyle!
Everything in the code seems correcet and I can't debug the error
private void getTextViewStyleValue() {
int[] AttrSet = {
android.R.attr.textColor,
android.R.attr.textStyle,
android.R.attr.fontFamily,
};
TypedArray a = context.obtainStyledAttributes(style, AttrSet);
textColor = a.getColor(0, DEFAULT_TEXT_COLOR);
int styleVal = a.getInt(1, 0);
font = Typeface.createFromAsset(context.getAssets(), a.getString(2));
a.recycle();
}
This is what is written about android.R.attr.textStyle's value
Related
I have replaced the default style of the data picker with the spinner one but now I need to change the date format (of the spinner not of the "result") to be the same in all cultures (dd/MM/yyyy).
I have tried to change the Format, but it's the format of the placeholder...
I'm sure that there is a way to change it in styles.xml but I don't know how to do it.
In styles.xml I have:
<item name="android:dialogTheme">#style/MyDialogTheme</item>
<item name="android:datePickerStyle">#style/MyDatePicker</item>
<style name="MyDialogTheme" parent="android:Theme.Material.Light.Dialog">
<item name="android:datePickerStyle">#style/MyDatePicker</item>
<item name="android:datePickerMode">spinner</item>
<item name="android:calendarViewShown">false</item>
<item name="android:spinnersShown">true</item>
</style>
<style name="MyDatePicker" parent="android:Widget.Material.Light.DatePicker">
<item name="android:datePickerMode">spinner</item>
<item name="android:calendarViewShown">false</item>
<item name="android:spinnersShown">true</item>
</style>
There is a way to change it here or in the custom renderer?
I had the same problem, I found this answer useful but it's for native android, I had to do some changes for Xamarin.Forms Android, create a custom renderer and add these lines:
protected override DatePickerDialog CreateDatePickerDialog(int year, int month, int day)
{
var dialog = base.CreateDatePickerDialog(year, month, day);
dialog.Show();
OrderDate(dialog, new char[] { 'd', 'm', 'y' });
return dialog;
}
private void OrderDate(DatePickerDialog dialog, char[] ymdOrder)
{
if (!dialog.IsShowing)
{
return;
}
int idYear = Resources.GetIdentifier("year", "id", "android");
int idMonth = Resources.GetIdentifier("month", "id", "android");
int idDay = Resources.GetIdentifier("day", "id", "android");
int idLayout = Resources.GetIdentifier("pickers", "id", "android");
NumberPicker spinnerYear = (NumberPicker)dialog.FindViewById(idYear);
NumberPicker spinnerMonth = (NumberPicker)dialog.FindViewById(idMonth);
NumberPicker spinnerDay = (NumberPicker)dialog.FindViewById(idDay);
LinearLayout layout = (LinearLayout)dialog.FindViewById(idLayout);
layout.RemoveAllViews();
for (int i = 0; i < SPINNER_COUNT; i++)
{
switch (ymdOrder[i])
{
case 'y':
layout.AddView(spinnerYear);
setImeOptions(spinnerYear, i);
break;
case 'm':
layout.AddView(spinnerMonth);
setImeOptions(spinnerMonth, i);
break;
case 'd':
layout.AddView(spinnerDay);
setImeOptions(spinnerDay, i);
break;
}
}
}
private void setImeOptions(NumberPicker spinner, int spinnerIndex)
{
ImeAction imeOptions;
if (spinnerIndex < SPINNER_COUNT - 1)
{
imeOptions = inputMethos.ImeAction.Next;
}
else
{
imeOptions = inputMethos.ImeAction.Done;
}
int idPickerInput = Resources.GetIdentifier("numberpicker_input", "id", "android");
TextView input = (TextView)spinner.FindViewById(idPickerInput);
input.SetImeActionLabel("",imeOptions);
}
The DatePicker (Spinner) on Android defaults to the chosen settings on the User's phone. It is generally advised not to override native behavior.
You can however, override this behavior by creating a custom renderer to use a Custom DatePicker by following the steps shown here: https://stackoverflow.com/a/7208968/11104068
I've looked at most all of the threads on this and none provided an answer that works. Styling the NumberPicker does not work (as per this thread: NumberPicker textColour)
Setting the style attribute on the numberPicker to a style that has a color item does not have any effect either. Nor does setting the textColor attribute on the numberPicker XML do anything.
Closest I've got to this is using the numberPicker to cast its getChildAt() to an EditText and then do setColor() on that EditText, but that only changes the color of the child once upon initialization and then every time it is selected from thereon; not what I am looking for either.
Any help? Thanks
The solution I tried and worked for me is:
In styles.xml add:
<style name="AppTheme.Picker" parent="Theme.AppCompat.Light.NoActionBar" >
<item name="android:textColorPrimary">#android:color/black</item>
</style>
Then use it like this inside your layout:
<NumberPicker
android:id="#+id/dialogPicker"
android:theme="#style/AppTheme.Picker"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="15dp" />
This code should solve your problem. The problem you are experiencing is because during the construction of NumberPicker it captures the EditText textColor and assigns to to a paint so it can draw the numbers above and below the edit text with the same color.
import java.lang.reflect.Field;
public static void setNumberPickerTextColor(NumberPicker numberPicker, int color)
{
try{
Field selectorWheelPaintField = numberPicker.getClass()
.getDeclaredField("mSelectorWheelPaint");
selectorWheelPaintField.setAccessible(true);
((Paint)selectorWheelPaintField.get(numberPicker)).setColor(color);
}
catch(NoSuchFieldException e){
Log.w("setNumberPickerTextColor", e);
}
catch(IllegalAccessException e){
Log.w("setNumberPickerTextColor", e);
}
catch(IllegalArgumentException e){
Log.w("setNumberPickerTextColor", e);
}
final int count = numberPicker.getChildCount();
for(int i = 0; i < count; i++){
View child = numberPicker.getChildAt(i);
if(child instanceof EditText)
((EditText)child).setTextColor(color);
}
numberPicker.invalidate();
}
Not sure why you would need to dive into Java Reflection API for this. Its a simple styling matter. The attribute that you need to override is: textColorPrimary.
<style name="AppTheme" parent="#android:style/Theme.Holo.Light">
....
<item name="android:textColorPrimary">#ff0000</item>
</style>
If you're using the TimePicker inside a Dialog, override android:textColorPrimary in the dialog's theme.
That's about it.
Additional info:
Here's an insightful comment by Yoann Hercouet:
This solution does not change only the color on the NumberPicker, it
is a global change that will impact A LOT of components
This is correct, but it overlooks the possibilities I am hinting at. Moreover, global implies app-wide impact. That can be limited to activity-scope by applying this theme only to activities containing the NumberPicker. But, I agree, this may still be too corrosive.
The idea here is to somehow inject textColorPrimary=INTENDED_COLOR into the theme that will be seen by NumberPicker. There are multiple ways to achieve this. Here's one way:
Define a bare-bone style in res/values/styles.xml:
<style name="NumberPickerTextColorStyle">
<item name="android:textColorPrimary">#color/intended_color</item>
</style>
Now, create a custom NumberPicker:
public class ThemedNumberPicker extends NumberPicker {
public ThemedNumberPicker(Context context) {
this(context, null);
}
public ThemedNumberPicker(Context context, AttributeSet attrs) {
// wrap the current context in the style we defined before
super(new ContextThemeWrapper(context, R.style.NumberPickerTextColorStyle), attrs);
}
}
Finally, use ThemedNumberPicker in your layout(s):
<package.name.ThemedNumberPicker
android:id="#+id/numberPicker"
....
....
.... />
We have successfully contained the impact that textColorPrimary=INTENDED_COLOR has on our app.
This is of course just one option. For example, if you were inflating a layout containing a NumberPicker, you could use:
// In this case, the layout contains <NumberPicker... />, not <ThemedNumberPicker... />
LayoutInflater.from(new ContextThemeWrapper(context, R.style.NumberPickerTextColorStyle))
.inflate(R.layout.number_picker_layout, ...);
Here is a Xamarin Snippet from the answer above with TextSize and TextStyle Bold
public static bool SetNumberPickerTextColorAndSize(NumberPicker numberPicker, Color color, ComplexUnitType complexUnitType, float textSize, TypefaceStyle style)
{
int count = numberPicker.ChildCount;
for (int i = 0; i < count; i++)
{
View child = numberPicker.GetChildAt(i);
if (child.GetType() == typeof(EditText))
{
try
{
Field selectorWheelPaintField = numberPicker.Class
.GetDeclaredField("mSelectorWheelPaint");
selectorWheelPaintField.Accessible = true;
EditText editText = (EditText) child;
editText.SetTextSize(complexUnitType, textSize);
editText.SetTypeface(editText.Typeface, style);
editText.SetTextColor(color);
Paint paint = (Paint) selectorWheelPaintField.Get(numberPicker);
paint.TextSize = TypedValue.ApplyDimension(complexUnitType, textSize, numberPicker.Resources.DisplayMetrics);
paint.Color = color;
paint.SetTypeface(editText.Typeface);
numberPicker.Invalidate();
return true;
}
catch (NoSuchFieldException e)
{
Log.Warn("setNumberPickerTextColor", e);
}
catch (IllegalAccessException e)
{
Log.Warn("setNumberPickerTextColor", e);
}
catch (IllegalArgumentException e)
{
Log.Warn("setNumberPickerTextColor", e);
}
}
}
return false;
}
For me setting android:textColorPrimary in my theme did nothing, looking at the source code for the NumberPicker it decides the text color from the EditText input thus one need to set the android:editTextColor instead.
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:editTextColor">#color/dark_gray</item>
</style>
Instead of changing every text color to the color you want, better just changing all editText color. NumberPicker actually has a child EditText that display the numbers.
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.NoActionBar">
<!-- Change edit color here. -->
<item name="android:editTextColor">#000000</item>
</style>
This worked for me. And although I have white text in the buttons, they havent changed.
Based on reflection reject on Android SDK >= 29 better to modify Simon's answer:
public void setNumberPickerTextColor(NumberPicker numberPicker, int color){
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
final int count = numberPicker.getChildCount();
for (int i = 0; i < count; i++) {
View child = numberPicker.getChildAt(i);
if (child instanceof EditText) {
try {
((EditText) child).setTextColor(color);
numberPicker.invalidate();
Field selectorWheelPaintField = numberPicker.getClass().getDeclaredField("mSelectorWheelPaint");
boolean accessible = selectorWheelPaintField.isAccessible();
selectorWheelPaintField.setAccessible(true);
((Paint) selectorWheelPaintField.get(numberPicker)).setColor(color);
selectorWheelPaintField.setAccessible(accessible);
numberPicker.invalidate();
Field selectionDividerField = numberPicker.getClass().getDeclaredField("mSelectionDivider");
accessible = selectionDividerField.isAccessible();
selectionDividerField.setAccessible(true);
selectionDividerField.set(numberPicker, null);
selectionDividerField.setAccessible(accessible);
numberPicker.invalidate();
} catch (Exception exception) {
Logger.exc(exception);
}
}
}
} else {
numberPicker.setTextColor(color);
}
}
In SDK >= 29 NumberPicker have .setTextColor() method.
I took the solution of #Andreas Merz and updated his code. The way things were assigned and the functions signatures/calls he used were not found. I am using min API 19. Here is the code that worked for me.
/**
* Based on https://stackoverflow.com/a/26657169/2313889
* #param picker
* #param color
* #param unit
* #param textSize
* #param typeface
* #return
*/
private void formatNumberPickerText(NumberPicker picker, int color,
int unit, float textSize,
Typeface typeface) {
int count = picker.getChildCount();
for (int i = 0; i < count; i++) {
View child = picker.getChildAt(i);
if (child instanceof EditText) {
try {
Class clazz = picker.getClass();
Field field = clazz.getDeclaredField("mSelectorWheelPaint");
field.setAccessible(true);
EditText editText = (EditText) child;
editText.setTextSize(unit, textSize);
editText.setTypeface(typeface);
editText.setTextColor(color);
Paint paint = (Paint) field.get(picker);
paint.setTextSize(TypedValue.applyDimension(
unit, textSize, getResources().getDisplayMetrics()
));
paint.setColor(color);
paint.setTypeface(typeface);
picker.invalidate();
return;
} catch (IllegalAccessException | NoSuchFieldException e) {
e.printStackTrace();
}
}
}
}
The accepted answer is overly complicated. A much simpler approach that worked for me was to override the: textColorPrimary attribute of the theme I was using.
<style name="Theme.MyTheme" parent="#android:style/Theme.Holo.NoActionBar.Fullscreen" >
<item name="android:textColorPrimary">#000000</item>
</style>
It did the job quite well!
For Kotlin users, use this extension function ( Based on #Tapa Save answer ).
fun NumberPicker.changeTextColor(color: Int) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
val count: Int = childCount
for (i in 0 until count) {
val child: View = getChildAt(i)
if (child is EditText) {
try {
child.setTextColor(color)
invalidate()
val selectorWheelPaintField: Field = this.javaClass.getDeclaredField("mSelectorWheelPaint")
var accessible: Boolean = selectorWheelPaintField.isAccessible
selectorWheelPaintField.isAccessible = true
(selectorWheelPaintField.get(this) as Paint).color = color
selectorWheelPaintField.isAccessible = accessible
invalidate()
val selectionDividerField: Field = this.javaClass.getDeclaredField("mSelectionDivider")
accessible = selectionDividerField.isAccessible()
selectionDividerField.isAccessible = true
selectionDividerField.set(this, null)
selectionDividerField.isAccessible = accessible
invalidate()
} catch (ignore: Exception) { }
}
}
} else {
textColor = color
}
}
It's easy with my NumberPicker library.
<com.github.tomeees.scrollpicker.ScrollPicker
...
app:textColor="..."
/>
I'm trying to reset the TextColor of a TextView at runtime. I would like to get the default color for TextView as a #ColorInt. I believe that the current Theme knows this.
Here's what I tried:
public #ColorInt int getDefaultThemeColor(int attribute) {
TypedArray themeArray = mContext.getTheme().obtainStyledAttributes(new int[] {attribute});
try {
int index = 0;
int defaultColourValue = 0;
return themeArray.getColor(index, defaultColourValue);
}
finally {
themeArray.recycle();
}
}
where attribute is:
android.R.attr.textColor
android.R.attr.textColorPrimary
android.R.attr.textColorSecondary
None of them worked to retrieve the right color. I've also tried to replace the first line of the method with:
TypedArray themeArray = mContext.getTheme().obtainStyledAttributes(R.style.AppTheme, new int[] {attribute});
I don't want the dirty solution of:
getting and storing the textColor of a TextView
changing the color to whatever
Reset it back to the previously stored value
Any hint?
Define the following extension function (using kotlin):
#ColorInt
#SuppressLint("ResourceAsColor")
fun Context.getColorResCompat(#AttrRes id: Int): Int {
val resolvedAttr = TypedValue()
theme.resolveAttribute(id, resolvedAttr, true)
val colorRes = resolvedAttr.run { if (resourceId != 0) resourceId else data }
return ContextCompat.getColor(this, colorRes)
}
And then use it as follow:
val defaultText = context.getColorResCompat(android.R.attr.textColorPrimary)
The following code gives you a ColorStateList, which is not exactly what you asked for, but might be also applicable in the context where you need it:
TypedArray themeArray = theme.obtainStyledAttributes(new int[]{android.R.attr.textColorSecondary});
ColorStateList textColorSecondary = themeArray.getColorStateList(0);
TL;DR I looking for an implementation of public static Drawable getDrawableFromAttribute(Context context, String attrName).
I'm searching for a way, to load dynamic drawables, which are defined in my style with custom attributes. That's my configuration
attr.xml
<resources>
<attr name="custom_image" type="reference">
</resources>
styles.xml
<resources>
<style name="demo">
<item name="custom_image">#drawable/fancy_picture</item>
</style>
</resources>
The fancy_picture is a named /res/drawables/fancy_pictures.xml.
Now, I want someone to enter the string "custom" and "image" and the ImageView should show the fancy_picture in it.
What is the best way to do this? If I use a XML-Layout file, I could write
<ImageView
...
android:src="?custom_image"
...
/>
I didn't use declare-styleable in my style xml and I would like to ignore them completely, if possible.
I found a solution for this
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public static Drawable getAttrDrawable(Context context, #AttrRes int attrRes) {
Drawable drawable = null;
TypedValue value = new TypedValue();
if (context.getTheme().resolveAttribute(attrRes, value, true)) {
String[] data = String.valueOf(value.string).split("/");
int resId = context.getResources().getIdentifier(data[2].substring(0, data[2].length() - 4), "drawable", context.getPackageName());
if (resId != 0) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
drawable = context.getDrawable(resId);
} else {
drawable = context.getResources().getDrawable(resId);
}
}
}
return drawable;
}
public static Drawable getAttrDrawable(Context context, String attr) {
int attrRes = context.getResources().getIdentifier(attr, "attr", context.getPackageName());
if (attrRes != 0) {
return getAttrDrawable(context, attrRes);
}
return null;
}
and it worked well for attr -> xml and attr -> png.
This is my code
TextView text_language_name4 = (TextView)view.findViewById(R.id.text);
if (text_language_name4 != null) {
int text_color4 = selected
? getResources().getColor(R.color.readcolor)
: getResources().getColor(R.color.readcolor);
text_language_name4.setTextColor(text_color4);
text_language_name4.setDuplicateParentStateEnabled(true);
}
When i am using R.attr.mytheme my app forces close
Any suggestions for using attr to change color of a text view
For the theme color try like this:
TypedValue tV = new TypedValue();
Theme theme = context.getTheme();
boolean success = theme.resolveAttribute(R.attr.theme_color, tV, true);
int colorFromTheme;
if(success)
colorFromTheme = tV.data;
else
// value not found....
Now set,
textView.setTextColor(colorFromTheme);
You can use something like this if i understood your problem right:
textView.setTextColor(Color.parseColor("#ffffff"));
While "#ffffff" is the hex value of the color.
Assuming you have:
<color name="green">#0000ff00</color>
And here is code:
int greenColor = getResources().getColor(R.color.green);
String strGreenColor = "#"+Integer.toHexString(greenColor);
mTextView.setTextColor(Color.parseColor(""+greenColor));