Get UIBarButtonItem from ToolbarItem

So, I have a UIAlertController action sheet that I display using iOS-only code in my cross-platform Xamarin.Forms app. The action sheet is displayed when a Xamarin.Forms.ToolbarItem is tapped by the user. When on iPad, the UIAlertController containing the action sheet needs to have its UIPopoverPresentationController.BarButtonItem set to the menu item that caused it to appear, or I have to manually specify a location on screen where I want the action sheet to appear.

Is there no way of converting a Xamarin.Forms.ToolbarItem into its corresponding UIBarButtonItem?

I've tried for hours by intercepting calls to PageRenderer and NavigationRenderer to no avail, since the ToolbarItems properties of the respective native views are never set. I can see the Xamarin.Forms.ToolbarItems I provided at Xamarin.Forms.Page construction, however. I cannot use Platform.GetRenderer() as it requires a VisualElement, which Xamarin.Forms.ToolbarItem doesn't implement.

I also looked at Xamarin.Forms.Platform.iOS.ToolbarItemExtensions.ToUIBarButtonItem, which gives me a proper UIBarButtonItem from a Xamarin.Forms.ToolbarItem, but the provided item is a new such, and has no correspondence on screen. Using the returned item as a value for UIPopoverPresentationController.BarButtonItem causes the application to crash.

Any other ideas?

Answers

  • kylehumfeldkylehumfeld USMember ✭✭

    I'm having the same issue. I think my workaround approach may be to get the x/y position of the click event from the handler's EventArgs, pass that along to the iOS handler, and use that to create a CGRect which will be the target of the Popover (you don't have to make it a UIBarButtonItem). Not a very satisfying workaround, but I can't think of a less kludgy option.

  • For reference sake, it could also be solved by using a Custom PageRenderer to get at the ToolbarItem, like below. Override the PageRenderer > ViewDidAppear method for the specific NavigationPage.

    [assembly: ExportRenderer(typeof(CustomPage), typeof(CustomPageRenderer))]
    
    namespace App.iOS.CustomRenderers
    {
        public class CustomPageRenderer : PageRenderer
        {
            public override void ViewDidAppear(bool animated)
            {
                var element = (ContentPage)Element;
                var itemIndex = -1;
                var offset = element.ToolbarItems.Count - 1;
                for (int i = 0; i < element.ToolbarItems.Count; i++)
                {
                    var item = element.ToolbarItems[i];
                    if (item.ClassId == "SomeStringId")
                    {
                        itemIndex = offset - i;
                        break;
                    }
                }
    
                if (itemIndex > -1)
                {
                    var barBtnItem = NavigationController.TopViewController.NavigationItem.RightBarButtonItems[itemIndex];
    
                    // Do something with the button, like save reference
                }
    
    
                base.ViewDidAppear(animated);
            }
        }
    }
    
Sign In or Register to comment.