热搜:fiddler git ip ios 代理
历史搜索

React Native仿微信通讯录侧边栏滑动选择代码

游客2024-08-22 14:33:01

React Native 仿微信通讯录侧边栏滑动选择效果:

React Native仿微信通讯录侧边栏滑动选择代码 1

完整代码:

import React, {useRef, useEffect} from 'react';
import {Dimensions, StyleSheet, View, Text, SafeAreaView} from 'react-native';
// 获取屏幕宽高
let ScreenWidth = Dimensions.get('window').width;
let ScreenHeight = Dimensions.get('window').height;
// 始终返回 true 的函数,用于设置触摸响应
const returnTrue = () => true;
const TestScreen = () => {
  const alphabet = [
    'A',
    'B',
    'C',
    'D',
    'E',
    'F',
    'G',
    'H',
    'I',
    'J',
    'K',
    'L',
    'M',
    'N',
    'O',
    'P',
    'Q',
    'R',
    'S',
    'T',
    'U',
    'V',
    'W',
    'X',
    'Y',
    'Z',
  ];
  // 创建 ref 来存储 select_null 和 measure 的值
  const selectNull = useRef(null);
  const measure = useRef({});
  // 创建 ref 来引用 sectionItem 的 view
  const sectionItemRef = useRef(null);
  // 修复 sectionItem 的尺寸测量
  const fixSectionItemMeasure = () => {
    const sectionItem = sectionItemRef.current;
    if (!sectionItem) {
      return;
    }
    setTimeout(() => {
      sectionItem.measure((x, y, width, height, pageX, pageY) => {
        // 存储测量的数据
        measure.current = {
          y: pageY,
          width,
          height,
        };
      });
    }, 0);
  };

  // 根据触摸点定位字母
  const getZM = (topHeight, currentHeight) => {
    const navItemHeight = 26; // 字母栏的高度(要在样式里面也设置高度,这里的高度是根据样式动态改变的,字母栏样式的高是多少,这里就写多少)
    // 计算触摸点在导航中的索引
    const indexNav = Math.ceil((currentHeight - topHeight) / navItemHeight) - 1; // ((当前距离屏幕距离-父容器距离屏幕距离) / 元素高度) - 1 = (当前的索引元素距离父容器顶部距离 / 元素高度) - 1 = 第 n 个字母 - 1 = 当前字母的索引值
    if (alphabet[indexNav]) {
      console.log(alphabet[indexNav]); // 在当前触摸点上面
      return alphabet[indexNav]; // 返回当前字母
    } else {
      console.log('null'); // 不在触摸点打印下 null
    }
  };

  // 处理触摸事件,该事件在用户触摸屏幕时调用
  const selectNav = e => {
    const ev = e.nativeEvent.touches[0]; // 获取多个触摸事件的第一个。比如你放了三根手指在屏幕上,他只算第一个放到屏幕上的
    const targetY = ev.pageY; // 动态获取屏幕上触摸点垂直方向的距离
    const localY = ev.locationY; // 第一次触摸到屏幕上距离顶部的距离
    const {y, width, height} = measure.current; // 获取当前的容器距离顶部的距离(这里因为父容器是 top:20,所以这里获取的是 20)
    console.log('y', y, targetY);
    // 调用 getZM 函数进行字母定位
    getZM(y, targetY); // 定位字母,并且触发相应的事件
  };

  // 在组件挂载时修复尺寸,该方法在组件第一次渲染后执行
  useEffect(() => {
    fixSectionItemMeasure();
  }, []);

  // 在组件更新时也修复尺寸,该方法在组件更新后执行
  useEffect(() => {
    fixSectionItemMeasure();
  });

  // 渲染函数组件
  return (
    <SafeAreaView>
      <View
        style={{
          width: ScreenWidth,
          height: ScreenHeight,
          position: 'relative',
        }}>
        <View
          ref={sectionItemRef} // 将当前 View 的引用存储到 sectionItemRef 中,以便后续可以通过 ref 访问它
          style={styles.container} // 设置 View 的样式,使用前面定义的 styles.container 样式
          onStartShouldSetResponder={returnTrue} // 定义当用户开始触摸屏幕时是否应该成为响应者的条件
          onMoveShouldSetResponder={returnTrue} // 定义当用户移动手指时是否应该成为响应者的条件
          onResponderGrant={selectNav} // 当响应器被激活时(即用户开始触摸屏幕)调用的函数
          onResponderMove={selectNav} // 当响应器在激活状态下移动时调用的函数
          onResponderRelease={selectNull.current} // 当响应器被释放(即用户停止触摸屏幕)时调用的函数
        >
          {alphabet.map((item, index) => {
            return (
              <View style={styles.oit} key={index}>
                <Text style={{lineHeight: 26, textAlign: 'center'}}>
                  {item}
                </Text>
              </View>
            );
          })}
        </View>
      </View>
    </SafeAreaView>
  );
};

// 样式定义
const styles = StyleSheet.create({
  container: {
    position: 'absolute',
    top: 20,
    right: 0,
    width: 80,
    height: 676,  // 26*26 26 个单词,每个单词 26 高度
    backgroundColor: 'pink',
  },
  oit: {
    flexShrink: 0,
    height: 26, // 高度自己慢慢调整(如果使用了 flex 布局,一定要看好自己的高度是否被正确设置	)
    width: '100%',
  },
});

export default TestScreen;
标签:React