I made a Xamarin.Forms project and I referenced my own font and then added an alias in the assembly like so:
[assembly: ExportFont("Samantha.ttf", Alias = "MyAwesomeCustomFont")]
Now... the thing is, this font which I have referenced is NOT being shown in the designer, instead I'm still getting the default font, even after referencing it:
<Button WidthRequest="70" Text="Click me" FontFamily="MyAwesomeCustomFont"/>
Now, this is frustrating because it is working when I deploy it and it showing the font
although I want the designer to illustrate exactly what's going on, so I do want the custom font to be shown in the designer... Is this possible?
Thanks,
I've solved my own problem. I created a custom renderer and it's showing in the preview:
[assembly: ExportRenderer(typeof(Xamarin.Forms.Button), typeof(CustomButtonRenderer))]
namespace Custombutton.Droid
{
class CustomButtonRenderer : ButtonRenderer
{
public CustomButtonRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Button> e)
{
base.OnElementChanged(e);
if (Control != null)
{
Control.SetAllCaps(false);
Typeface tf = Typeface.CreateFromAsset(Android.App.Application.Context.Assets, "NUNITO-BOLD.ttf");
Control.SetTypeface(tf, TypefaceStyle.Bold);
}
}
}
}
Result in designer:
Related
My Problem:
I use Shell with bottom Tabbar and I simply want to change it height on Android and maybe on iOS.
My Search Results:
I know that the Tabbar is an Android/iOS build in feature with solid specified height.
There seems to be a way to achieve that using a "Custom-Renderer". All projects I have found with this approach don't work with my visual studio (>100 Errors or simply does nothing).
I find it hard to believe that i need >100 rows of code to "only" adjust a height. Could someone provide a working solution to change the Shell Tabbar (bottom tabs) height ?
Edit
Unfourtounately you need to create a custom renderer on each platform project:
Android
MyShellRenderer class
[assembly: ExportRenderer(typeof(App.AppShell), typeof(App.Droid.MyShellRenderer))]
namespace App.Droid
{
public class MyShellRenderer : ShellRenderer
{
public MyShellRenderer(Context context) : base(context)
{
}
protected override IShellBottomNavViewAppearanceTracker CreateBottomNavViewAppearanceTracker(ShellItem shellItem)
{
return new MyBottomNavViewAppearanceTracker(this, shellItem);
}
}
}
MyBottomNavViewAppearanceTracker class
class MyBottomNavViewAppearanceTracker : ShellBottomNavViewAppearanceTracker
{
public MyBottomNavViewAppearanceTracker(IShellContext shellContext, ShellItem shellItem) : base(shellContext, shellItem)
{
}
public override void SetAppearance(BottomNavigationView bottomView, IShellAppearanceElement appearance)
{
bottomView.LayoutParameters.Height = 400;
base.SetAppearance(bottomView, appearance);
}
}
Edit:
iOS part credit goes to https://forums.xamarin.com/discussion/169894/how-to-change-shell-height-of-flyout-items-at-the-bottom-of-the-page
iOS
MyShellRenderer class
[assembly: ExportRenderer(typeof(App.AppShell), typeof(App.iOS.MyShellRenderer))]
namespace App.iOS
{
public class MyShellRenderer : ShellRenderer
{
protected override IShellTabBarAppearanceTracker CreateTabBarAppearanceTracker()
{
return new MyCreateTabBarAppearanceTracker();
}
}
}
CreateTabBarAppearanceTracker class
class CreateTabBarAppearanceTracker : ShellTabBarAppearanceTracker
{
public override void SetAppearance(UITabBarController controller, ShellAppearance appearance)
{
UITabBar tabBar = controller.TabBar;
int tabBarHeight = 100;
if (tabBar.Frame.Height != tabBarHeight)
{
tabBar.Frame = new CGRect(tabBar.Frame.X, tabBar.Frame.Y + (tabBar.Frame.Height - tabBarHeight), tabBar.Frame.Width, tabBarHeight);
}
}
}
Extras
You were probably missing some namespaces that would explains the abnormal big number of errors.
could not be found are you missing a using directive or an assembly reference
Usually people don't include namespaces (using statements) in answers because most of the time namespaces are obvious and are handled easily by visual studio intellisense.
Just put or hover the cursor on the red underlined statement and a small tooltip appears
Then click on "Show potential fix" or one of the keyboard shortcuts, select the appropriate fix (usually the first one of the suggested list), in this case intelisense will add the required namespace automatically.
Every Code example i have found has excluded the using directives. in my case i needed those following 3 which i wasnt able to find. Thanks to the answer of #Cfun the code above work with adding:
using Google.Android.Material.BottomNavigation;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
I am learning C# and Xamarin.Forms at the moment, so please treat me like a complete beginner.
I have an entry in my XML in Xamarin.Forms:
<Entry x:Name="temperature" Placeholder="Temperatur" Keyboard="Numeric" Margin="20,0"/>
In my CS:
double temp = double.Parse(temperature.Text);
This all works fine. But I need to use a different kind of entry for Android. Because Xamarin.Forms Entry do not handle decimal separators very well when it comes to Samsung phones.
On Android I want to use NuGet "NumericEditText-Xamarin.Android" like this:
<br.com.akamud.NumericEditText
android:id="#+id/txtNumeric"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="number|numberDecimal" />
It should handle my entry input, and then of course handle the entry after that with the shared code of Xamarin.Forms. Is dependency service the best way to go about solving this?
Would someone be so kind to help me out in the right direction.
Dependency service is used to invoke native api on specific project, if the issue is related to UI, a custom renderer is the better choice.
You need to create a custom renderer for a custom view, and replace the view with NumericEditText inside the custom renderer.
Create Custom View
public class EntryView : View
{
}
Usage of Custom view in page
xmlns:local ="clr-namespace:App2"
<local:EntryView/>
Custom renderer
[assembly: ExportRenderer(typeof(EntryView), typeof(MyRenderer))]
namespace App2.Droid
{
public class MyRenderer : Xamarin.Forms.Platform.Android.ViewRenderer<EntryView, NumericEditText>
{
Context _context;
NumericEditText editView;
public MyRenderer(Context context) : base(context)
{
_context = context;
}
protected override void OnElementChanged(ElementChangedEventArgs<EntryView> e)
{
base.OnElementChanged(e);
if(e.NewElement != null)
{
if (Control == null)
{
editView = new NumericEditText(Context);
editView.InputType = InputTypes.NumberFlagDecimal|InputTypes.ClassNumber;
SetNativeControl(editView);
}
}
}
}
}
Refer to https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/custom-renderer/view.
So I am working on Android application. Right now I am creating MainPage where I insert Entry which has the bottom line as always. The bottom line on my previewer is White while on my phone it appears to be Black.
So to fix the issue I decided to play with renderers and see if I can fix it.
I created Class in App called CustomEntryRenderer which inherits from Entry.
Then I created Class in App.Android called CustomEntryRednererAndroid which is supposed to change the color of bottom entry line. But it doesn`t affect it. I tried doing the same with some custom renderers I found on the internet.
For example deleting bottom line didn`t affect the program as well:
removing line
Entry from MainPage.xaml:
<Entry
Grid.Row="4"
Grid.ColumnSpan="2"
TextColor="Silver"
Placeholder="Write Your nickname"
PlaceholderColor="Silver"
/>
CustomEntryRenderer:
public class CustomEntryRenderer : Entry
{
}
CustomEntryRendererAndroid:
[assembly: ExportRenderer(typeof(CustomEntryRenderer), typeof(MyEntryRenderer))]
namespace App3.Droid
{
public class MyEntryRenderer : EntryRenderer
{
public MyEntryRenderer(Context context) : base(context) { }
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if (Control == null || e.NewElement == null) return;
if (Build.VERSION.SdkInt >= BuildVersionCodes.Lollipop)
Control.BackgroundTintList = ColorStateList.ValueOf(Android.Graphics.Color.White);
else
Control.Background.SetColorFilter(Android.Graphics.Color.White, PorterDuff.Mode.SrcAtop);
}
}
}
Top answer for Android
And for some reason also in CustomEntryRendererAndroid.cs I had to use Android.Graphic instead of Xamarin.Forms.Color. But I dont think that is the issue.
I have been trying for a couple of hours now and can`t find the way out of this situation.
Would appreciate any ideas.
In xaml you are using the default Entry control and not your CustomEntryRenderer which is what your renderer is affecting. Also, you might want to rename it because it is not actually your renderer, but your custom control.
To resolve your issue you can either change your renderer typeof(CustomEntryRenderer) to typeof(Entry) to affect all Android entries in your app by default. For example, this worked for my test app for all Entries:
[assembly: ExportRenderer(typeof(Entry), typeof(MyEntryRenderer))]
namespace YourNameSpace
{
public class MyEntryRenderer : EntryRenderer
{
public MyEntryRenderer(Context context) : base(context) { }
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if (Control == null || e.NewElement == null) return;
if (Build.VERSION.SdkInt >= BuildVersionCodes.Lollipop)
Control.BackgroundTintList = ColorStateList.ValueOf(Android.Graphics.Color.White);
else
Control.Background.SetColorFilter(Android.Graphics.Color.White, PorterDuff.Mode.SrcAtop);
}
}
}
The other option is to switch your xaml code in MainPage to actually use your custom control. For example, <local:CustomEntryRenderer/>
Adding this in the Styles.xml repairs it globally
<item name="colorControlNormal">#1BB8A3</item>"
Today I updated to Xamarin.Forms 2.5.0 and saw, that I get the following warnings:
From the Android sub-project:
Warning CS0618 'Forms.Context' is obsolete: 'Context is obsolete as of version 2.5. Please use a local context instead.'
How can I get the local context instead of Forms.Context? Is the Android Context meant?
From the custom renderer:
Warning CS0618 'ButtonRenderer.ButtonRenderer()' is obsolete: 'This constructor is obsolete as of version 2.5. Please use ButtonRenderer(Context) instead.'
In my ButtonRenderer I only have the OnElementChanged() method, so what should I change here? Simply add a ButtonRenderer(Context) constructor? I still get the warning, if I do this in my platform renderer class. Does anyone have an example? The official documentation doesn't mention it and Google also doesn't bring some useful results, except the open source code of ButtonRenderer. This change also concerns many other renderer classes.
Does anyone had experienced other changes, which brakes plugins and so on?
PS: Also I didn't found out, when Device.Windows was deprecated. Now I replaced it with Device.UWP.
I had this same issue for a SearchBarRenderer and all I needed to do to fix it was add a constructor like so:
public ShowSearchBarRenderer(Context context) : base(context)
{
}
Hope that answers the second part of your question.
There are two questions here:
How do I update Custom Renderers to use a local context?
How can I access the current context now that Xamarin.Forms.Forms.Context is obsolete?
How to Update Custom Renderers
Add the overloaded Constructor to each custom renderer
Here is an example using a ButtonRenderer
[assembly: ExportRenderer(typeof(CustomButton), typeof(CustomButtonRenderer))]
namespace MyApp.Droid
{
public class CustomButtonRenderer : ButtonRenderer
{
public CustomButtonRenderer(Context context) : base(context)
{
}
protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
//ToDo: Customize Button
}
}
}
How to Access The Current Context
Install Xamarin.Essentials NugGet Package.
Now, you can call Xamarin.Essentials.Platform.AppContext when you need to access the current activity.
Here's an example of how to open the App's Settings in Xamarin.Forms.
[assembly: Dependency(typeof(DeepLinks_Android))]
namespace MyApp.Droid
{
public class DeepLinks_Android : IDeepLinks
{
Context CurrentContext => Xamarin.Essentials.Platform.AppContext;
public Task OpenSettings()
{
var myAppSettingsIntent = new Intent(Settings.ActionApplicationDetailsSettings, Android.Net.Uri.Parse("package:" + CurrentContext.PackageName));
myAppSettingsIntent.AddCategory(Intent.CategoryDefault);
return Task.Run(() =>
{
try
{
CurrentContext.StartActivity(myAppSettingsIntent);
}
catch (Exception)
{
Toast.MakeText(CurrentContext.ApplicationContext, "Unable to open Settings", ToastLength.Short);
}
});
}
}
}
use Android.App.Application.Context
There is a discussion of this topic on the Forums
I'm trying to open a settings view in a Caliburn.Micro WinRT 8.1 app using VS2013 RC, but I keep getting an unhandled exception when opening it with the following message:
Value cannot be null. Parameter name: Could not parse the VisualElements from the app manifest.
I can reproduce the issues with the following steps:
create a new Windows Store app from VS2013 RC using the Blank app template.
add Caliburn.Micro via NuGet.
in App.xaml, change the base class to caliburn:CaliburnApplication (the namespace is declared as xmlns:caliburn="using:Caliburn.Micro").
in App.xaml.cs, change the class like this (for the CM-based settings I follow http://compiledexperience.com/blog/posts/settings-caliburn)
Code below:
public sealed partial class App
{
private WinRTContainer _container;
public App()
{
InitializeComponent();
}
protected override void Configure()
{
_container = new WinRTContainer();
_container.RegisterWinRTServices();
_container.PerRequest<MainViewModel>();
_container.PerRequest<SettingsViewModel>();
ISettingsService settings = _container.RegisterSettingsService();
settings.RegisterCommand<SettingsViewModel>("Test settings");
}
protected override object GetInstance(Type service, string key)
{
var instance = _container.GetInstance(service, key);
if (instance != null) return instance;
throw new Exception("Could not locate any instances.");
}
protected override IEnumerable<object> GetAllInstances(Type service)
{
return _container.GetAllInstances(service);
}
protected override void BuildUp(object instance)
{
_container.BuildUp(instance);
}
protected override void PrepareViewFirst(Frame rootFrame)
{
_container.RegisterNavigationService(rootFrame);
}
protected override void OnLaunched(LaunchActivatedEventArgs args)
{
DisplayRootView<MainView>();
}
}
Finally, create folders for Views and ViewModels in the solution add add to them the required items: MainViewModel, SettingsViewModel, MainView, SettingsView. The views just include a TextBlock with some text. MainViewModel derives from Screen, while SettingsViewModel derives from PropertyChangedBase. There is no relevant code in any of them.
When launching the app, I can see the main view; then I open the charms bar and click settings, and I find the label leading to my app settings; when I click it, I get the exception quoted above. Any hint?
You can find a full repro solution here: http://sdrv.ms/18GIMvB .
If you aren't ready to move to the alpha version of CM, you can update Callisto to 1.4.0 via NuGet. That fixed the error for me.
It seems that the new CM release (alpha 2) fixed the issue, so I'm adding some more information here to help other newcomers like me. Here is what I'm doing now:
In app's Configure I have some bootstrap code like:
...
ResourceLoader loader = ResourceLoader.GetForViewIndependentUse("Resources");
ISettingsService settings = _container.RegisterSettingsService();
settings.RegisterFlyoutCommand<ContentSettingsViewModel>(loader.GetString("SettingsContent"));
The ContentSettingsViewModel is a viewmodel for filtering some contents. The string got from resources is the label which will appear in the settings flyout (be sure there is an entry for this string, as passing an empty or null string triggers an exception). This VM is derived from CM Screen as I'm overriding OnActivate and OnDeactivate to load and save settings when the user opens or dismisses the settings page.