基于react native的锚点

基于react native的锚点

效果示例图

示例代码

复制代码
/* eslint-disable react-native/no-inline-styles */
import React, { useEffect, useRef, useState } from 'react';
import {
  Image,
  ImageBackground,
  ScrollView,
  StyleSheet,
  Text,
  TouchableOpacity,
  View,
} from 'react-native';
import HTML from 'react-native-render-html';
import { pxToPd, pxToPdT } from '../../common/js/device';
const desc =
  '<p>如违反《赛事须知》中的内容,可能使我受到警告、判负、丧失比赛资格/获奖资格以及禁赛等赛事处罚,亦可能被请离现场。如违反《赛事须知》中的内容,可能使我受到警告、判负、丧失比赛资格/获奖资格以及禁赛等赛事处罚,亦可能被请离现场。如违反《赛事须知》中的内容,可能使我受到警告、判负、丧失比赛资格/获奖资格以及禁赛等赛事处罚,亦可能被请离现场。</p>';

const tempData = [
  {
    id: 1,
    name: '工藤新一一级标题',
    data: [
      {
        id: 2,
        name: '二级标题002',
        content: desc,
      },
      {
        id: 3,
        name: '二级标题003',
        content: desc,
      },
      {
        id: 4,
        name: '二级标题004',
        content: desc,
      },
    ],
  },
  {
    id: 5,
    name: '毛利兰一级标题',
    data: [
      {
        id: 6,
        name: '二级标题006',
        content: desc,
      },
      {
        id: 7,
        name: '二级标题007',
        content: desc,
      },
      {
        id: 8,
        name: '二级标题008',
        content: desc,
      },
    ],
  },
  {
    id: 9,
    name: '流放了一级标题',
    data: [
      {
        id: 10,
        name: '二级标题0010',
        content: desc,
      },
      {
        id: 11,
        name: '二级标题0011',
        content: desc,
      },
      {
        id: 12,
        name: '二级标题0012',
        content: desc,
      },
    ],
  },
];

const TestCatalog = () => {
  const scrollViewRef = useRef(null);

  //列表数据
  const [dataList, setDataList] = useState([]);

  const viewRefs = useRef([]);
  const menuRef = useRef([]);

  const initFunction = () => {
    setDataList(() => tempData);
  };

  const goSkipHandle = row => {
    let tempArr = menuRef.current;
    tempArr.some(item => {
      if (item.id === row.id) {
        scrollViewRef.current.scrollTo({ y: item?.y - 100, animated: true });
      }
    });
  };

  const getPositionValue = (row, y) => {
    let tempMenu = [...menuRef.current];
    let tempItem = row;
    if (tempItem.y === undefined) {
      tempItem.y = y;
    }
    tempMenu.push(row);
    menuRef.current = tempMenu;
  };

  useEffect(() => {
    initFunction();
    return () => {};
  }, []);
  return (
    <>
      <View style={{ flex: 1 }}>
        <ScrollView ref={scrollViewRef}>
          {/* 列表内容 */}
          {dataList?.map((item, index) => (
            <View
              style={styles.ruleBlock}
              key={'ruleBlock-' + index}
              ref={ref => {
                viewRefs.current[item?.id] = ref;
              }}
              onLayout={() => {
                if (viewRefs.current[item?.id]) {
                  viewRefs.current[item?.id].measure(
                    (x, y, width, height, pageX, pageY) => {
                      console.log(x, y, width, height, pageX);
                      getPositionValue(item, pageY);
                    },
                  );
                }
              }}>
              {/* 一级标题 */}
              <View style={styles.ruleBlockTitle}>
                <ImageBackground
                  style={styles.ruleBlockTitleBg}
                  source={require('../../common/imgs/main_ruleDetail_titleBg.png')}>
                  <Text
                    style={styles.ruleBlockTitleTxt}
                    ellipsizeMode="middle"
                    numberOfLines={1}>
                    {item?.name}
                  </Text>
                </ImageBackground>
              </View>
              {/* 装饰图 */}
              <Image
                style={styles.ruleBlockDecorate}
                source={require('../../common/imgs/main_ruleDetail_tips.png')}
              />
              {/* 列表内容-start */}
              {item?.data?.map((subitem, subindex) => (
                <View
                  style={styles.ruleBlockSubCon}
                  key={'ruleBlockSubCon-' + subindex}>
                  {/* 二级标题 */}
                  <View
                    style={styles.ruleBlockSubTitle}
                    ref={ref => {
                      viewRefs.current[subitem?.id] = ref;
                    }}
                    onLayout={() => {
                      if (viewRefs.current[subitem?.id]) {
                        viewRefs.current[subitem?.id].measure(
                          (x, y, width, height, pageX, pageY) => {
                            console.log(x, y, width, height, pageX);
                            getPositionValue(subitem, pageY);
                          },
                        );
                      }
                    }}>
                    <Text style={styles.ruleBlockSubTitleTxt}>
                      {subitem?.name}
                    </Text>
                  </View>
                  {/* 内容 */}
                  <View style={{ width: '100%', height: pxToPd(24) }} />
                  <View style={styles.ruleBlockSubDesc}>
                    <HTML
                      contentWidth={100}
                      source={{
                        html: `<div>${subitem?.content}</div>`,
                      }}
                    />
                  </View>
                </View>
              ))}

              {/* 列表内容-end*/}

              <View style={{ width: '100%', height: pxToPd(40) }} />
            </View>
          ))}
        </ScrollView>
      </View>
      <View style={styles.modalWrap}>
        {dataList?.map(item => (
          <View>
            <TouchableOpacity onPress={() => goSkipHandle(item)}>
              <Text
                style={{
                  width: '100%',
                  height: pxToPd(60),
                  lineHeight: pxToPd(60),
                  textAlign: 'center',
                }}>
                {item?.name}
              </Text>
            </TouchableOpacity>
            {item?.data?.map(subitem => (
              <TouchableOpacity onPress={() => goSkipHandle(subitem)}>
                <Text
                  style={{
                    width: '100%',
                    height: pxToPd(60),
                    lineHeight: pxToPd(60),
                    textAlign: 'center',
                  }}>
                  {subitem?.name}
                </Text>
              </TouchableOpacity>
            ))}
          </View>
        ))}
      </View>
    </>
  );
};

const styles = StyleSheet.create({
  detailBg: {
    width: '100%',
    height: pxToPd(1624),
  },
  container: {
    flex: 1,
    position: 'absolute',
    top: 0,
    left: 0,
    right: 0,
    bottom: 0,
  },
  //内容
  ruleBlock: {
    width: '93.6%',
    marginLeft: '3.2%',
    borderRadius: pxToPd(40),
    backgroundColor: '#fff',
    minHeight: pxToPd(400),
    position: 'relative',
    marginBottom: pxToPd(97),
  },
  ruleBlockTitle: {
    width: pxToPd(533),
    height: pxToPd(86),
    marginLeft: -pxToPd(8),
    marginTop: -pxToPd(8),
  },
  ruleBlockTitleBg: {
    width: '100%',
    height: '100%',
  },
  ruleBlockTitleTxt: {
    height: pxToPd(86),
    width: pxToPd(500),
    lineHeight: pxToPd(86),
    fontSize: pxToPdT(32),
    fontWeight: 'bold',
    color: '#fff',
    marginLeft: pxToPd(19),
  },
  ruleBlockDecorate: {
    width: pxToPd(160),
    height: pxToPd(193),
    position: 'absolute',
    top: -pxToPd(14),
    right: -pxToPd(1),
  },
  ruleBlockSubCon: {
    width: '93.6%',
    marginLeft: '3.2%',
    marginTop: pxToPd(42),
  },
  ruleBlockSubTitle: {
    width: '100%',
  },
  ruleBlockSubTitleTxt: {
    width: '100%',
    fontSize: pxToPdT(30),
    fontWeight: 'normal',
    color: '#333',
    textAlign: 'center',
  },
  ruleBlockSubDesc: {
    width: '100%',
  },
  modalWrap: {
    borderRadius: pxToPd(24),
    width: pxToPd(300),
    position: 'absolute',
    top: 100,
    right: 20,
    backgroundColor: '#f5f5f5',
    flexDirection: 'column',
  },
});

export default TestCatalog;
相关推荐
Jerry17 分钟前
Compose 5 个简短动画,让您的应用脱颖而出
android
天天进步201538 分钟前
掌握React状态管理:Redux Toolkit vs Zustand vs Context API
linux·运维·react.js
冷冷的菜哥42 分钟前
react实现无缝轮播组件
前端·react.js·typescript·前端框架·无缝轮播
PenguinLetsGo1 小时前
你的App是否有出现过幽灵调用?
android
用户7678797737321 小时前
后端转全栈之Next.js文件约定
react.js·next.js
没有了遇见1 小时前
Android ViewPager2 嵌套 RecyclerView 滑动冲突解决方案
android
咖啡の猫2 小时前
Android开发-选择按钮
android·gitee
火柴就是我2 小时前
android 以maven的方式 引入本地的aar
android
过-眼-云-烟2 小时前
新版Android Studio能打包但无法run ‘app‘,编译通过后手机中没有安装,顶部一直转圈
android·ide·android studio
hedalei3 小时前
android14 硬键盘ESC改BACK按键返回无效问题
android·android14·esc·back按键