基于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;
相关推荐
雨白21 分钟前
Jetpack系列(二):Lifecycle与LiveData结合,打造响应式UI
android·android jetpack
小白变怪兽22 分钟前
一、react18+项目初始化(vite)
前端·react.js
kk爱闹2 小时前
【挑战14天学完python和pytorch】- day01
android·pytorch·python
每次的天空4 小时前
Android-自定义View的实战学习总结
android·学习·kotlin·音视频
恋猫de小郭4 小时前
Flutter Widget Preview 功能已合并到 master,提前在体验毛坯的预览支持
android·flutter·ios
断剑重铸之日5 小时前
Android自定义相机开发(类似OCR扫描相机)
android
随心最为安5 小时前
Android Library Maven 发布完整流程指南
android
岁月玲珑5 小时前
【使用Android Studio调试手机app时候手机老掉线问题】
android·ide·android studio
然我9 小时前
React 开发通关指南:用 HTML 的思维写 JS🚀🚀
前端·react.js·html
还鮟9 小时前
CTF Web的数组巧用
android