Xamarin.Forms custom Android NavigationPageRenderer title and subtitle - xamarin

Currently working on a project where I want to use AppCompat and have a requirement setting title and subtitle on most of the pages.
It doesn't work using AppCompat at all - neither setting the properties nor using a custom view.
When not using AppCompat both works as expected. The full source code is available here so just run the app if you're curious :)
using System.ComponentModel;
using Android.App;
using Android.Widget;
using App1.Droid.Renderers;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
#if __APPCOMPAT__
using NavigationRenderer = Xamarin.Forms.Platform.Android.AppCompat.NavigationPageRenderer;
#else
using NavigationRenderer = Xamarin.Forms.Platform.Android.NavigationRenderer;
#endif
[assembly: ExportRenderer(typeof(NavigationPage), typeof(NavigationPageRenderer))]
namespace App1.Droid.Renderers
{
public class NavigationPageRenderer : NavigationRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<NavigationPage> e)
{
base.OnElementChanged(e);
SetCustomView(e.NewElement.CurrentPage.GetType().Name);
}
private void SetCustomView(string view)
{
var activity = (Activity)Context;
#if __APPCOMPAT__
var actionBar = ((FormsAppCompatActivity)Context).SupportActionBar;
#else
var actionBar = activity.ActionBar;
#endif
actionBar.Title = view;
actionBar.Subtitle = " -> " + view;
var abv = new LinearLayout(activity)
{
Orientation = Orientation.Vertical
};
var main = new TextView(activity)
{
Text = view,
};
main.SetTextColor(Color.Aqua.ToAndroid());
main.SetPadding(4, 4, 2, 6);
abv.AddView(main);
abv.AddView(new TextView(activity)
{
Text = " -> " + view
});
actionBar.SetDisplayShowCustomEnabled(true);
actionBar.CustomView = abv;
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName.Equals("CurrentPage"))
{
SetCustomView(((NavigationPage)sender).CurrentPage.GetType().Name);
}
}
}
}
Edit: Thanks #jimmgarr. Altered the code slightly to keep alternating between AppCompbat and "normal mode". The code is available here

So it looks like the NavigationPage uses its own Toolbar instance. That's why setting the properties on SupportActionBar isn't doing anything.
I was able to get it working by overriding OnViewAdded() to get a reference to the new Toolbar when it's added:
public override void OnViewAdded(Android.Views.View child)
{
base.OnViewAdded(child);
if (child.GetType() == typeof(Support.Toolbar))
toolbar = (Support.Toolbar)child;
}
Then using the reference inside SetCustomView() to set only the Subtitle since the Title is already set automatically.
Here's the complete renderer class :)

Related

I want to Display Square Checkbox on IOS ,IPad in xamarin form

This Below is my IOS Page .I want to show this type of check box on iOS in xamarin form. I have use Xamarin 5.0 version. When I am try to use check element in iOS show rounded check box but I want square check box.
<CheckBox x:Name="chkRememberMe" BackgroundColor="#7E7E7E" SizeChanged="20" IsChecked="False" CheckedChanged="ChkRememberMe_OnCheckedChanged" ></CheckBox>
This is my check box code what can I do that in iOS for a square checkbox.I'm completely new to xamarin.forms, I need to add a checkbox, radio buttons and drop down list. I tried some samples from net but I'm not able to get the checkbox. Can anyone help me to achieve.Controls.Checkbox to create checkbox for ios and andorid in Xamarin Forms.Now i am getting the checkbox but i cant read the value either it is checked or not.Here is my code
You could use the plugin Xamarin.Forms.InputKit from nuget .
xmlns:input="clr-namespace:Plugin.InputKit.Shared.Controls;assembly=Plugin.InputKit"
<input:CheckBox Text="xxx" Type="Check"/>
If you want to customize the style of the checkbox , you could check https://github.com/enisn/Xamarin.Forms.InputKit/wiki/CheckBox .
If you don't want to change the check boxes on other platforms, you can use a custom renderer to only change how it looks on iOS.
Subclass the CheckBox in your shared project:
public class CustomCheckBox : CheckBox {}
And add the custom renderer to the iOS project:
using CoreGraphics;
using UIKit;
using Xamarin.Forms.Platform.iOS;
using Xamarin.Forms;
using YourApp.iOS;
using YourApp.Controls; // namespace of your CustomCheckBox
using System.ComponentModel;
[assembly: ExportRenderer(typeof(CustomCheckBox), typeof(CustomCheckBoxRenderer))]
namespace YourApp.iOS
{
public class CustomCheckBoxRenderer : ViewRenderer<CustomCheckBox, UIView>
{
private const float SideLength = 18f;
private bool firstTime = true;
protected override void OnElementChanged(ElementChangedEventArgs<CustomCheckBox> e)
{
base.OnElementChanged(e);
if (Control == null)
{
var checkBox = new UIView();
SetNativeControl(checkBox);
}
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == CustomCheckBox.IsCheckedProperty.PropertyName || firstTime)
{
SetNeedsDisplay();
}
}
public override void Draw(CGRect rect)
{
Element.Color.ToUIColor().SetStroke();
if (Element.IsChecked)
{
var checkPath = new UIBezierPath();
checkPath.MoveTo(new CGPoint(1 + .2 * SideLength, 1 + .475 * SideLength));
checkPath.AddLineTo(new CGPoint(1 + .45 * SideLength, 1 + .675 * SideLength));
checkPath.AddLineTo(new CGPoint(1 + .8 * SideLength, 1 + .275 * SideLength));
checkPath.LineWidth = 3f;
checkPath.Stroke();
}
var boxPath = UIBezierPath.FromRoundedRect(
new CGRect(1f, 1f, SideLength, SideLength), UIRectCorner.AllCorners, new CGSize(2,2));
boxPath.LineWidth = 2f;
boxPath.Stroke();
firstTime = false;
}
public override CGSize SizeThatFits(CGSize size)
{
return new CGSize(SideLength + 2, SideLength + 2);
}
}
}

Is there any way in Xamarin Forms to change the background color of a dialog box?

Here's what my dialog box looks like with a dark theme.
Does anyone know of a way that the colors could be changed in a Xamarin Forms app so that the dialog displays with white text on a dark background?
Does anyone have an idea what the problem might be?
Option 1
You could change it in specific platforms by using DependencyService
in forms
create the interface
using Xamarin.Forms;
namespace xxx
{
public interface IPopUp
{
void Popup(string title, string message,Color titleColor,Color messageColor, EventHandler handler);
}
}
in iOS
using System;
using System.Text;
using xxx.iOS;
using Foundation;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using xxx;
[assembly: Dependency(typeof(PopupImplemention))]
namespace xxx.iOS
{
public class PopupImplemention : IPopUp
{
public void Popup(string title, string message, Color titleColor, Color messageColor, EventHandler handler)
{
UIAlertController alertController = UIAlertController.Create(title,message,UIAlertControllerStyle.Alert);
var firstAttributes = new UIStringAttributes
{
ForegroundColor =titleColor.ToUIColor(),
};
var secondAttributes = new UIStringAttributes
{
ForegroundColor =messageColor.ToUIColor(),
};
alertController.SetValueForKey(new NSAttributedString(title, firstAttributes), new NSString("attributedTitle"));
alertController.SetValueForKey(new NSAttributedString(message, secondAttributes), new NSString("attributedMessage"));
UIAlertAction cancelAction = UIAlertAction.Create("Cancel",UIAlertActionStyle.Cancel,null);
UIAlertAction okAction = UIAlertAction.Create("OK", UIAlertActionStyle.Default,(sender)=> { handler?.Invoke(sender, new EventArgs()) ; });
alertController.AddAction(cancelAction);
alertController.AddAction(okAction);
var currentViewController = topViewControllerWithRootViewController(UIApplication.SharedApplication.Delegate.GetWindow().RootViewController);
currentViewController.PresentViewController(alertController,true,null);
}
UIViewController topViewControllerWithRootViewController(UIViewController rootViewController)
{
if (rootViewController is UITabBarController)
{
UITabBarController tabBarController = (UITabBarController)rootViewController;
return topViewControllerWithRootViewController(tabBarController.SelectedViewController);
}
else if (rootViewController is UINavigationController)
{
UINavigationController navigationController = (UINavigationController)rootViewController;
return topViewControllerWithRootViewController(navigationController.VisibleViewController);
}
else if (rootViewController.PresentedViewController != null)
{
UIViewController presentedViewController = rootViewController.PresentedViewController;
return topViewControllerWithRootViewController(presentedViewController);
}
else
{
return rootViewController;
}
}
}
}
in Android
in MainActivity
public static MainActivity Intance;
protected override void OnCreate(Bundle savedInstanceState)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(savedInstanceState);
Intance = this;
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App());
}
using Xamarin.Forms;
using xxx;
using xxx.Droid;
using Android;
using System;
using Xamarin.Forms.Platform.Android;
using Android.Support.V7.App;
using Android.Text;
[assembly: Dependency(typeof(PopupImplemention))]
namespace xxx.Droid
{
public class PopupImplemention : IPopUp
{
public void Popup(string title, string message, Color titleColor, Color messageColor, EventHandler handler)
{
// because html.string could not support format string , so you need to set the color directly in the string with a static value
Android.Support.V7.App.AlertDialog.Builder alert = new Android.Support.V7.App.AlertDialog.Builder(MainActivity.Intance);
alert.SetTitle(Html.FromHtml(string.Format("<font color='#ff0000'>{0}</font>" ,title),FromHtmlOptions.ModeLegacy));
alert.SetMessage(Html.FromHtml(string.Format("<font color='#00ff00'>{0}</font>", message), FromHtmlOptions.ModeLegacy));
alert.SetPositiveButton("OK", (senderAlert, args) =>
{
handler?.Invoke(senderAlert, args);
});
alert.SetNegativeButton("Cancel", (senderAlert, args) =>
{
});
Android.Support.V7.App.AlertDialog dialog = alert.Create();
dialog.Show();
}
}
}
And call it in forms
DependencyService.Get<IPopUp>().Popup("Title","xxxxxxxxxxxx",Color.Red,Color.Blue,(sen,args)=> {
// handle the logic when clikc the OK button
});
Option 2
You could use the plugin Rg.Plugins.Popup ,which allows to open Xamarin.Forms pages as a popup that can be shared across iOS, Android and UWP . And you can customize it as you want .

How can I change the Font Size and Weight for the Header in a Navigation Page?

I can change the Font Color like this:
var homePage = new NavigationPage(new HomePage())
{
Title = "Home",
Icon = "ionicons_2_0_1_home_outline_25.png",
BarTextColor = Color.Gray,
};
But is there a way to change the Font Size and Weight for the Title? I would like to change it for the iOS and Android platforms only. Hoping that someone knows of Custom Renderer code that can help me to do this.
Note that this question is similar to my question on how to change the Font which has been answered here:
How can I change the font for the header of a Navigation page with Xamarin Forms?
Here is an Custom Renderer for Android where you are able to change the Font Size and also the Font Weight. I've marked the values you have to change with an TODO.
using Android.Content;
using Android.Graphics;
using App5.Droid;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android.AppCompat;
[assembly: ExportRenderer(typeof(NavigationPage), typeof(CustomNavigationPageRenderer))]
namespace App5.Droid
{
public class CustomNavigationPageRenderer : NavigationPageRenderer
{
private Android.Support.V7.Widget.Toolbar _toolbar;
public CustomNavigationPageRenderer(Context context) : base(context)
{
}
public override void OnViewAdded(Android.Views.View child)
{
base.OnViewAdded(child);
if (child.GetType() == typeof(Android.Support.V7.Widget.Toolbar))
{
_toolbar = (Android.Support.V7.Widget.Toolbar)child;
_toolbar.ChildViewAdded += Toolbar_ChildViewAdded;
}
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
_toolbar.ChildViewAdded -= Toolbar_ChildViewAdded;
}
}
private void Toolbar_ChildViewAdded(object sender, ChildViewAddedEventArgs e)
{
var view = e.Child.GetType();
System.Diagnostics.Debug.WriteLine(view);
if (e.Child.GetType() == typeof(Android.Support.V7.Widget.AppCompatTextView))
{
var textView = (Android.Support.V7.Widget.AppCompatTextView)e.Child;
// TODO: CHANGE VALUES HERE
textView.TextSize = 25;
textView.SetTypeface(null, TypefaceStyle.Bold);
_toolbar.ChildViewAdded -= Toolbar_ChildViewAdded;
}
}
}
}
Here is an implementation of a Custom Renderer for iOS.
using App5.iOS;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
[assembly: ExportRenderer(typeof(NavigationPage), typeof(CustomNavigationPageRenderer))]
namespace App5.iOS
{
public class CustomNavigationPageRenderer : NavigationRenderer
{
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
var att = new UITextAttributes();
// TODO: Create your FontSize and FontWeight here
var fontSize = Font.SystemFontOfSize(30.0);
var boldFontSize = Font.SystemFontOfSize(35.0, FontAttributes.Bold);
// TODO: Apply your selected FontSize and FontWeight combination here
att.Font = boldFontSize.ToUIFont();
UINavigationBar.Appearance.SetTitleTextAttributes(att);
}
}
}
}

I want to add my own image to switch Control in ios using Xamarin forms

I tried to add my own image to switch Control in xamarin forms using rendering concept but i am unable to override the existing image.Below is my code.
In shared project i added code like this
Switch switcher = new ExtendedSwitchnew();
and in ios
[assembly: ExportRenderer(typeof(ExtendedSwitchnew),typeof(SwitchRenderernew))]
namespace test.iOS
{
public class SwitchRenderernew :SwitchRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Switch> e)
{
base.OnElementChanged(e);
if (Control != null)
{
UIImage imgon = UIImage.FromFile("Images/switchon.png");
UIImage imgoff = UIImage.FromFile("Images/switchoff.png");
Control.OnImage = imgon;
Control.OffImage = imgoff;
}
}
}
}
Help me.Thanks in advace.

How to use Android AutoCompleteTextView on Xamarin.Forms

I'm working on a Xamarin.forms project but i need to use Android.Widget.AutoCompleteTextView how can i apply that?
When i am trying to add AutoCompleteTextView UserNameAutoComplete; to ContentPage i get the following error:
Content = new StackLayout
{
VerticalOptions = LayoutOptions.Center,
Padding = new Thickness(25),
Children =
{
UserNameAutoComplete,
passwordEditor,
}
};
cannot convert from 'Android.Widget.AutoCompleteTextView' to
'Xamarin.Forms.View'
Android.Widget.AutoCompleteTextView is a View from Android.
Solution for PCL:
You can't use platform specific View's on Xamarin Forms (PCL) ContentPage.
To use platform specific View you should use a custom render.
There is a blog post from #JamesMontemagno that shows how to do what you need.
This code is draft exemple please use it as such.
1 - Create your own custom Xamarin.Forms control that will be renderered in Android as an AutoCompleteTextView:
public class AutoCompleteView : View
{
// Place need properties here.
}
2 - In Android project add a renderer for AutoCompleteView:
[assembly: ExportRenderer(typeof(AutoCompleteView), typeof(AutoCompleteViewRenderer))]
namespace App.Droid
{
public class AutoCompleteViewRenderer : ViewRenderer<AutoCompleteView, AutoCompleteTextView>
{
// Initialize the AutoCompleteTextView
protected override void OnElementChanged (ElementChangedEventArgs<AutoComplete> e)
{
base.OnElementChanged (e);
if (e.OldElement != null || this.Element == null)
return;
var autoComplete = new AutoCompleteTextView(Forms.Context);
SetNativeControl (autoComplete);
}
// Use the control here.
protected override void OnElementPropertyChanged (object sender, PropertyChangedEventArgs e) {
base.OnElementPropertyChanged (sender, e);
if (this.Element == null || this.Control == null)
return;
// variable this.Control is the AutoCompleteTextView, so you an manipulate it.
}
}
}
Solution for Shared Project:
When using Shared Project there is a possibility to use Native Embedding, like:
...
var textView = new TextView (Forms.Context) { Text = originalText };
stackLayout.Children.Add (textView);
contentView.Content = textView.ToView();
...

Resources