Giter VIP home page Giter VIP logo

Comments (9)

nhaarman avatar nhaarman commented on June 19, 2024

An Activity's onBackPressed() normally finishes the Activity.
The AcornActivity overrides Activity.onBackPressed() to prevent the Activity from closing and allowing the Navigator to handle back press events, using the OnBackPressListener.

If the Navigator returns true in its onBackPressed() function, it is assumed the Navigator successfully handled the event and no further action is necessary. If it returns false, it is assumed the Navigator could not handle the back press, and the Activity's own onBackPressed() function is called, finishing the Activity:

@CallSuper
override fun onBackPressed() {
if (!acornDelegate.onBackPressed()) {
super.onBackPressed()
}
}

Thus, in short, returning true from the root Navigator's onBackPressed() will not finish the Activity, returning false will finish it.

from acorn.

nhaarman avatar nhaarman commented on June 19, 2024

Giving it a thought, #144 introduced routing the back press to the currently active ViewController. If your ViewController implements the OnBackPressedListener interface, you have the control to intercept the event there.

I would probably handle such a requirement here, since you might want to show a notification to the user on the first back press. This will result in a similar setup as if you were to add a button to exit the app:

interface MyContainer {

   fun setOnBackPressListener(f: () -> Unit)
}

class MyViewController(...) : ViewController, MyContainer, OnBackPressedListener {

  private var onBackPressedListener: (() -> Unit)? = null

  override fun setOnBackPressListener(f: () -> Unit) {
    onBackPressedListener = f
  }

  private var backPressCount = 0
  override fun onBackPressed() : Boolean {
    backPressCount++
    if(backPressCount < 2) { 
      // Return true here to 'claim' the back press event and prevent the Activity from being finished
      return true 
    }

    onBackPressedListener?.invoke()
    // Always return true here, we're manually handling the back event now.
    return true
  }
}

class MyScene(
  private val listener: Events
): Scene<MyContainer> {

  override fun attach(c: MyContainer) {
    c.setOnBackPressListener { listener.onBackPressed() }
  }

  interface Events {
    
    fun onBackPressed()
  }
}

Then call finish() in the Navigator when you implement the MyScene.Events interface. Something like this should work, I've typed this out without the compiler 🙃

from acorn.

manueldidonna avatar manueldidonna commented on June 19, 2024

Thus, in short, returning true from the root Navigator's onBackPressed() will not finish the Activity, returning false will finish it.

You can see that my simplified version of fun onBackPressed(): Boolean from a CompositeStackNavigator always return true but the activity will be normally finished

from acorn.

nhaarman avatar nhaarman commented on June 19, 2024

That is because you're invoking super.onBackPressed(), which will result in an empty stack in the CompositeStackNavigator, finishing the Activity because of that (Navigator.Events.finished() will be invoked).

from acorn.

manueldidonna avatar manueldidonna commented on June 19, 2024

I got it, is there a way to avoid it happening without rewriting the entire navigator implementation?

from acorn.

nhaarman avatar nhaarman commented on June 19, 2024

I've edited my comment above with a sample, does that help?

from acorn.

nhaarman avatar nhaarman commented on June 19, 2024

An easier sample without the manual routing through the Scene (which might work well enough as well):

interface MyContainer : Container

class MyViewController(...) : ViewController, MyContainer, OnBackPressedListener {

  private var backPressCount = 0
  override fun onBackPressed() : Boolean {
    backPressCount++
    if(backPressCount < 2) { 
      // Return true here to 'claim' the back press event and prevent the Activity from being finished
      return true 
    }

    // Return false here, allowing the Navigator to handle the back press.
    return false
  }
}

from acorn.

manueldidonna avatar manueldidonna commented on June 19, 2024

An easier sample without the manual routing through the Scene (which might work well enough as well)

The scene could be present many times in the stack, and the back twice behavior should happen only when that scene is the last one.

Anyway I really apprecciate your work, using Acorn is a pleasure (far better than fragments). I love how you have separate the responsabilities of ui, data managment and navigation into several components but I think that Navigators are the least flexible components. This kind of issue proves it. I have to rewrite their implementation for every minimal behavior change

from acorn.

manueldidonna avatar manueldidonna commented on June 19, 2024

Here is my solution. I hope this could be helpful

class Navigator : Navigator.Events {
    // true by default
    var isRootSceneActive = true 

    var onLastBackPressListener: (() -> Boolean)? = null

    // this listener is added to every child navigator
    override fun scene(scene: Scene<out Container>, data: TransitionData?) {
        isRootSceneActive = **some black magic based on the current scene**
    }

    override fun onBackPressed(): Boolean {
         if (!isRootSceneActive || onLastBackPressListener?.invoke() == false)
             return super.onBackPressed()
         else
             return true
     }
}

class Activity {
    override fun onCreate(savedInstanceState: Bundle?) {
        navigator().onLastBackPressListener = { **back press twice logic** }
    }

    override fun onDestroy() {
        // don't leak activity
        navigator().onLastBackPressListener = null
    }

}

from acorn.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.