I'm facing some strange behaviour in my Xamarin App.
In the shared project I separated all control based styles in single xaml files.
All styles are combined in the DefaultTheme.xaml file.
Then, the DefaultTheme.xaml will be used by the LightTheme.xaml and DarkTheme.xaml.
That's how my styles are managed. Then, depending on "Darkomde on/off" I either load the LightTheme.xaml or the DarkTheme.xaml in the iOS and Android project.
On Android I set the themes like this in the MainActivity.cs (I'm using a SplashActivity.cs as well, should it be set there already?)
protected override void OnCreate(Bundle savedInstanceState)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(savedInstanceState);
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App());
SetAppTheme();
}
void SetAppTheme()
{
if (Resources.Configuration.UiMode.HasFlag(UiMode.NightYes))
SetTheme(RemoteControlRepetierServer.Theme.Dark);
else
SetTheme(RemoteControlRepetierServer.Theme.Light);
}
public void SetTheme(Theme theme)
{
switch (theme)
{
case RemoteControlRepetierServer.Theme.Light:
// Night mode is not active, we're using the light theme
if (App.AppTheme == "light")
return;
App.Current.Resources = new LightTheme();
App.AppTheme = "light";
break;
case RemoteControlRepetierServer.Theme.Dark:
// Night mode is active, we're using dark theme
if (App.AppTheme == "dark")
return;
//Add a Check for App Theme since this is called even when not changed really
App.Current.Resources = new DarkTheme();
App.AppTheme = "dark";
break;
}
App.CurrentAppTheme = theme;
}
So far so good. Now, if I start my Android app, it seems that not all styles are loaded. For instance the Gauge. While the Gauge on the first tab looks like it should, the Gauge on the second tab doesn't.
Both are using the same XAML for the styling.
<gauge:Scale.Pointers>
<gauge:NeedlePointer Value="{Binding SelectedExtruder.TempRead}" Color="{DynamicResource Gray-Black}"
KnobColor="{DynamicResource Gray-Black}" KnobStrokeColor="{DynamicResource Gray-Black}"/>
<gauge:RangePointer Value="{Binding SelectedExtruder.TempRead}" Color="{DynamicResource PrimaryColor}"
RangeCap="Both"
/>
<gauge:MarkerPointer Value="{Binding SetExtruderTemp}" Color="{DynamicResource Red}"/>
</gauge:Scale.Pointers>
Also the Style of the NumericUpDown control is not set on the second tab. This only happens on Android, iOS looks fine all tabs.
I'm not sure what's causing this issue. Any help is appreciated.
If you need further information or code snippets, just let me know.
Just figured out that using the SyncfusionTheme was causing this behaviour. Once I removed it from the MergedDictionaries, it worked.
Related
In my Xamarin project, in the header of the XAML file, I have set:
Shell.BackgroundColor="DarkGreen"
Part of xaml header declaration looks like that:
On Android all things are ok (check the picture below), but on iOS the secondary toolbar (shown in red square) is white, and I can't understand why does it happen and how can I fix this issue?
You can add on itemsApp->AppDelegate.cs->FinishedLaunching method:
if (UIDevice.CurrentDevice.CheckSystemVersion(13, 0))
{
UITabBar.Appearance.TintColor = UIColor.Blue;
UINavigationBar.Appearance.BackgroundColor = UIColor.Blue;
}
The complete method for FinishedLaunching is:
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.SetFlags("CollectionView_Experimental");
global::Xamarin.Forms.Forms.Init();
LoadApplication(new App());
if (UIDevice.CurrentDevice.CheckSystemVersion(13, 0))
{
UITabBar.Appearance.TintColor = UIColor.Blue;
UINavigationBar.Appearance.BackgroundColor = UIColor.Blue;
}
return base.FinishedLaunching(app, options);
}
I'm trying to build an app using the new Widows App SDK. I used the Windows Community Toolkit to create the application.
After consulting the documentation, I tried this:
On the first page that my app displays, I created a Textblock:
<TextBlock Text="Hello" x:Name="CustomTitleBar" />
In this page's code behind, I added the following code:
private void Page_Loaded(object sender, RoutedEventArgs e)
{
App.MainWindow.ExtendsContentIntoTitleBar = true;
App.MainWindow.SetTitleBar(CustomTitleBar);
App.MainWindow.Activate();
}
On the App XAML page I followed the doumentation's directions to override these values:
<SolidColorBrush x:Key="WindowCaptionBackground">Green</SolidColorBrush>
<SolidColorBrush x:Key="WindowCaptionBackgroundDisabled">LightGreen</SolidColorBrush>
<SolidColorBrush x:Key="WindowCaptionForeground">Red</SolidColorBrush>
<SolidColorBrush x:Key="WindowCaptionForegroundDisabled">Pink</SolidColorBrush>
This above does make the default titlebar go away. However, I am left with just the word "Hello" with no background or buttons:
Is there something I'm missing?
You should probably be using the AppWindow and presenter (in my case I used the OverlapedPresenter) classes. Here's some code I used on my app.
public MainWindow()
{
InitializeComponent();
AppWindow appWindow = GetAppWindowForCurrentWindow();
OverlappedPresenter overlappedPresenter = appWindow.Presenter as OverlappedPresenter;
overlappedPresenter.IsResizable = false;
appWindow.TitleBar.ExtendsContentIntoTitleBar = false;
}
Then, right under the constructor I use the method Microsoft provides in this sample:
private AppWindow GetAppWindowForCurrentWindow()
{
IntPtr hWnd = WinRT.Interop.WindowNative.GetWindowHandle(this);
WindowId myWndId = Win32Interop.GetWindowIdFromWindow(hWnd);
return AppWindow.GetFromWindowId(myWndId);
}
I use the OverlapsedPresenter class to change some things about the window, like if it's resizable or not.
There is a known issue with UWP Xamarin Apps in that the size that fonts render in for Windows Mobile (not sure about Desktop Windows 10) are MUCH larger than they render on the other two platforms iOS and Android. The fix I have found a for this is to put a numeric font size with a decimal point in it (for example 24.1 for Large font size) in UWP apps. This works great. What I would like not is to define a static resource in my App.xaml that will work for all platforms. What I tried, that obviously does not work, is the following:
<OnPlatform x:Key="CustLarge" x:TypeArguments="x:Double">
<On Platform="iOS|Android">Large</On>
<On Platform="UWP">24.1</On>
</OnPlatform>
The theory is that in my XAML I would simply code all my large font sizes as "CustLarge" like this:
FontSize = "{StaticResource CustLarge}" />
Any ideas how I can accomplish this without doing on OnPlatform for every FontSize in my app? Any help would be appreciated.
UPDATE: Below are screen shots of what I am talking about. The iOS emulator was for the iPhone 6 4.7" wide. The Windows 10 emulator was a the 10.0.15254.9 5" phone.
You can see the Map All text is way bigger than it should be. (I am doing a relative comparison to the text in the segment control to the right of the stand alone buttons.) In both cases the fontsize is set to MICRO.
So back to my question - does anyone know how to do this?
I was able to find a workaround by creating a custom ResourceDictionnary, and adding FontSizes in the constructor.
public class SResourceDictionnary : ResourceDictionary
{
public SResourceDictionnary()
{
Add("Micro", new OnPlatform<double>
{
Default = Device.GetNamedSize(NamedSize.Micro, typeof(Label)),
Platforms = { new On
{
Value = 12d,
Platform = new List<string>{"UWP"}
}
}
});
Add("Small", new OnPlatform<double>
{
Default = Device.GetNamedSize(NamedSize.Small, typeof(Label)),
Platforms = { new On
{
Value = 14d,
Platform = new List<string>{"UWP"}
}
}
});
Add("Medium", new OnPlatform<double>
{
Default = Device.GetNamedSize(NamedSize.Medium, typeof(Label)),
Platforms = { new On
{
Value = 18d,
Platform = new List<string>{"UWP"}
}
}
});
Add("Large", new OnPlatform<double>
{
Default = Device.GetNamedSize(NamedSize.Large, typeof(Label)),
Platforms = { new On
{
Value = 20d,
Platform = new List<string>{"UWP"}
}
}
});
}
Then I merged the dictionary in my App.xaml like this
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<helpers:SResourceDictionnary></helpers:SResourceDictionnary>
</ResourceDictionary.MergedDictionaries>
<Style TargetType="Label">
<Setter Property="FontSize" Value="{StaticResource Small}" ></Setter>
</Style>
</ResourceDictionary>
</Application.Resources>
It allowed me to use FontSize as StaticResource.
The only disadvantage is that you lose intellisense in Xaml
I have added fontawesome in my projects of Xamarin.Forms, on UWP font looks as expected but on android it is square. I have set build-action to AndroidAsset but it does not work.
On Android, it's a bit of a hassle use FontAwesome. This code behind post is about how to use Font Awesome in the simplest way possible. It's as easy as using a Label once set up.
We use a custom renderer that looks at the Label in question, determines if there is one character in the text field and if that character has the value of 0xf000 or higher. If so, we replace the font with FontAwesome.
Since the icons all begin at 0xf000 or higher, the custom renderer will make sure that the correct font is used
Reference article
[assembly: ExportRenderer(typeof(Label), typeof(AwesomeRenderer))]
namespace Awesome.Droid
{
public class AwesomeRenderer : LabelRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
{
base.OnElementChanged(e);
var label = (TextView)Control;
var text = label.Text;
if(text.Length > 1 || text[0] < 0xf000)
{
return;
}
var font = Typeface.CreateFromAsset(Xamarin.Forms.Forms.Context.ApplicationContext.Assets, "fontawesome.ttf");
label.Typeface = font;
}
}
}
I got some strange black magic going on with my app.
I have defined an ImageBrush in a style dictionary:
<classes:MultiResImageChooser x:Key="MultiResImageChooser"/>
<ImageBrush x:Name="SplashScreenImageBrush"
ImageSource="{Binding SplashScreenResolutionImage, Source={StaticResource MultiResImageChooser}}"
Stretch="Fill" />`
The MultiResImageChooser class has a one simple property:
public class MultiResImageChooser
{
public BitmapImage SplashScreenResolutionImage
{
get
{
switch (ResolutionHelper.CurrentResolution)
{
case Resolutions.HD720p:
return new BitmapImage(new Uri("/Images/SplashScreenImage.Screen-720p.jpg", UriKind.Relative));
case Resolutions.WXGA:
return new BitmapImage(new Uri("/Images/SplashScreenImage.Screen-WXGA.jpg", UriKind.Relative));
case Resolutions.WVGA:
return new BitmapImage(new Uri("/Images/SplashScreenImage.Screen-WVGA.jpg", UriKind.Relative));
default:
throw new InvalidOperationException("Unknown resolution type");
}
}
}
}
SplashScreenImageBrush is binded to the background property of a Border element:
<Border x:Name="SplashScreen"
Background="{StaticResource SplashScreenImageBrush}"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" />
So, the problem is that when I debug the application on an WP8 emulator or WP8 device everything works fine.
When launching the app without debugging, the Border background property is rendered White.
The image files are included in the project and have the Build Action set to Content.
Also, if I set the ImageSource directly to an image path, everything works.
So, the problem seems to be the MultiResImageChooser, but I do not know what could be wrong with it.
Any kind of help or hints will be greatly appreciated.
BTW, this issue does not get reproduced on w WP7.1 device and emulator.
My bet: ResolutionHelper.CurrentResolution doesn't work properly for some reason (timing issue?), so the "default" branch of your switch is executed. Your binding therefore fails, the brush doesn't get initialized, and you get a white color instead. From there, I'd start by confirming the execution of the "default" branch, for instance by putting a specific image instead of throwing an exception. Then, if my theory is right, look into the ResolutionHelper to understand what's going on.