facebook / react-native

A framework for building native applications using React
https://reactnative.dev
MIT License
118.16k stars 24.21k forks source link

[Android] Provide a PopupMenu component #3004

Closed satya164 closed 8 years ago

satya164 commented 8 years ago

Currently there is no way to specify an overflow menu icon for Navigator.NavigationBar (or is there?). I can add a custom button, sure, but I cannot find a way to show a menu. Does such a functionality exist?

The Menu component is widely used on Android, and it'll be awesome to have it.

mkonicek commented 8 years ago

Can you please use Stack Overflow to ask questions and tag them with react-native? http://stackoverflow.com/questions/tagged/react-native

Many people from the community hang out on Stack Overflow and will be able to see your question. Using Stack Overflow for questions also helps us use Github issues to keep track of bugs that need to be fixed.

satya164 commented 8 years ago

@mkonicek Hmm... I guess no menu component exists for Android? May be I should change the title. This is more of a feature request than just a question.

mkonicek commented 8 years ago

@satya164 Do you mean something like the Android Spinner? http://developer.android.com/intl/zh-cn/guide/topics/ui/controls/spinner.html

It's planned for one of the future releases: https://facebook.github.io/react-native/docs/known-issues.html

mkonicek commented 8 years ago

There's also http://developer.android.com/intl/zh-cn/reference/android/widget/PopupMenu.html

mkonicek commented 8 years ago

You probably mean this one, right? http://i.stack.imgur.com/j67fB.gif

satya164 commented 8 years ago

@mkonicek Yes. I'm talking about the popup menu. I should change my title :)

Adding an overflow icon is not an issue since I can add any custom view. Popup menu is the one. Thanks :)

hedgerwang commented 8 years ago

For now, you can make your own custom button for the navigation bar.

Speaking of the menu, you'd need to build a separate menu or modal dialog separately and use the button as a trigger to open a menu.

satya164 commented 8 years ago

@hedgerwang Unfortunately, the Modal component is not yet implemented for Android.

I cannot build a menu either, as everything is overflow: hidden and cannot be changed. Hence there cannot be content larger than the container.

ide commented 8 years ago

You can make a large container that is transparent and has pointerEvents="box-none" on it, and put a smaller, visible view inside.

Also Modal is intended for hybrid apps. If you are using only React Native, I recommend you use a Navigator w/out NavigationBar.

satya164 commented 8 years ago

@ide I'll try it out. I actually need a PopupMenu, not a modal. I'll try to make a native component and send a pull request.

niftylettuce commented 8 years ago

@ide @satya164 Why don't the React Native docs for Modal say "Android is not supported"? This is frustrating.

ide commented 8 years ago

@niftylettuce want to send a PR to clarify this in Modal's docblock?

niftylettuce commented 8 years ago

@ide Don't really have time, trying to crank out a project.

prashanthmerugucs commented 8 years ago

When Modal component is worked for android also.Thanks

leeight commented 8 years ago

+1

pewh commented 8 years ago

+1

atc3 commented 8 years ago

+1

For anyone looking for a quick replacement, react-native-dialogs is a good solution that plugs into native dialogs.

Ehesp commented 8 years ago

+1

Some way to force a component to the front of the "stack" would be even more helpful, since it'd apply to more than just the Dialog spec.

mkonicek commented 8 years ago

@Ehesp Totally agree. We used to have a JS-based solution internally but later realized a native implementation works better in hybrid apps (apps where only parts are built with React Native). Here is the JS implementation, feel free to try it out: https://gist.github.com/mkonicek/1a8bd7253e3257687228

It hooks into the Portal here: https://github.com/facebook/react-native/blob/master/Libraries/ReactIOS/renderApplication.android.js#L92

I believe we started working on a native implementation of Modals internally. @AaaChiuuu do we use it in any fb app it ready to be open sourced?

aaronechiu commented 8 years ago

Oh man, I don't think anyone currently uses it. In fact, it got broken when we removed BaseViewPropertyApplicator so styles weren't properly applied to the host view. I really, really wish I could get on this to unblock you guys but my hands are all tied with internal integration and it sounds like the London side of our team is getting stretched too. Krzysztof attempted a fix before he left but it seemed pretty hard to him.

If the community could take this on that would be amazing. The gist of the current implementation before the breakage is creating an Android Dialog in the ReactModalHostView extends ViewGroup and attaching a newly defined DismissEvent to the Dialog in the addEventEmitters(...) of ReactModalHostManager extends ViewGroupManager<ReactModalHostView>.

mkonicek commented 8 years ago

Thanks for the update @AaaChiuuu!

Here's the code, if anyone has bandwidth to ship it that would be awesome!

https://gist.github.com/mkonicek/00453ec3f6c965b93afd https://gist.github.com/mkonicek/58c7c9824987a54bfc54

Then Modal might just work on Android :)

niftylettuce commented 8 years ago

Lets get it in!

Ehesp commented 8 years ago

I'm confused here... How does a Modal differ from the Alert API?

satya164 commented 8 years ago

@Ehesp You can render views inside a Modal.

Ehesp commented 8 years ago

Ah nice. What about the original request here though? If we want a popout menu/spinner coming from the navbar, do we achieve that with positioning a Modal, or is it a separate thing?

image

satya164 commented 8 years ago

@Ehesp I doubt it'll be easy. BTW there is a third party component available for dropdowns - https://www.npmjs.com/package/react-native-dropdown-android , if it serves your purpose

Ehesp commented 8 years ago

Yeah I've taken a look at that, not very customisable though by the looks of it.

I think the main problem is there seems to be no way to "force to front". Things like FABs, Spinners, Bottom Sheets are possible but are always required to be at the end of the render stack, rather than being able to "pop to top".

niftylettuce commented 8 years ago

Modal does not work for Android -- you just have to use Portal instead and sniff the Platform.

Check out what I did with https://github.com/niftylettuce/react-native-loading-spinner-overlay - it overlays a spinner (basically a modal) on top of both Android and iOS platforms

niftylettuce commented 8 years ago

@Ehesp There is a way to force to front :+1: see https://github.com/niftylettuce/react-native-loading-spinner-overlay

satya164 commented 8 years ago

BTW I'm currently working on making <Modal /> work on Android. Will post soon.

alvaromb commented 8 years ago

@mkonicek do you have an approximate release date for Android's Spinner component? I'm porting an app to Android and I would like to leverage if I have to drop a custom solution or not.

Or if you need help I could give a hand, although I do not have any Android experience.

satya164 commented 8 years ago

@alvaromb I don't think anyone is working on it.

alvaromb commented 8 years ago

But... it's on the roadmap @satya164 https://facebook.github.io/react-native/docs/known-issues.html

satya164 commented 8 years ago

@alvaromb Yeah, it's on the roadmap, so it'll be worked on eventually :)

PR is much welcome. But first let's confirm if this component exists internally, then someone could share the code which will make it easier for you.

cc @mkonicek

satya164 commented 8 years ago

@alvaromb Ok, so seems this component existed internally and was just open sourced - 18437093f2664beedd3239bb525d7daa3f2bcdbd

Ehesp commented 8 years ago

@satya164 +1 that stuff all day long. This should be in 0.18, if it works fine :D

Ehesp commented 8 years ago

@satya164 How are you getting on with implementing the Android Modal?

satya164 commented 8 years ago

@Ehesp PR is here - #5320

terrysahaidak commented 8 years ago

Hey @satya164, how it is goin' with PopupMenu?

wvengen commented 8 years ago

We have a Picker now, since 0.19. Haven't put it into a NavigationBar yet, but it looks like that could already work.

terrysahaidak commented 8 years ago

@wvengen yup, but how it can be used with the button instead of picker text field (or what it is)?

wvengen commented 8 years ago

@terrysahaidak That's a good point. As a somewhat ugly workaround I'm now using a Picker with an opacity of zero and a fixed width, positioning it on top of an icon (though not in a NavigationBar). I'd love it to be possible to specify an element for rendering the Picker button, perhaps something for a new issue.

chirag04 commented 8 years ago

context popupMenu is already exposed on UIManager. I have a small wrapper that adds a vertical hamburger menu and shows the popup on it like the youtube app.

import React from 'react-native';
import Icon from 'react-native-vector-icons/Ionicons';

import styles from './styles';

const {
  View,
  UIManager,
  findNodeHandle,
  TouchableOpacity,
} = React;

const ICON_SIZE = 24;

class PopupMenu extends React.Component {
  handleShowPopupError = () => {
    // show error here
  };

  handleMenuPress = () => {
    const { actions, onPress } = this.props;

    UIManager.showPopupMenu(
      findNodeHandle(this.refs.menu),
      actions,
      this.handleShowPopupError,
      onPress,
    );
  };

  render() {
    return (
      <View>
        { this.props.children }
        <TouchableOpacity onPress={this.handleMenuPress} style={styles.touchableContainer}>
          <Icon
            name="android-more-vertical"
            size={ICON_SIZE}
            color={'grey'}
            ref="menu"
          />
        </TouchableOpacity>
      </View>
    );
  }
}

PopupMenu.propTypes = {
  actions: React.PropTypes.array.isRequired,
  onPress: React.PropTypes.func.isRequired,
  children: React.PropTypes.object.isRequired,
};

export default PopupMenu;
<PopupMenu actions=['1', '2'] onPress={() => { // }}>
      <YourListItem .... />
</PopupMenu>
terrysahaidak commented 8 years ago

@chirag04 AWESOME! Thanks a lot!

chirag04 commented 8 years ago

@mkonicek @satya164 I will let you guys close this.

terrysahaidak commented 8 years ago

@chirag04 this should be mentioned in the docs I think.

chirag04 commented 8 years ago

@terrysahaidak can you PR?

kkgelu commented 8 years ago

@wvengen is it possible to invoke the click/tap programmatically for the picker? If so, we could have a zero sized picker, and prompt it by hooking any other events (instead of overlapping views).

Sorry for hunting workaround here, urgently need such an option menu (as an equivalent to actionsheet in iOS), and the picker has all the right attributes I need.

xotahal commented 8 years ago

@kkgelu What kind of problem do you have with @chirag04's solution? I use it in react-native-material-ui and it works well.

kkgelu commented 8 years ago

@xotahal my bad... I rushed to try wvengen's solution. @chirag04 's solution is absolutely brilliant.

For next person: if you don't want that wrapper, this is a minimal example you can try:

      UIManager.showPopupMenu(
        findNodeHandle(this.refs.viewOnWhichToPopup),
        ["Option 1", "Option 2"],
        () => console.log("something went wrong with the popup menu"),
        (e, i)=> console.log(e + " : " + i),
      );

Output:

03-30 20:29:56.522  4023  4275 I ReactNativeJS: itemSelected : 0
03-30 20:29:59.085  4023  4275 I ReactNativeJS: itemSelected : 1

It works everywhere!

Last, I'll remember to turn to UIManager for things next time, let's hope the team don't change it.. ^_^