美文网首页react-native
RN-可拖动的悬浮按钮

RN-可拖动的悬浮按钮

作者: 你家毕老师 | 来源:发表于2021-09-06 12:17 被阅读0次

    RN-可拖动的悬浮按钮

    需求

    分享悬浮按钮,需要展示在特定页面,并且支持拖动(防止遮挡页面内容)

    解决方案思路

    1. 封装原生组件,为RN提供原生桥

    • 缺点:两端都需要开发,而且原生组件的位置、大小改变很难适应后续需求、两端代码需要二次封装以对外提供一致的方法和属性。
    • 优点:调用现有组件,不需要额外开发组件相关内容。

    2. 第三方组件-react-native-interactable

    • 缺点:需要原生链接一下库,代码比较老(最后维护日期是17年),可能会与当前环境不兼容或出现莫名其妙的bug。
    • 优点:直接集成,瞬间完成开发,节省时间。

    3. 参考别人写的案例造轮子-RN开发图标拖动效果实现

    • 缺点:贴的代码太多太长了。。。
    • 优点:。。。

    4. 自己搞个RN组件

    • 缺点:完全没思路,不确定多久可以搞定。
    • 优点:组件bug可控,可以通过看文档造轮子学习熟悉一下相关知识。

    开整

    1. 了解RN中的滑动手势-PanResponder

    PanResponder.gif

    真是意外发现,官方给出的例子还有代码,已经基本实现了想要的功能。。

    首先以当前例子为基础直接贴到我们的demo里慢慢改

    运行一下,发现没问题,到目前发现自己搞并不难。所以我们决定更进一步优化,做个松手后自动边缘吸附的效果吧,这样又可以与原生保持一致,而且会有比较好的效果。

    2. 通过RN中的动画做吸附效果-Animated.ValueXY

    看到这个demo,发现运气太好了已经成功了99%啊。这就是想要的效果啊。

    AnimatedValueXY.gif

    3. 计算松手后的位置,实现边缘吸附

    /*
     * @Author: 毕帅 
     * @Date: 2021-09-03 09:42:36 
     * @Last Modified by: 毕帅
     * @Last Modified time: 2021-09-06 09:45:00
     */
    import React, { Component } from "react";
    import { Animated, PanResponder } from "react-native";
    import { currentScreen } from "../../utils/Utils";
    
    class GJSuspendView extends Component {
      pan = new Animated.ValueXY();
      panResponder = PanResponder.create({
        onMoveShouldSetPanResponder: () => true,
        onPanResponderGrant: () => {
          this.pan.setOffset({
            x: this.pan.x._value,
            y: this.pan.y._value
          });
        },
        onPanResponderMove: Animated.event([
          null,
          { dx: this.pan.x, dy: this.pan.y }
        ]),
        onPanResponderRelease: (e, gestureState) => {
          // 距边界的距离
          let space = 10;
          // 屏幕宽高
          let screenW = currentScreen().width;
          let screenH = currentScreen().height;
          let { locationX, locationY, pageX, pageY } = e.nativeEvent;
          let { dx, dy } = gestureState;
          // locationX locationY 触摸点相对于组件的位置
          // pageX pageY 触摸点相对于根元素也就是屏幕的位置
          // dx dy 拖动了多远
    
          // 1.计算出最后位置是应该吸附左侧还是右侧
          // 手势结束时组件的x坐标
          let finalX = pageX - locationX;
          let finalY = pageY - locationY;
    
          let isLeft = screenW / 2 > (finalX + this.viewW / 2);
    
          // 2.计算最终偏移量
          // 最终x轴偏移量
          let offsetX = 0;
          // 判断应该吸附在左边还是右边
          if (isLeft) {
            offsetX = dx - finalX + space;
          } else {
            offsetX = dx - (finalX + this.viewW + space - screenW);
          }
    
          let offsetY = dy;
          // 判断view是否超出顶部
          if (finalY < space) {
            offsetY -= (finalY - space);
          }
          // 判断view是否超出底部
          if (finalY + this.viewH + space > screenH) {
            offsetY -= (finalY + this.viewH + space - screenH);
          }
          Animated.spring(
            this.pan, // Auto-multiplexed
            {
              toValue: { x: offsetX, y: offsetY },
              speed: 150,
              bounciness: 0
            }
          ).start(() => {
            console.log('结束');
            this.pan.flattenOffset();
          });
        }
      });
    
      render() {
        let { renderContentView } = this.props;
        return (
          <Animated.View
            onLayout={(event) => {
              this.viewW = event.nativeEvent.layout.width;
              this.viewH = event.nativeEvent.layout.height;
              this.viewX = event.nativeEvent.layout.x;
              this.viewY = event.nativeEvent.layout.y;
            }}
            style={{
              transform: [{ translateX: this.pan.x }, { translateY: this.pan.y }]
            }}
            {...this.panResponder.panHandlers}
          >
            {renderContentView()}
          </Animated.View>
        );
      }
    }
    
    export default GJSuspendView;
    

    4. 总结

    我们在官方例子里加上一点四则运算,计算出最终的偏移量,最终达到了想要的效果,有时候官网已经帮我们把代码写好了😂

    RPReplay_Final1630898614.gif

    相关文章

      网友评论

        本文标题:RN-可拖动的悬浮按钮

        本文链接:https://www.haomeiwen.com/subject/rfpewltx.html