Making buttons mixed case on Android from Xamarin Forms - android

I am new to Xamrin. I am attempting to build a Xamarin Forms app (as little native as possible) for running on both Android and IOS.
I am running in the Android Emulator and by buttons all have uppercase text even though I'm specifying text in mixed case.
I have found a number of pages that say to add the following to styles.xml:
<item name="android:textAllCaps">false</item>
and another that referenced:
<item name="textAllCaps">false</item>
It looks like, though, that there's been some changes according to the docs in styles.xml, so I added it and it now looks like this:
<?xml version="1.0" encoding="utf-8" ?>
<resources>
<style name="MainTheme" parent="MainTheme.Base">
<!-- As of Xamarin.Forms 4.6 the theme has moved into the Forms binary -->
<!-- If you want to override anything you can do that here. -->
<!-- Underneath are a couple of entries to get you started. -->
<!-- Set theme colors from https://aka.ms/material-colors -->
<!-- colorPrimary is used for the default action bar background -->
<!--<item name="colorPrimary">#2196F3</item>-->
<!-- colorPrimaryDark is used for the status bar -->
<!--<item name="colorPrimaryDark">#1976D2</item>-->
<!-- colorAccent is used as the default value for colorControlActivated
which is used to tint widgets -->
<!--<item name="colorAccent">#FF4081</item>-->
<item name="textAllCaps">false</item>
<item name="android:textAllCaps">false</item>
</style>
</resources>
But when I run the emulator, it shows all button text in all uppercase.
I don't know what else to try.

You can create the Custom Renderer for button and set the SetAllCaps to false and try.
Here is the Code:
public class CustomButtonRenderer : ButtonRenderer
{
public CustomButtonRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Button> e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
// Cleanup
}
if (e.NewElement != null)
{
var button = (Button)this.Control;
button.SetAllCaps(false);
}
}
}

I made a test and found the issue is related to the version of Xamarin.Forms.
If you are using Xamarin.Forms 4.6 , the solution you mentioned before does the trick , we just need to add <item name="android:textAllCaps">false</item> into style.xml .
If you're using the latest version(4.8) , the solution above does not work , we need to create custom renderer for the Button , pls copy the code into your android project.
[assembly: ExportRenderer(typeof(Xamarin.Forms.Button), typeof(MyRenderer))]
namespace YourNameSpace.Droid
{
class MyRenderer : ButtonRenderer
{
public MyRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Button> e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
// Cleanup
}
if (e.NewElement != null)
{
Control.SetAllCaps(false);
}
}
}
}

Related

Switch color is not respected/damped - turn off effect on trackTint color (OnColor)

Normally you would use the OnColor like this
<Switch x:Name="optionSwitch" HorizontalOptions="StartAndExpand" OnColor="Blue" ThumbColor="Cyan" />
to customize the track color and you get the following result:
IsToggled = true;
IsToggled = false;
But in my application the OnColor is always overwritten and I don't know the cause for this (something in Theme.Material.Light.DarkActionBar?).
This is the look and feel in my app with the same code:
IsToggled = true;
IsToggled = false;
So the track color is not the color I set. It seems that there is an "effect", which modifies the color. I thought I could use a custom renderer and change the values for TrackTintMode:
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Switch> e)
{
base.OnElementChanged(e);
if (Control != null)
{
Control.TrackTintMode = Android.Graphics.PorterDuff.Mode.SrcOver;
}
}
But with this the off color is also set and on re-enabling it goes back to default. I tried many other things but the post would get very long with this ...
How can I turn this "feature" off?
Edit:
After many tries I think I can reproduce the issue. The MainActivity.cs has to look like this:
[Activity(Label = "TestSwitch", Icon = "#mipmap/icon", Theme = "#style/AppTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize )]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsApplicationActivity
{
// ...
}
And the according theme in styles.xml:
<?xml version="1.0" encoding="utf-8" ?>
<resources>
<style name="AppTheme" parent="android:Theme.Material.Light.DarkActionBar">
</style>
</resources>
The rest is based on the default XF template.
I was able to reproduce this issue.
Originally, the default Xamarin.Forms Android project used an older style of control rendering that was common prior to Android 5.0. Applications built using the template have FormsApplicationActivity as the base class of their main activity.
Xamarin.Forms Android projects now use FormsAppCompatActivity as the base class of their main activity.
Change:
global::Xamarin.Forms.Platform.Android.FormsApplicationActivity
To:
global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
And use the style.xml like below.
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
After changing, you would get the color you want.

How to read a TextAppearance attribute programmatically [duplicate]

Currently I'm using either a WebView or a TextView to show some dynamic data coming from a webservice in one of my apps.
If the data contains pure text, it uses the TextView and applies a style from styles.xml.
If the data contains HTML (mostly text and images) it uses the WebView.
However, this WebView is unstyled. Therefor it looks a lot different from the usual TextView.
I've read that it's possible to style the text in a WebView simply by inserting some HTML directly into the data. This sounds easy enough, but I would like to use the data from my Styles.xml as the values required in this HTML so I won't need to change the colors et cetera on two locations if I change my styles.
So, how would I be able to do this? I've done some extensive searching but I have found no way of actually retrieving the different style attributes from your styles.xml. Am I missing something here or is it really not possible to retrieve these values?
The style I'm trying to get the data from is the following:
<style name="font4">
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:textSize">14sp</item>
<item name="android:textColor">#E3691B</item>
<item name="android:paddingLeft">5dp</item>
<item name="android:paddingRight">10dp</item>
<item name="android:layout_marginTop">10dp</item>
<item name="android:textStyle">bold</item>
</style>
I'm mainly interested in the textSize and textColor.
It is possible to retrieve custom styles from styles.xml programmatically.
Define some arbitrary style in styles.xml:
<style name="MyCustomStyle">
<item name="android:textColor">#efefef</item>
<item name="android:background">#ffffff</item>
<item name="android:text">This is my text</item>
</style>
Now, retrieve the styles like this
// The attributes you want retrieved
int[] attrs = {android.R.attr.textColor, android.R.attr.background, android.R.attr.text};
// Parse MyCustomStyle, using Context.obtainStyledAttributes()
TypedArray ta = obtainStyledAttributes(R.style.MyCustomStyle, attrs);
// Fetch the text from your style like this.
String text = ta.getString(2);
// Fetching the colors defined in your style
int textColor = ta.getColor(0, Color.BLACK);
int backgroundColor = ta.getColor(1, Color.BLACK);
// Do some logging to see if we have retrieved correct values
Log.i("Retrieved text:", text);
Log.i("Retrieved textColor as hex:", Integer.toHexString(textColor));
Log.i("Retrieved background as hex:", Integer.toHexString(backgroundColor));
// OH, and don't forget to recycle the TypedArray
ta.recycle()
The answer #Ole has given seems to break when using certain attributes, such as shadowColor, shadowDx, shadowDy, shadowRadius (these are only a few I found, there might be more)
I have no idea as to why this issue occurs, which I am asking about here, but #AntoineMarques coding style seems to solve the issue.
To make this work with any attribute it would be something like this
First, define a stylable to contain the resource ids like so
attrs.xml
<resources>
<declare-styleable name="MyStyle" >
<attr name="android:textColor" />
<attr name="android:background" />
<attr name="android:text" />
</declare-styleable>
</resources>
Then in code you would do this to get the text.
TypedArray ta = obtainStyledAttributes(R.style.MyCustomStyle, R.styleable.MyStyle);
String text = ta.getString(R.styleable.MyStyle_android_text);
The advantage of using this method is, you are retrieving the value by name and not an index.
The answers from Ole and PrivatMamtora didn't work well for me, but this did.
Let's say I wanted to read this style programmatically:
<style name="Footnote">
<item name="android:fontFamily">#font/some_font</item>
<item name="android:textSize">14sp</item>
<item name="android:textColor">#color/black</item>
</style>
I could do it like this:
fun getTextColorSizeAndFontFromStyle(
context: Context,
textAppearanceResource: Int // Can be any style in styles.xml like R.style.Footnote
) {
val typedArray = context.obtainStyledAttributes(
textAppearanceResource,
R.styleable.TextAppearance // These are added to your project automatically.
)
val textColor = typedArray.getColorStateList(
R.styleable.TextAppearance_android_textColor
)
val textSize = typedArray.getDimensionPixelSize(
R.styleable.TextAppearance_android_textSize
)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val typeface = typedArray.getFont(R.styleable.TextAppearance_android_fontFamily)
// Do something with the typeface...
} else {
val fontFamily = typedArray.getString(R.styleable.TextAppearance_fontFamily)
?: when (typedArray.getInt(R.styleable.TextAppearance_android_typeface, 0)) {
1 -> "sans"
2 -> "serif"
3 -> "monospace"
else -> null
}
// Do something with the fontFamily...
}
typedArray.recycle()
}
I took some inspiration from Android's TextAppearanceSpan class, you can find it here: https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/text/style/TextAppearanceSpan.java
I was not able to get the earlier solutions to work.
My style is:
<style name="Widget.TextView.NumPadKey.Klondike" parent="Widget.TextView.NumPadKey">
<item name="android:textSize">12sp</item>
<item name="android:fontFamily">sans-serif</item>
<item name="android:textColor">?attr/wallpaperTextColorSecondary</item>
<item name="android:paddingBottom">0dp</item>
</style>
The obtainStyledAttributes() for android.R.attr.textSize gives String results of "12sp" which I then have to parse. For android.R.attr.textColor it gave a resource file XML name. This was much too cumbersome.
Instead, I found an easy way using ContextThemeWrapper.
TextView sample = new TextView(new ContextThemeWrapper(getContext(), R.style.Widget_TextView_NumPadKey_Klondike), null, 0);
This gave me a fully-styled TextView to query for anything I want. For example:
float textSize = sample.getTextSize();
With Kotlin, if you include the androidx.core:core-ktx library in your app/library...
implementation("androidx.core:core-ktx:1.6.0") // Note the -ktx
...you can have either of the following (no need for you to recycle the TypedArray):
// Your desired attribute IDs
val attributes = intArrayOf(R.attr.myAttr1, R.attr.myAttr2, android.R.attr.text)
context.withStyledAttributes(R.style.MyStyle, attributes) {
val intExample = getInt(R.styleable.MyIntAttrName, 0)
val floatExample = getFloat(R.styleable.MyFloatAttrName, 0f)
val enumExample = R.styleable.MyEnumAttrName, MyEnum.ENUM_1 // See Note 1 below
// Similarly, getColor(), getBoolean(), etc.
}
context.withStyledAttributes(R.style.MyStyle, R.styleable.MyStyleable) {
// Like above
}
// attributeSet is provided to you like in the constructor of a custom view
context.withStyledAttributes(attributeSet, R.styleable.MyStyleable) {
// Like above
}
Note 1 (thanks to this answer)
For getting an enum value you can define this extension function:
internal inline fun <reified T : Enum<T>> TypedArray.getEnum(index: Int, default: T) =
getInt(index, -1).let { if (it >= 0) enumValues<T>()[it] else default }
Note 2
The difference between -ktx dependencies like androidx.core:core and androidx.core:core-ktx is that the -ktx variant includes useful extension functions for Kotlin.
Otherwise, they are the same.
Also, thanks to the answer by Ole.
If accepted solution not working for try to rename attr.xml to attrs.xml (worked for me)

Android: Change color of Switch that is added dynamically

Android beginner here, so please bear with me...
I'm using a drawer where the menu items are added dynamically.Currently, this is what my code looks like:
val menu = nav_view.menu
menu.clear()
val selectedCatalogIsEmpty = selectedCatalogs.isEmpty()
for (catalog in catalogs){
val menuItem = menu.add(R.id.catalog_items, Menu.FIRST + catalog.catalogId, Menu.NONE, catalog.catalogName)
val switch = Switch(applicationContext)
menuItem.actionView = switch
if(selectedCatalogIsEmpty ||
selectedCatalogs.contains(catalog.catalogId) ) {
menuItem.isChecked = true
switch.isChecked = true
if(selectedCatalogIsEmpty){
selectedCatalogs.add(catalog.catalogId)
}
}
switch.setOnCheckedChangeListener { _, isChecked -> menuItem.isChecked = isChecked }
}
val menuItemSettings = menu.add(R.id.settings, Menu.NONE+ 5000, Menu.NONE, "Settings" )
Now, what i'd like to do is change the color of the thum when in the selected state. In order to achieve that, I've added the following to the styles.xml file:
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">#color/colorPrimary</item>
<item name="colorPrimaryDark">#color/colorPrimaryDark</item>
<item name="colorAccent">#color/colorPrimary</item>
<item name="colorControlNormal">#color/colorWhite</item>
<item name="colorControlActivated">#color/colorPrimary</item>
</style>
Unfortunately, I'm still getting the wrong color during runtime. Instead of the blue. I'm getting a greeny thumb:
It's clear that I've completely missed the point...I've run a couple of searches and people suggest using the SwitchCompat instead of the Switch. I've tried doing that, but I must also be missing something because I've ended up seing the text in really small caps (instead of the thumb I get with the Switch view).
Thanks.
Regards,
Luis
Ok, so after more than 3 hours, I've finally found my bug: I was using the applicationContext to initialize the Switch and application's theme isn't initialized: it's only used to apply a default theme for the remaining activities. So, updating the Switch instantiation to something like this solves the problem:
val switch = Switch(this#MainActivity) //kotlin ref to my activity

Issue with toggling status bar color on Android O

Something is not working; I don’t know if it's a problem with the emulator or it's a bug on Android Oreo (I have not a physical device with Android O), but I can’t switch from dark to light status bar theme like in Marshmallow.
styles.xml (from api 23):
<resources>
<style name="ThemeLight" parent="MyBaseTheme">
<item name="android:windowBackground">?attr/colorPrimary</item>
<item name="android:statusBarColor">?attr/colorPrimary</item>
<item name="android:windowLightStatusBar">true</item>
</style>
<style name="ThemeDark" parent="MyBaseThemeDark">
<item name="android:windowBackground">?attr/colorPrimary</item>
<item name="android:statusBarColor">?attr/colorPrimary</item>
<item name="android:windowLightStatusBar">false</item>
</style>
</resources>
This works fine on Android M, when I change the theme with setTheme(), but in Android O, once I switch to the light theme, it is no longer changed and the status bar remains dark (windowLightStatusBar = true) /:
It must be a bug and I have reported it to google (https://issuetracker.google.com/issues/65883460).
I use these code to temporary solve the problem.
// fix windowLightStatusBar not changed after applyStyle on Android O
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
final TypedArray a = obtainStyledAttributes(new int[]{android.R.attr.windowLightStatusBar});
final boolean windowLightStatusBar = a.getBoolean(0, false);
a.recycle();
int flag = getWindow().getDecorView().getSystemUiVisibility();
if (windowLightStatusBar) {
flag |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
} else {
flag &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
}
getWindow().getDecorView().setSystemUiVisibility(flag);
}

Android Custom Alert Dialog Display Error after changing the Build Version

I am developing a simple demo . Here in this demo, I am just creating one simple custom alert dialog . It works fine.
It shows me the perfect result when i build application in 1.6, but when i change the android version from 1.6 to 2.2, it shows the unexpected result. It doesn't show the background screen on which i display the custom alert dialog.
Here is my xml file. Custom Dialog Theme File
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="CustomDialogTheme" parent="#android:style/AlertDialog">
<item name="android:windowFrame">#null</item>
<item name="android:windowContentOverlay">#null</item>
<item name="android:backgroundDimEnabled">true</item>
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowAnimationStyle">#android:style/Theme.Dialog</item>
</style>
</resources>
Here is My CustomConfirmOkDialog Class
package com.utility.org;
import android.app.Activity;
import android.app.Dialog;
import android.view.View;
import android.view.Window;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class CustomConfirmOkDialog extends Dialog implements OnClickListener
{
private Button okButton = null;
private TextView infoText=null,confirmBody=null;
private int errorMessage=0;
#SuppressWarnings("unused")
private Activity activity;
public CustomConfirmOkDialog(Activity context,int customdialogtheme,int errorMessage)
{
super(context,customdialogtheme);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.confirm_ok);
this.errorMessage = errorMessage;
this.activity = context;
initControls();
}
private void initControls()
{
okButton = (Button) findViewById(R.id.ok_button);
okButton.setOnClickListener(this);
infoText = (TextView)findViewById(R.id.infoText);
confirmBody = (TextView)findViewById(R.id.confirmBody);
switch (this.errorMessage)
{
case Utility.INVALID_USERNAME_PASSWORD:
try
{
infoText.setText(R.string.signIn);
confirmBody.setText(R.string.invalidUsernameAndPassword);
}
catch (Exception e)
{
e.printStackTrace();
}
break;
default:
break;
}
}
public void onClick(View v)
{
dismiss();
}
}
Calling this class from my main activity using the below code.
CustomConfirmOkDialog dialog = new CustomConfirmOkDialog(MainActivity.this, R.style.CustomDialogTheme, Utility.INVALID_USERNAME_PASSWORD);
dialog.show();
Here you can clearly notice that 1st image shows the background . Its build in android 1.6 version while 2nd image doesn't shows the background . It shows the entire black screen. Its build in android version 2.2 . I am very thankful if anyone can solve this issue.
Can anyone help me to solve this simple and silly issue ?
Thanks in Advance.
It resolved my problem by changing the following code in Custom Dialog Theme xml file.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="CustomDialogTheme" parent="#android:style/Theme.Translucent.NoTitleBar">
<item name="android:windowFrame">#null</item>
<item name="android:windowContentOverlay">#null</item>
<item name="android:backgroundDimEnabled">true</item>
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowNoTitle">true</item>
</style>
</resources>
I also faced the same problem. the problem is when I called constructor of Dialog class
Dialog(Context context, int themeId)
it will hide the background activity. The only solution that i found is don't call this constructor, instead only call
Dialog(Context context)
and set your style in the layout file.
So in your code, only write
super(context)
instead of
super(context, themeid);
Apparently, this is a known issue.
This only happens when you try inheriting from the framework themes.
Using #android:style directly will still treat them as non-
fullscreen, which punches through the black background as expected.
One workaround is to start with a nearly-blank theme (like Panel or
Translucent) and then render what you need in your own layout (such as
dialog edges, etc).
Thought, I still don't fully understand this solution myself yet.
And actually, I'm no longer sure they're talking about the exact same bug you've seen, since they're talking about it not working for an older version of the sdk (not a newer one like yours). See the bug report.

Categories

Resources