Not sure if it is a Xamarin IOS bug but on the same panel we have a custom control that pops a modal view of choices(like a picker) and a standard Xamarin Forms Picker. If the standard picker is displaying the scroller at the bottom and then then custom modal control is tapped and receives focus the modal view pops up but the standard picker never disappears creating a hung panel.
The standard IOS picker does lose focus but never disappears. I have a renderer created but can't figure how to close the IOS picker.
namespace HCMobile.iOS.CustomRenderers
{
public class CustomPickerRenderer : PickerRenderer
{
public CustomPickerRenderer() { }
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
var isFocused = ((Picker)sender).IsFocused;
// This fires when the IOS picker looses focus but never closes the picker at the bottom of the panel. Scroller disappears if ANY other control receives focus.
if (Control != null && !isFocused)
{
UIPickerView pickerView = (UIPickerView)Control.InputView;
}
else
{
UIPickerView pickerView = (UIPickerView)Control.InputView;
}
}
}
}
Has anyone else ran into this problem?
Related
I'm creating an app using xamarin Forms (multiplatform), I'm using a Navigation page, but I want to change the arrow ("<-") to text ("back")
Do you know how could i do it?
Thanks
(I'm going to use it in an Android App, but I'm creating the app using Xamarin forms)
You could use custom renderer to remove the navigation icon and set it with text. But, when you do that, you need to capture the click of the text and simulate the back event.
Create the interface:
public class CustomNavigationPage : NavigationPage
{
public CustomNavigationPage(Page startupPage) : base(startupPage)
{
}
}
The implementation of Android:
[assembly: ExportRenderer(typeof(CustomNavigationPage),
typeof(NavigationPageRenderer_Droid))]
namespace NavigationPageDemo.Droid
{
public class NavigationPageRenderer_Droid : NavigationPageRenderer
{
public Android.Support.V7.Widget.Toolbar toolbar;
public Activity context;
public NavigationPageRenderer_Droid(Context context) : base(context)
{
}
protected override Task<bool> OnPushAsync(Page view, bool animated)
{
var retVal = base.OnPushAsync(view, animated);
context = (Activity)Forms.Context;
toolbar = context.FindViewById<Android.Support.V7.Widget.Toolbar>(Droid.Resource.Id.toolbar);
if (toolbar != null)
{
//if (toolbar.NavigationIcon != null)
//{
//toolbar.NavigationIcon = Android.Support.V7.Content.Res.AppCompatResources.GetDrawable(context, Resource.Drawable.back);
//toolbar.NavigationIcon = null;
toolbar.NavigationIcon = null;
toolbar.Title = "back";
toolbar.SetOnClickListener(new OnClick());
//}
}
return retVal;
}
protected override Task<bool> OnPopViewAsync(Page page, bool animated)
{
return base.OnPopViewAsync(page, animated);
}
}
public class OnClick : Java.Lang.Object, IOnClickListener
{
void IOnClickListener.OnClick(Android.Views.View v)
{
App.Current.MainPage.Navigation.PopAsync();
}
}
In the custom renderer, use the OnClickListener to capture the click on text.
when you are working with xamarin forms it is suggested make use of common components and make least use of custom renderer.
Now for your requirement you want to create custom navigation bar
so here is how you can do it.
Create BaseContent Page
Create a Control Template inside your base page your can follow this link
Inside your control template using a grid view place your label with text binding (Back),also your can place a label in center to show title of page again u can make use of template binding which u would come to know when u go through the link
Now inherit your main page with your basecontentpage page
add your control template inside your main page
turn off your navigation bar of your main page
and you are done, this would give u more power to add more things like image or toolbar in your navbar
also to dynamically handle your back button u can check the count from navigationstack if its 0 u can show Humburger Icon or if its more than 0 u can show your label using IsVisible True/False
How can I get navigation back button event if I have MasterDetailPage?
Toolbar toolbar = FindViewById(Resource.Id.toolbar) return null
If want to get event of the hardware back button, you can use OnBackButtonPressed method in ContentPage to get navigation back button event as follow:
protected override bool OnBackButtonPressed()
{
Console.WriteLine("Press back button.");
return base.OnBackButtonPressed();
}
Event that is raised when the hardware back button is pressed. This event is not raised on iOS.
=====================================Update==================================
Else if want to get back event from ToolBar , you should use Android.Support.V7.Widget for Toolbar.
In Acitivity OnCreate:
Android.Support.V7.Widget.Toolbar toolbar = this.FindViewById<Android.Support.V7.Widget.Toolbar>(Resource.Id.toolbar);
SetSupportActionBar(toolbar);
Override OnOptionsItemSelected method :
public override bool OnOptionsItemSelected(IMenuItem item)
{
if(item.ItemId == Android.Resource.Id.Home)
{
Console.WriteLine("Here is back button event.");
}
return base.OnOptionsItemSelected(item);
}
I am creating xamarin form app and I want to perform some action on navigation back button.Is there any approach to do that?
P.S :> Software back button, not Hardware back button.
In this article, you'll find everything.
IF the article disappears or changes at some point, here you will find the specifics of the solution.
You'll need to create a Custom ContentPage
namespace WhateverYourNamespace
{
public class CoolContentPage : ContentPage
{
/// <summary>
/// Gets or Sets the Back button click overriden custom action
/// </summary>
public Action CustomBackButtonAction { get; set; }
public static readonly BindableProperty EnableBackButtonOverrideProperty =
BindableProperty.Create(
nameof(EnableBackButtonOverride),
typeof(bool),
typeof(CoolContentPage),
false);
/// <summary>
/// Gets or Sets Custom Back button overriding state
/// </summary>
public bool EnableBackButtonOverride
{
get
{
return (bool)GetValue(EnableBackButtonOverrideProperty);
}
set
{
SetValue(EnableBackButtonOverrideProperty, value);
}
}
}
}
As you see, there's an action event that we are going to subscribe to in our Xamarin Forms code level and to be invoked from Xamarin native project level.
There is also a bool property to enable or disable the overriding of the Back Button click event so that you can decide whether to subscribe to the overriding event or not as a page property.
Android :
You'll need to override the OnOptionsItemSelected() event in our MainActivity class in order to capture the nav bar back button click in Android for Xamarin Forms.
public override bool OnOptionsItemSelected(IMenuItem item)
{
// check if the current item id
// is equals to the back button id
if (item.ItemId == 16908332)
{
// retrieve the current xamarin forms page instance
var currentpage = (CoolContentPage)
Xamarin.Forms.Application.
Current.MainPage.Navigation.
NavigationStack.LastOrDefault();
// check if the page has subscribed to
// the custom back button event
if (currentpage?.CustomBackButtonAction != null)
{
// invoke the Custom back button action
currentpage?.CustomBackButtonAction.Invoke();
// and disable the default back button action
return false;
}
// if its not subscribed then go ahead
// with the default back button action
return base.OnOptionsItemSelected(item);
}
else
{
// since its not the back button
//click, pass the event to the base
return base.OnOptionsItemSelected(item);
}
}
public override void OnBackPressed()
{
// this is not necessary, but in Android user
// has both Nav bar back button and
// physical back button its safe
// to cover the both events
// retrieve the current xamarin forms page instance
var currentpage = (CoolContentPage)
Xamarin.Forms.Application.
Current.MainPage.Navigation.
NavigationStack.LastOrDefault();
// check if the page has subscribed to
// the custom back button event
if (currentpage?.CustomBackButtonAction != null)
{
currentpage?.CustomBackButtonAction.Invoke();
}
else
{
base.OnBackPressed();
}
}
iOS :
iOS you need to override the ViewWillAppear() method in your CoolContentPageRenderer class.
So the below code should be placed inside your CoolContentPageRenderer class.
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
if (((CoolContentPage)Element).EnableBackButtonOverride)
{
SetCustomBackButton();
}
}
private void SetCustomBackButton()
{
// Load the Back arrow Image
var backBtnImage =
UIImage.FromBundle("iosbackarrow.png");
backBtnImage =
backBtnImage.ImageWithRenderingMode
(UIImageRenderingMode.AlwaysTemplate);
// Create our Button and set Edge
// Insets for Title and Image
var backBtn = new UIButton(UIButtonType.Custom)
{
HorizontalAlignment =
UIControlContentHorizontalAlignment.Left,
TitleEdgeInsets =
new UIEdgeInsets(11.5f, 15f, 10f, 0f),
ImageEdgeInsets =
new UIEdgeInsets(1f, 8f, 0f, 0f)
};
// Set the styling for Title
// You could set any Text as you wish here
backBtn.SetTitle("Back", UIControlState.Normal);
// use the white color in ios back button text
backBtn.SetTitleColor(UIColor.White,
UIControlState.Normal);
backBtn.SetTitleColor(UIColor.LightGray,
UIControlState.Highlighted);
backBtn.Font = UIFont.FromName("HelveticaNeue",
(nfloat)17);
// Set the Image to the button
backBtn.SetImage(backBtnImage, UIControlState.Normal);
// Allow the button to Size itself
backBtn.SizeToFit();
// Add the Custom Click event you would like to
// execute upon the Back button click
backBtn.TouchDown += (sender, e) =>
{
// Whatever your custom back button click handling
if(((CoolContentPage)Element)?.
CustomBackButtonAction != null)
{
((CoolContentPage)Element)?.
CustomBackButtonAction.Invoke();
}
};
//Set the frame of the button
backBtn.Frame = new CGRect(
0,
0,
UIScreen.MainScreen.Bounds.Width / 4,
NavigationController.NavigationBar.Frame.Height);
// Add our button to a container
var btnContainer = new UIView(
new CGRect(0, 0,
backBtn.Frame.Width, backBtn.Frame.Height));
btnContainer.AddSubview(backBtn);
// A dummy button item to push our custom back button to
// the edge of screen (sort of a hack)
var fixedSpace =
new UIBarButtonItem(UIBarButtonSystemItem.FixedSpace)
{
Width = -16f
};
// wrap our custom back button with a UIBarButtonItem
var backButtonItem = new UIBarButtonItem("",
UIBarButtonItemStyle.Plain, null)
{
CustomView = backBtn
};
// Add it to the ViewController
NavigationController.TopViewController.
NavigationItem.LeftBarButtonItems
= new[] { fixedSpace, backButtonItem };
}
How to use it :
<WhateverYourNamespace:CoolContentPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:WhateverYourNamespace=
"clrnamespace:XFNavBarBackBtnClickOverride;
assembly=XFNavBarBackBtnClickOverride"
x:Class="XFNavBarBackBtnClickOverride.Page2"
Title="Page 3"
EnableBackButtonOverride="True"
BackgroundColor="#00bfff">
<StackLayout
Spacing="20"
Padding="20,10,20,10"
VerticalOptions="Center"
HorizontalOptions="Center" >
<Label Text="This is the cool page,
which has the Navigation Bar Back button
click overriden. How go ahead and click that Back
button! ;)"
FontSize="20"
HorizontalTextAlignment="Center"
TextColor="White"/>
</StackLayout>
</WhateverYourNamespace:CoolContentPage>
For ANDROID add this in you main activity OnCreate() after LoadApplication(new App()) line.
Android.Support.V7.Widget.Toolbar toolbar
= this.FindViewById<Android.Support.V7.Widget.Toolbar>(Resource.Id.toolbarSetSupportActionBar(toolbar);
I have JFXPanel with a textbox and few buttons on it. I want to lost focus of textbox if user click on anywhere other than child controls.
Here is my working example:
override the mouse click event of JFXPanel as follows:
jfxPanel.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
if(!toolbarJFX.getScene().getFocusOwner().isPressed()) {
toolbarJFX.getScene().getRoot().requestFocus();
}
}
});
I want to display a drop down menu when a user clicks a button. Something like comboBox but instead of the comboBox its a button. How can I do it??
I solved it using PopupMenu. Here is the code for other's reference.
public static Rect GetElementRect(FrameworkElement element)
{
GeneralTransform buttonTransform = element.TransformToVisual(null);
Point point = buttonTransform.TransformPoint(new Point());
return new Rect(point, new Size(element.ActualWidth, element.ActualHeight));
}
private async void Button_Click(object sender, RoutedEventArgs e)
{
var menu = new PopupMenu();
menu.Commands.Add(new UICommand("Label", (command) =>
{
//do work
}));
// We don't want to obscure content, so pass in a rectangle representing the sender of the context menu event.
// We registered command callbacks; no need to handle the menu completion event
var chosenCommand = await menu.ShowForSelectionAsync(GetElementRect((FrameworkElement)sender));
if (chosenCommand == null) // The command is null if no command was invoked.
{
}
}
Milan,
You'll need to create a custom control or a user control that combines a button and a popup. You could also just implement this in-place with a button and popup. I suggest you look at Callisto's Menu control and start from there to implement your dropdown menu:
Callisto controls (includes a Menu)