bottom tap新增一个自定义icon,点击弹出Modal

我想实现的效果是这样的:

 

    

注意:Modal的背景还是其他的tab,并没有变化,等Modal消失后Screen还是原来的screen。

Solution:

      因为中间的自定义图标按钮需要有一部分在Tab中,所以还是把icon作为tab中的一个screen的,于是就借用:tabBarButton 来实现,参考了一些文章,都是把Modal封装为一个组件,然后把Tab.screen的component设置为这个组件,结果怎么调试都有问题,不是这有问题就是那有问题。后来改变了下思路,把Model放置在平行于Tab.Navigator的同级元素上解决了这个问题。代码如下:

       

  // 设置Model是否显示的state,这个state需要放在tab同级组件中,不能放到Model组件中
  const [isAddActivityVisible, setIsAddActivityVisible] = useState(false);
  const clickAddActivity = () => { setIsAddActivityVisible(true); };
  const hideAddActivity = () => { setIsAddActivityVisible(false); };
  // 借助Tab的listeners方法来做,因为需要preventDefault()来阻止screen跳转
<>
</Tab.Navigator>
   <Tab.Screen
        name="AddActivity"
        listeners={
          ({ navigation }) => ({
            tabPress: (e) => {
              // Prevent default action
              e.preventDefault();
              clickAddActivity();
            },
          })
        }
        options={{
            tabBarButton: (props) => (
              <TouchableOpacity {...props}>
                <Icon icon="add1" size={58} />
              </TouchableOpacity>
            )
          }} >
      {() => <></>}
      ......
  </Tab.Navigator>
   // 放在和Tab.Navigator同级
   <AddActivityModal isModalVisible={isAddActivityVisible} onHide={hideAddActivity} />
</>

     而Modal组件自己定义即可。

     

interface ModalProps {
  isModalVisible: boolean;
  onHide: () => void;
}

export const AddActivityModal : FC<ModalProps> = 
  ({isModalVisible, onHide}) => {
  React.useEffect(() => {
    console.log('AddActivityModal did mount,isModalVisible:'+isModalVisible);
  }, []);

  return (
    <Modal isVisible={isModalVisible} onHide={onHide} onBackdropPress={onHide}>
      <Modal.Container>
        <View style={styles.modal}>
        <Modal.Header title="LogRocket is fab!" />
        <Modal.Body>
        <Text style={styles.text}>Agree to continue with this guide</Text>
        </Modal.Body>
        <Modal.Footer>
        <Button title="I agree" onPress={onHide} />
        </Modal.Footer>
        </View>
      </Modal.Container>
    </Modal>
  );
}

 ----------------------------------------------------------------------------------------------

尝试过的有问题的方案:

1.  尝试把Modal的component放在Tab.Screen中。参考:https://medium.com/@my.maithi/react-native-navigation-add-custom-button-in-the-middle-of-tabbar-6c390201a2bb ,这个方案把圆形button和Modal放到一个Screen component中,其中也包括了state。

     问题在于:中间圆形button的样式总是调不好。

2.  把中间圆形Button放在Tab.Screen中,用TabBarButton来控制,这种方案如下:

    <Tab.Screen
        name="AddActivity"
        options={
          ({ navigation }) => ({
            tabBarButton: (props) => (
              <TouchableOpacity
                onPress={() => console.log("1111")}
                {...props}>
                <Icon icon="add1" size={58} />
              </TouchableOpacity>
            ),
          })
        } >
      {() => <AddActivityModal isModalVisible={isAddActivityVisible} onHide={hideAddActivity} />}
  </Tab.Screen>

        问题有:a) AddActivityModal 是Tab.Screen的child component, 根据react推荐做法,需要把state从child component中提升到父类的compoenent中  b) 在TouchableOpacity中点击onPress方法,总是不能加载child component,好像这个onPress方法阻碍了系统默认的behavior(转到childScreen),没有很好的解决办法 c) 即便b的问题解决了,点击中间的button的时候会转到Modal的Screen,但是当Modal窗口取消后整个Screen就变空白了,因为navigation转到modal的screen了,modal隐藏后就是空白了。

       所以这两个方案都有问题,思路不对。

需要注意的技术点:

      1)当有Parent Component和其Child Component时候,不要尝试直接在parent组件中直接调用child组件的方法,这不是推荐的做法,推荐的做法是用prop来传递值,由child component来做处理。当然在特殊情况下也可以做到这一点,主要用Ref, CreateRef, UseRef,参考:https://refine.dev/blog/react-useref-hook-and-ref/#using-the-useref-hook-in-an-application , https://blog.logrocket.com/use-forwardref-react/

     2)当父component中有个button,点击后想要change 子component中的state变化,这种情况下,根据推荐做法,需要把state lift提升,参考:https://legacy.reactjs.org/docs/lifting-state-up.html ,https://react.dev/learn/sharing-state-between-components

------------------------ update -------------------

最近又发现了这个github开源库:https://github.com/hoaphantn7604/react-native-curved-bottom-bar , 暂时没有尝试,先做下记录。

 

posted @ 2024-04-02 15:02  saaspeter  阅读(18)  评论(0编辑  收藏  举报