Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Demo: Custom back handler for android hardware back button #272

Merged
merged 4 commits into from
May 17, 2021

Conversation

ashwinibm
Copy link
Contributor

@ashwinibm ashwinibm commented May 12, 2021

Summary

  • Created a wrapper component to handle Android back button press.
  • Custom handler: Go to the first screen in the stack when android back button is pressed on the example screen. Otherwise, let react-navigation's default back handling happen.

Demo

custom_back_screen.mp4

@terryatgithub
Copy link
Contributor

Concise and beautiful code , pleasant to read.

@ashwinibm ashwinibm requested a review from adamstep May 14, 2021 08:56
@ashwinibm ashwinibm marked this pull request as ready for review May 14, 2021 08:56
Copy link
Contributor

@adamstep adamstep left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work!

@ashwinibm ashwinibm merged commit 579094c into master May 17, 2021
@terryatgithub
Copy link
Contributor

terryatgithub commented May 19, 2021

@ashwinibm there are two new questions related to navigation:

  1. [minor question] Event hardwareBackPress is only for Android, so is there the necessity to distinguish iOS/Android in demo you provided?
  2. [major requirement] Can the gestures (swipe left/right) in both iOS/Android have the same customized handle with hardwareBackPress ? if yes, how to implement it ?
    Thanks a lot.

@ashwinibm ashwinibm deleted the ashwinibm/experiment-android-back-handler branch May 19, 2021 04:42
@ashwinibm
Copy link
Contributor Author

Hi @terryatgithub

  1. The BackHandler API used in the demo is for Android only so I don’t think you’ll need to distinguish it for iOS/Android

  2. Since hardwareBackPress is only for the system back button, the swipe gestures need to be handled separately. react-navigation provides some ways to do this depending on the version you are using. I haven't used these myself but here are some references I found that may be helpful:

https://reactnavigation.org/docs/1.x/stack-navigator#gesturesenabled
https://reactnavigation.org/docs/preventing-going-back/
react-navigation/react-navigation#1063

@terryatgithub
Copy link
Contributor

Hi @terryatgithub

  1. The BackHandler API used in the demo is for Android only so I don’t think you’ll need to distinguish it for iOS/Android
  2. Since hardwareBackPress is only for the system back button, the swipe gestures need to be handled separately. react-navigation provides some ways to do this depending on the version you are using. I haven't used these myself but here are some references I found that may be helpful:

https://reactnavigation.org/docs/1.x/stack-navigator#gesturesenabled
https://reactnavigation.org/docs/preventing-going-back/
react-navigation/react-navigation#1063

thank you @ashwinibm , the links can deal with enable/disable gestures, can't handle detect of user gestures that trigger navigation. so I will try to look for the answer, thanks a lot.

@terryatgithub
Copy link
Contributor

terryatgithub commented May 20, 2021

hi @ashwinibm , after practical test , this method is a good way, but only can handle some simple action, like popToTop() or pop(count), can not do complicated action, like navigate() to specific page.

that's because in the method onBack of HandleBack.js, the url in navigation.state.params is not the target route's url(actually, maybe the target url would not be accessed in this case?), but the source page's url, i.e. the current page.
and meanwhile can not get the key of target route.

below are the details.

let's say, we have 4 pages in sequence as below:

  1. home.xml, there is a button when click, push to pagea
  2. pagea.xml, there is a button when click, push to pageb
<view action="push" href="/navigation/pageb.xml" style="Button">
  <text style="Button__Label">Push to page B</text>
</view>
  1. pageb.xml, there is a button when click, push to pagec
<view action="push" href="/navigation/pagec.xml" style="Button">
  <text style="Button__Label">Push to page C</text>
</view>
  1. pagec.xml, there is a back button when click, navigate to pagea and refresh it (the key point)
<header style="Header">
 <text action="navigate" href="/navigation/pagea.xml?timestamp=1234" style="Header__Back">Back to PageA</text>
 <text style="Header__Title">Page C</text>
</header>

and here the test starts:

  • case 1: when click back button in pagec.xml, will trigger below code in Hyperviewscreen.js:
navigate = (params, key) => {
  const navigation = this.props.navigation;
  navigation.navigate({ routeName: 'MainStack', params, key });
}

at this moment the values of params and key is the target route's, as below. so the target is reached perfectly.

image

  • case 2: but when click Android physical back button in pagec.xml, below code in HandleBack.js was triggered:
  onBack = () => {
    if(this.props.navigation && this.props.navigation.goBack && !this.props.navigation.isFirstRouteInParent()){
      const { url } = this.props.navigation.state.params;
      if (url.includes("custom_android_back")) {
        this.props.navigation.popToTop(null);
        return true;
      }
    }
    return false;
  };

at this moment, the url in navigation.state.params is not the target route's url, but the current page's url, i.e: pagec.xml as below, and meanwhile the key of target route can not be accessed:

image

more test

even if add some parameter in pageb.xml, but still can not get the route.key of pagea. so does it mean HandleBack can not handle route.navigate() ?

<view action="push" href="/navigation/pagec.xml?custom_android_back=/navigation/pagea.xml" style="Button">
  <text style="Button__Label">Push to page C</text>
</view>

above all, just some cases need to share.
thanks for your time. thank you so much.

@ashwinibm
Copy link
Contributor Author

ashwinibm commented May 21, 2021

Hi @terryatgithub

Thanks for all the details. Yes, you are right. it's limited to a few actions like disabling, popping to the root screen, etc.
If we need to support navigating to an arbitrary screen in the stack, it'll probably require a lot more work within hyperview core. Since we'll need access to the route key and params.
Or if we want functionality like showing alerts on clicking android back button, that would also require updates in the core.
We had briefly discussed this but didn't think this was a very frequent use case.

@adamstep any other ideas?

@terryatgithub
Copy link
Contributor

yes, some issues gradually merge as the business complexity increases. now there are a few scenarios we've met until now.

  1. go back specific page and refresh its content.
  2. show alert before user quit when in pages that need input.

now the priority of above issues is not urgent, so pls take your time.
thank you very much.

@terryatgithub
Copy link
Contributor

yes, some issues gradually merge as the business complexity increases. now there are a few scenarios we've met until now.

  1. go back specific page and refresh its content.
  2. show alert before user quit when in pages that need input.

now the priority of above issues is not urgent, so pls take your time.
thank you very much.

hi, @ashwinibm , support of the swipe left/right gesture(#279) and android physical back key is on the plan in our next sprint.
so if any progress or update, pls kindly let us know.
thank you very much.

@ashwinibm
Copy link
Contributor Author

Hi @terryatgithub
Unfortunately, we haven’t made progress on this and I may not get much time to work on it in the near future.
But here’s one approach I was thinking of, if you’d like to contribute a PR to support custom navigation handling.

  1. Define a holdall attribute like extra in the XML markup
<text
  action="back"
  extra="dummy" // Can be a json string too
  href="#"
>
  Back with extra route params
</text>
  1. In src/core/hyper-ref/index.js
createActionHandler(…) {
  …
  const extra = behaviorElement.getAttribute(‘extra’);
  // Pass extra to all the onUpdate() calls as 'opts'
  onUpdate(href, action, element, { delay, showIndicatorId, extra });
  …
}
  1. In src/services/navigation/index.js Pass the extra attribute through to navigation handlers as part of routeParams.
navigate(…) {
  const { showIndicatorId, delay, extra } = opts;
  …
  const routeParams = { delay, extra, preloadScreen, url };
}

In our app, we should now be able to access the extra attribute as part of navigation.state.params. And we can take whatever action we want.

Note: The name for this attribute can be more precise. I've just described a general approach.
Other approaches are welcome too :)

cc: @adamstep

@terryatgithub
Copy link
Contributor

hi @ashwinibm , I will try this method when solving this feature in the future.
btw, it seems that this method can not support 'Android physical back key' and 'Gesture swipe left/right' feature.
thank you so much.

@ashwinibm
Copy link
Contributor Author

This would need to be coupled with android back key handling that is described in this PR.
The idea is to pass on arbitrary custom attributes (e.g. target url, some alert attributes, etc) to the back handler that resides within your app. And the back handler can react accordingly.

I haven't looked into the gestures much but gesture handling is also part of react navigation library. If hyperview passes through the custom attributes to the app, we should be able to use the library's gesture handlers based on those attributes.

@terryatgithub
Copy link
Contributor

ok, we will try later.
thanks ashwinibm.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants