基于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;
相关推荐
闲暇部落33 分钟前
‌Kotlin中的?.和!!主要区别
android·开发语言·kotlin
诸神黄昏EX3 小时前
Android 分区相关介绍
android
GISer_Jing3 小时前
React核心功能详解(一)
前端·react.js·前端框架
大白要努力!4 小时前
android 使用SQLiteOpenHelper 如何优化数据库的性能
android·数据库·oracle
Estar.Lee4 小时前
时间操作[取当前北京时间]免费API接口教程
android·网络·后端·网络协议·tcp/ip
Winston Wood4 小时前
Perfetto学习大全
android·性能优化·perfetto
FØund4045 小时前
antd form.setFieldsValue问题总结
前端·react.js·typescript·html
疯狂的沙粒6 小时前
如何在 React 项目中应用 TypeScript?应该注意那些点?结合实际项目示例及代码进行讲解!
react.js·typescript
Dnelic-7 小时前
【单元测试】【Android】JUnit 4 和 JUnit 5 的差异记录
android·junit·单元测试·android studio·自学笔记
鑫宝Code7 小时前
【React】React Router:深入理解前端路由的工作原理
前端·react.js·前端框架