ReactNativeでポップアップメニューの実装
ReactNativeでポップアップメニューといえば react-native-material-menu での実装がよく見つかるのですが、表示内容のカスタマイズはまずできない構造だったので、仕方なく react-native-popup-menu に置き換えたというお話です。
react-native-material-menu でアイコンがうまく配置できない
このあたりの issues でアイコン配置についての言及があり、配置はスペースで調整しているようです。
最初は気にしていなかったんですが、コードを良く調べてみると、MenuItemに渡したchildrenはTextの配下に入るようです。
どおりで、どうやっても右端にアイコンが配置できないわけだ...。
(現在、2.0.0になっていますが、未だにMenuItemのchildrenはText配下です)
このままでは到底デザインどおりの配置は無理なので、別のライブラリを探しました。
react-native-popup-menu を使う
割と自由度が高そうなライブラリを見つけたのでポップアップメニューの類をそれに置き換えることにしました。
1. 最上層になる部分を MenuProvider で覆う
以下は react-native-material-menu
の Basic Usage
にある実装サンプルです。
react-navigation
を使っている場合はNavigationContainer
を覆えば良さそうです。
後は中の画面で Menu 以下を追加するだけで簡単に実装できます。
import { MenuProvider } from 'react-native-popup-menu';
export const App = () => (
<MenuProvider>
<YourApp />
</MenuProvider>
);
2. 表示するメニューの実装
ポップアップメニューを開くボタン込みで以下のような実装です。
import {
Menu,
MenuTrigger,
MenuOptions,
MenuOption,
renderers,
} from 'react-native-popup-menu';
function createMenu() {
return (
<Menu renderer={renderers.NotAnimatedContextMenu}>
<MenuTrigger>
<Text>メニュー</Text>
</MenuTrigger>
<MenuOptions
customStyles={{
optionsContainer: styles.options,
optionWrapper: styles.option,
}}>
<MenuOption onSelect={() => alert('Hoge')} text='Hoge' />
<MenuOption onSelect={() => alert('Fuga')}>
<Text style={{color: 'red'}}>Fuga</Text>
</MenuOption>
</MenuOptions>
</Menu>
);
}
const styles = StyleSheet.create({
options: {
width: 300,
marginTop: 10,
marginLeft: -30,
borderRadius: 8,
},
option: {
minHeight: 48,
padding: 8,
},
});
Menu: ポップアップメニューの開始タグです。renderer
で開き方を指定できます。例はアニメーションしないメニューです。パッと開く感じです。Popoverで吹き出し型、SlideInMenuで下から生えてくるメニューが出せます。
MenuTrigger: ポップアップを開くボタンです。テキスト以外にもなんでも置けます。テキストだけの場合は、<MenuTrigger text='Menu' />
というふうにもできます。
MenuOptions: ポップアップの外枠です。これのマージンなどを調整するとボタンからの表示位置を調整できます。メニューの幅などもここに指定。(marginLeftにマイナス値を入れると、ボタンの左側に開きます)
MenuOption: ポップアップ内のリストです。一般的なView内配置になるので、よくあるテキスト左寄せ、アイコン右寄せみたいな作り込みのViewを渡しても大丈夫です。
以上の実装で十分過ぎるぐらいにポップアップメニューの実装は可能です。
この他、細かい設定が必要という場合は、react-native-popup-menu のサンプルやドキュメントを読むと良さそうです。
まとめ
凝ったデザインのポップアップメニューを作りたい場合は react-native-popup-menu をおすすめします。
また、MenuTrigger
には disabled 属性があるので、このタイミングでメニューを開かせたくないという場合にも有効です。
MenuOption
も disabled 属性があるので、色々とコントロールし易いのではないでしょうか。