omz:forum

    • Register
    • Login
    • Search
    • Recent
    • Popular

    Welcome!

    This is the community forum for my apps Pythonista and Editorial.

    For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.


    Sticking a custom back button item into a NavigationView?

    Pythonista
    navigationview
    4
    17
    7201
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • shinyformica
      shinyformica last edited by

      Whoo-boy...I am spamming the airwaves this past couple days. Here's another one...in my attempts to get the NavigationView to be a little less half-baked for my purposes, I need a way to know when the back button is pressed. So I thought I'd be clever and insert my own UIBarButtonItem in the navigation bar the navigation controller is using so I could provide a target/action for when it is activated...so I tested it with this:

      def backButtonBarItemAction(_self, _cmd):
          print "target called!"
      BackButtonBarItemTarget = objc_util.create_objc_class("BackButtonBarItemTarget",
                                              methods=[backButtonBarItemAction])
      target = BackButtonBarItemTarget.new().autorelease()
      
      v1 = ui.View()
      v1.name = "view1"
      
      v2 = ui.View()
      v2.name = "view2"
      
      n = ui.NavigationView(v1)
      n.push_view(v2)
      
      nc = n.objc_instance.navigationController()
      vc = nc.bottomViewController()
      ni = vc.navigationItem()
      print "nav item:",ni
      print "back item:",ni.backBarButtonItem()
      
      UIBarButtonItem = objc_util.ObjCClass("UIBarButtonItem")
      print "target:",target
      backitem = UIBarButtonItem.alloc().initWithTitle_style_target_action_(
                                      "TEST",0,target,"backButtonBarItemAction")
      backitem.autorelease()
      ni.backBarButtonItem = backitem
      
      print "custom back item:",backitem
      print "back item now:",ni.backBarButtonItem()
      
      n.present()
      
      print "nav item after present:",ni
      

      The strange thing here is that nothing seems to be wrong...the code all works with no tracebacks or errors in objective-c-land. However, while the back item text does change to "TEST", indicating my custom item is there, pressing the back button doesn't trigger my target selector...anyone have any ideas? I'm guessing something in the NavigationView implementation is overriding my target/action.

      1 Reply Last reply Reply Quote 0
      • JonB
        JonB last edited by JonB

        I believe action must be a selector. I'm not sure if objc_util handles the cast for you.

        Try sel('backButton....'). Also, try it with a trailing colon, I forget if that is needed or not.

        1 Reply Last reply Reply Quote 0
        • JonB
          JonB last edited by

          You could also use my view browser to see if your action is getting properly set

          1 Reply Last reply Reply Quote 0
          • shinyformica
            shinyformica last edited by

            It shouldn't need anything special there...I'm using that same target/action setup for other, similar things and it works fine. Though I did try calling objc_util.sel("backButtonBarItemAction") with and without a trailing colon, but nothing changes.

            Let me install your view browser and see what that shows me.

            1 Reply Last reply Reply Quote 0
            • shinyformica
              shinyformica last edited by

              Well...I give up for now.
              I can't find any way to insert myself into the back button action...I tried adding my own UIBarButtonItem, and even a UIBarButtonItem with a custom UIButton in it. Can't get anything to call my own target action.

              I think the only real way to do this would be to insert my own UIViewController into the hierarchy to see when views are pushed or popped, or to just build my own NavigationView from scratch.

              mikael cvp 2 Replies Last reply Reply Quote 0
              • mikael
                mikael @shinyformica last edited by

                @shinyformica, how about listening to a notification instead?

                1 Reply Last reply Reply Quote 0
                • JonB
                  JonB last edited by

                  Have you tried using the hidden ui.Button to get an action target, similar to, say, the mapkit example?

                  1 Reply Last reply Reply Quote 0
                  • cvp
                    cvp @shinyformica last edited by

                    @shinyformica Not sure we can replace the back button, did you try this

                    1 Reply Last reply Reply Quote 0
                    • JonB
                      JonB last edited by

                      Note you were setting the back button of the BOTTOM navigation item. You want the top.
                      That said, for me only the left bar button worked for me. I used a normal py left button items.

                      1 Reply Last reply Reply Quote 0
                      • cvp
                        cvp last edited by

                        As here, you could check which view is on_screen

                        1 Reply Last reply Reply Quote 0
                        • cvp
                          cvp last edited by

                          draw called when back tapped (or I am too naïve 😢)

                          import ui
                          
                          class MyView(ui.View):
                          	def __init__(self,name):
                          		self.name = name
                          	def draw(self):
                          		if self.name != n.name:
                          			if n.name != None:
                          				print(n.name,'closed')
                          			n.name = self.name
                          
                          v1 = MyView('v1')
                          v2 = MyView('v2')
                          v3 = MyView('v3')
                          
                          n = ui.NavigationView(v1)
                          n.push_view(v2)
                          n.push_view(v3)
                          
                          n.present()
                          
                          1 Reply Last reply Reply Quote 0
                          • shinyformica
                            shinyformica last edited by shinyformica

                            Whoa! Love this community :)

                            Ok, in reverse order:

                            @cvp - I thought about it, and did some tests, but on_screen would have to be checked manually, and the problem here is I need to know when a view is popped off the stack, not check at some point in the future if it has been popped - and I'm not willing to mess with an update_interval hack to do that. Also, on_screen would have issues when the navigationview itself hasn't been shown, or is itself hidden, which would require holding a bunch of state.

                            @JonB - it's actually confusing, but you don't modify the back button on the currently visible view, you modify it on the view below that one, since that's what UIKit uses to populate the back button in the navigation bar. The whole thing is confusing, and Apple's docs are a bit hard to parse, but the applicable info is here: https://developer.apple.com/documentation/uikit/uinavigationcontroller?language=objc

                            The Left Item
                            For all but the root view controller on the navigation stack, the item on the left side of the navigation bar provides navigation back to the previous view controller. The contents of this left-most button are determined as follows:
                            
                            If the new top-level view controller has a custom left bar button item, that item is displayed. To specify a custom left bar button item, set the leftBarButtonItem property of the view controller’s navigation item.
                            
                            If the top-level view controller does not have a custom left bar button item, but the navigation item of the previous view controller has an object in its backBarButtonItem property, the navigation bar displays that item.
                            
                            If a custom bar button item is not specified by either of the view controllers, a default back button is used and its title is set to the value of the title property of the previous view controller—that is, the view controller one level down on the stack. (If there is only one view controller on the navigation stack, no back button is displayed.)
                            

                            anyway, it doesn't seem to matter if, in this two-view test stack, I set the back button item of the bottom view, or the left button item of the top view, I don't get my target action called. And the only time I even see the title of the back button change is when I set a custom back button item on the bottom view, as in the example.

                            @cvp I've tried all the things I can think of to get my custom button or custom action to show up and be called...setting all the applicable flags, sticking custom buttons in...nothing seems to work.

                            @mikael - what the?! I swear I searched for notifications which would let me know when the navigation view controller changes views...and didn't find any. And nobody seems to mention the existence of those in the discussions of the topic on stackoverflow, etc. but I think you've given me the winner...even though I feel like I'm doing a bit too much via the notification mechanism, it sure comes in handy!

                            JonB 1 Reply Last reply Reply Quote 0
                            • JonB
                              JonB last edited by

                              Ahh, yes left button items set on the top view works, but back button would be on the one under the top.. got it.

                              Funny I thought you had tried and dismissed notifications already, or I would have mentioned it. I guess what we need is a UI.View subclass with a set of delegate decorators that register for notifications, but allow you to write the callback in python...

                              One other thing I tried but might be worth another look: the back button has a custom order that you can set. In that custom view you could install a ui.Button.
                              My initial efforts failed here, but I might have already been trying the top view, instead of bottom.

                              1 Reply Last reply Reply Quote 0
                              • shinyformica
                                shinyformica last edited by

                                @JonB I only didn't mention/dismissed notifications because none showed up when I searched for it. As it turns out, the "UINavigationControllerDidShowViewControllerNotification" (cripes Apple, I appreciate verbosity, but for goodness sake!) notification is actually technically an undocumented private API, which is generally a no-no. I'll use it for now, since it seems to be my only route without rolling my own navigation controller setup.

                                @mikael notification for the WIN! Works like a charm, and can be isolated to the specific navigation controller I want to monitor.

                                1 Reply Last reply Reply Quote 0
                                • JonB
                                  JonB @shinyformica last edited by JonB

                                  @shinyformica ok, never mind.. I guess back button title and appearance only can be changed
                                  https://stackoverflow.com/questions/9765162/backbarbuttonitem-doesnt-call-action

                                  1 Reply Last reply Reply Quote 0
                                  • cvp
                                    cvp last edited by

                                    If I correctly understand this, already pointed above, it should be possible to not display the back button but to display a left button, at the right of the back button, thus not in the top bar, thus exactly what you want.
                                    But I've tried without success.

                                    1 Reply Last reply Reply Quote 0
                                    • shinyformica
                                      shinyformica last edited by

                                      @cvp yeah...same here, no success with any of the things that seem like they should let me modify the back or left button items to something I am in control of.

                                      The good news is that @mikael 's pointer to the hidden notification works perfectly, so I'm good to go.

                                      1 Reply Last reply Reply Quote 0
                                      • First post
                                        Last post
                                      Powered by NodeBB Forums | Contributors