Xamarin Form - Add png icon in toolbar with color - xamarin

This is my code
ToolbarItems.Add(new ToolbarItem("User", "userAvatar.png", async () => {
await Navigation.PopToRootAsync();
}));
It's not working. It's place a masked single color image instead a png in colors.
I'm trying to archive something like this...
Any clue ?

I was going mad about this issue once, too (my situation was a bit more subtle, I had a plain and a colored verion of the icon and was wondering why the heck the colored icon would not be loaded) and unfortunately it's not that easy to overcome.
The icons being monochrome is the default behavior for iOS apps and Xamarin.Forms implements this behavior. According to this post you'll need a custom renderer to show colored icons in the navigation bar.
Edit
According to this post, you'll have to set the UIImageRenderingMode for the respective images in your custom renderer
image = image.ImageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal);
using the renderer implementation from this answer, it should be something in the line of
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
[assembly: ExportRenderer(typeof(TabbedPage), typeof(MyProject.iOS.Renderers.IosMainMenuRenderer))]
namespace MyProject.iOS.Renderers {
public class IosMainMenuRenderer : TabbedRenderer {
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
var items = TabBar.Items;
for (var i = 0; i < items.Length; i++) {
items[i].Image = items[i].ImageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal);
items[i].SelectedImage = items[i].SelectedImage.ImageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal);
}
}
}
}
but I have not tested this!

For a color logo on the right on all my navigation pages I used this custom renderer:
[assembly: ExportRenderer(typeof(CustomNavigationPage), typeof(CustomNavigationRenderer))]
namespace App.iOS
{
public class CustomNavigationRenderer : NavigationRenderer
{
public override void ViewDidLayoutSubviews()
{
base.ViewDidLayoutSubviews();
var logo = NavigationBar.TopItem.RightBarButtonItem.Image;
if (logo == null) return;
if (logo.RenderingMode == UIImageRenderingMode.AlwaysOriginal)
{
return;
}
NavigationBar.TopItem.RightBarButtonItem.Image = logo.ImageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal);
}
}
}

The easiest way is to not use a toolbar, instead, set the type of this page as a Modal when navigating to it(Using Navigation.PushModal()). And add a horizontal LinearLayout that will act as the toolbar.

Related

Xamarin iOS ToolbarItem Image showing white image

Xamarin Forms IconImageSource:
On Android Toolbar image is shown correctly, on iOS a white image is shown. How can I fix this?
I added file to Resources folder and set build Action to BundleResource.
If I change filename to non excisting file, image is not shown at all. I tried changing extension to JPG, same result, also a white image is shown.
I used this code snippit.
ToolbarItem toolbarItemSearch = new ToolbarItem { IconImageSource = ImageSource.FromFile("searchIcon.png") };
ToolbarItems.Add(toolbarItemSearch);
iOS has tinting the ToolbarItems by default , the color is blue/white .
To solve it we need to create a custom renderer for NavigationPage , and set the TintColor to transparent , and set the image with another rendering mode .
Sample code
[assembly: ExportRenderer(typeof(NavigationPage), typeof(MyRenderer))]
namespace FormsApp.iOS
{
class MyRenderer : NavigationRenderer
{
public override void PushViewController(UIViewController viewController, bool animated)
{
base.PushViewController(viewController, animated);
var currentPage = (this.Element as Xamarin.Forms.NavigationPage)?.CurrentPage;
if (this.NavigationBar == null || currentPage == null)
return;
var buttonItems = TopViewController.NavigationItem.RightBarButtonItems;
foreach (var button in buttonItems)
{
if(button.Image != null){
button.Image = button.Image.ImageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal);
button.TintColor = UIColor.Clear;
}
}
}
}
}
Refer to
Image in Toolbar item on iOS are white(Xamarin Forms)
The solution from #ColeX - MSFT did the trick! Additionally make sure to do a null pointer check for non Image buttons.

Xamarin: detect page pushed on NavigationRenderer

I order to apply some navigationBar properties (like as the background image) for different page, I think to have a condition on my custom NavigationRenderer.
My idea is to have some condition like (in my working code)
public class CustomNavigationRenderer : NavigationRenderer
{
public override void ViewDidLoad()
{
base.ViewDidLoad();
if (pagePushed is 1)
{
NavigationBar.SetBackgroundImage(new UIImage(), UIBarMetrics.Default);
NavigationBar.ShadowImage = new UIImage();
}
else (ahother page){
var img = UIImage.FromBundle("MyImage");
NavigationBar.SetBackgroundImage(img, UIBarMetrics.Default);
}
}
}
that allows me to have at least a condition to apply a different navigation properties. Another way is to have 2 Navigationrenderer class but I think is not possible.
Any idea to how do that?
If you look at the source code for NavigationRenderer here, you will notice there are quite a few methods and callbacks you can take advantage of.
I would suggest you can do something like this:
1) Code for your custom NavigationRenderer (iOS project, you will have to do something similar on Android):
using System.Threading.Tasks;
using MyProject.iOS;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
[assembly: ExportRenderer(typeof(NavigationPage), typeof(NavRenderer))]
namespace MyProject.iOS
{
public class NavRenderer : NavigationRenderer
{
protected override async Task<bool> OnPushAsync(Page page, bool animated)
{
var result = await base.OnPushAsync(page, animated);
if(result)
{
if (page is IMyPageType1)
{
NavigationBar.SetBackgroundImage(new UIImage(), UIBarMetrics.Default);
NavigationBar.ShadowImage = new UIImage();
}
else if(page is IMyPageType2)
{
var img = UIImage.FromBundle("MyImage");
NavigationBar.SetBackgroundImage(img, UIBarMetrics.Default);
}
}
return result;
}
}
}
2) Based on the code above, you need to add two interfaces. These should be located in the same project / dll where your Pages are located (all your Xamarin.Forms UI):
public interface IMyPageType1
{
}
public interface IMyPageType2
{
}
3) Now everything that's remaining is implement the interfaces on the pages where you need it. For example:
public partial class MyPage1 : ContentPage, IMyPageType1
{
//...
}
From here, possibilities are endless! You can add for example a method to IMyPageType1 that would return a color, and then inside your renderer, once you know the page being pushed is implementing IMyPageType1, you can call the method and get the color to use.

How to reduce padding between the icon and text in xamarin button

I have created a button in my xamarin application and have added an icon to it but there is too much of padding between the icon and the text as shown in the screenshot below.
How can I reduce this space between the two?
I have learnt about the custom renders for Xamarin.Android but its not working for me.
Following is the code for my custom renderer
[assembly: ExportRenderer(typeof(Button), typeof(ZeroPaddingRenderer))]
namespace MyApp.Droid
{
class ZeroPaddingRenderer : ButtonRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Button> e)
{
base.OnElementChanged(e);
Control.SetPadding(0, Control.PaddingTop, 0, Control.PaddingBottom);
}
}
}
Here is the code for button
Button btn_login = new Button
{
VerticalOptions = LayoutOptions.Center,
Text = "Login",
};
btn_login.Image = "login.png";
Any help will be appreciated.

Change EditText Cursor Color in Xamarin Forms

I have an Entry in my ContentPage and am doing rendering in Xamarin Android.
Here my problem is EditText background color is white and cursor color is also white.
Here I want to change the cursor color to black.
Is there any way to change the cursor color?
Here is my code.
Entry to ExtendedEntry :
public class ExtendedEntry : Entry { }
Use ExtendedEntry in Content Page :
var txtPhoneNumber = new ExtendedEntry { Placeholder = "Phone Number", Keyboard = Keyboard.Numeric, TextColor = Color.Black };
Render the ExtendedEntry in Xamarin Android :
using Xamarin.Forms.Platform.Android;
using Xamarin.Forms;
[assembly: ExportRenderer(typeof(ExtendedEntry), typeof(ExtendedEntryRender))]
namespace Project.Droid
{
public class ExtendedEntryRender : EntryRenderer
{
// Override the OnElementChanged method so we can tweak this renderer post-initial setup
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if (e.OldElement == null)
{ // perform initial setup
// lets get a reference to the native control
var nativeEditText = (global::Android.Widget.EditText)Control;
// do whatever you want to the textField here!
nativeEditText.SetBackgroundResource(Resource.Drawable.text_box);
}
}
}
}
Can any one help me to solve this problem?
Thanks in advance.
You can change the cursor color using:
IntPtr IntPtrtextViewClass = JNIEnv.FindClass(typeof(TextView));
IntPtr mCursorDrawableResProperty = JNIEnv.GetFieldID (IntPtrtextViewClass, "mCursorDrawableRes", "I");
JNIEnv.SetField (Control.Handle, mCursorDrawableResProperty, 0); // replace 0 with a Resource.Drawable.my_cursor
0 will keep the same color as the TextColor on your Entry.
Edit: To change the cursur color the only option is to change the theme by adding for example:
Theme = "android:style/Theme.Holo.light" in MainActivity

How can a scroll a specific row or section to the top of a Xamarin.Forms.ListView

I have a Xamarin.Forms.ListView that contains events that are grouped by date. There are events that occur in future and events that occur in the past.
Users would like to have their screen load with a future event closest to the current date in view so that they do not need to manually scroll down to view it.
What options do I have with a Xamarin.Forms.ListView to accomplish this for iOS and Android users?
I have made some progress. I am able to accomplish my goal in iOS by creating a CustomListView and an iOS render to support it.
In Xamarin.Forms you create a CustomListView then after you have loaded the list you an call ScrollToRow(item,section) to manually scroll to the row you need.
In iOS the renderer maps the method to UITableView message ScrollToRow(...);
For Android I still need to create the renderer but I do know that I need to map to the calls getListView().setSelection(...); or getListView().smoothScrollToPosition(...);
I am sure there is a more elegant way to do this but for now it is getting the job done
Source For: Common.CustomListView
using System;
using Xamarin.Forms;
namespace Common {
public class CustomListView : ListView {
public Action<int, int, bool> ScrollToRowDelegate { get; set; }
public void ScrollToRow(int itemIndex, int sectionIndex = 0, bool animated = false) {
if (ScrollToRowDelegate != null) {
ScrollToRowDelegate (itemIndex, sectionIndex, animated);
}
}
}
}
iOS Renderer Source:YourApplication.iOS.Renderers.CustomListViewRenderer
using System;
using Xamarin.Forms.Platform.iOS;
using Xamarin.Forms;
using Common;
using MonoTouch.UIKit;
using MonoTouch.Foundation;
using YourApplication.iOS.Renderers;
[assembly: ExportRenderer (typeof(CustomListView), typeof(CustomListViewRenderer))]
namespace YourApplication.iOS.Renderers
{
public class CustomListViewRenderer : ListViewRenderer
{
protected override void OnModelSet (VisualElement view) {
base.OnModelSet (view);
var listView = view as CustomListView;
listView.ScrollToRowDelegate = (itemIndex, sectionIndex, animated) => {
ScrollToRow(itemIndex, sectionIndex, animated);
};
}
private void ScrollToRow(int itemIndex, int sectionIndex, bool animated) {
var tableView = this.Control as UITableView;
var indexPath = NSIndexPath.FromItemSection (itemIndex, sectionIndex);
tableView.ScrollToRow (indexPath, UITableViewScrollPosition.Top, animated);
}
}
}

Resources