根据 rotation/size 更改 Flatlist 列数的脚本有问题

Problem with script to change number of Flatlist columns depending on rotation/size

我正在编写一些代码来计算平面列表的 numColumns - 意图是在横向平板电脑上 3 个,在纵向平板电脑上 2 个,在纵向平板电脑上 1 个 phone。

这是我的代码:

const [width, setWidth] = useState(Dimensions.get('window').width);
const [imageWidth, setImageWidth] = useState(100);
const [imageHeight, setImageHeight] = useState(100);

const [columns, setColumns] = useState(3);

useEffect(() => {
    function handleChange() {
        setWidth(Dimensions.get('window').width);
    }
    Dimensions.addEventListener("change", handleChange);
    return () => Dimensions.removeEventListener("change", handleChange);
}, [width]);

useEffect(() => {
    if (width > 1100) {
        setColumns(3);
    } else if (width <= 1099 && width > 600) {
        setColumns(2);
    } else {
        setColumns(1);
    }
    setImageWidth((width - (64 * columns) + 15) / columns);
    setImageHeight(((width - (64 * columns) + 15) / columns) * .6);
}, [width]);

imageWidth 和 imageHeight 被传递到 flatlist 的渲染组件以调整图像大小。

当我在横向模式下加载它时似乎工作正常,但如果我旋转到纵向模式,我得到这个:

然后,如果我回到横向,它仍然是 2 列?

知道如何解决这个问题吗?

您返回的不是设备的高度,之后,您需要计算设备的方向(isLandscape)。

逻辑上它的流程如下:

  1. 是设备横向吗? (setColumns 3)
  2. 设备是宽屏还是竖屏? (设置第 2 列)
  3. 其他(setColumns 1)

从那里您可以将其传递到第二个 useEffect(例如,useColumnsHook)。这应该能够根据设备的方向设置 height/width。

我还建议根据设备的百分比而不是精确像素设置 height/width (100%, 50%, 33.3%)。

const [width, setWidth] = useState(Dimensions.get('window').width);
const [imageWidth, setImageWidth] = useState(100);
const [imageHeight, setImageHeight] = useState(100);

const [columns, setColumns] = useState(3);

/**
 * orientation
 * 
 * return {
 *   width,
 *   height
 * }
 */
const useScreenData = () => {
  const [screenData, setScreenData] = useState(Dimensions.get("screen"))

  useEffect(() => {
    const onChange = (result) => {
      setScreenData(result.screen)
    }

    Dimensions.addEventListener("change", onChange)

    return () => Dimensions.removeEventListener("change", onChange)
  })

  return {
    ...screenData,
  }
}

const { width, height } = useScreenData()
const isLandscape = width > height


useEffect(() => {
  if (isLandscape && width > 1100) {
    // handle landscape
    setColumns(3)
  } else if (!isLandscape && (width <= 1099 && width > 600)) {
    setColumns(2)
  } else {
    setColumns(1)
  }

  setImageWidth((width - (64 * columns) + 15) / columns);
  setImageHeight(((width - (64 * columns) + 15) / columns) * .6);
}, [width, isLandscape]);

1:平板电脑或Phone

您可以将 react-native-device-info 包与维度 API 一起使用。检查isTablet()方法并根据结果应用不同的样式。

如果你关心 Expo 用户,那么你必须使用 expo-constants userInterfaceIdiom 方法来检测 isTablet Reference

import DeviceInfo from 'react-native-device-info';

let isTablet = DeviceInfo.isTablet();

2:纵向模式或横向模式

然后你可以通过

找到纵向模式或横向模式
const isPortrait = () => {
    const dim = Dimensions.get('screen');
    return dim.height >= dim.width;
};

3:代码:

import React, { useState, useEffect } from "react";
import { View, Text, Dimensions } from "react-native";
import DeviceInfo from "react-native-device-info";

const App = () => {
  const isLandscapeFunction = () => {
    const dim = Dimensions.get("screen");
    return dim.width >= dim.height;
  };

  const [width, setWidth] = useState(Dimensions.get("window").width);
  const [imageWidth, setImageWidth] = useState(100);
  const [imageHeight, setImageHeight] = useState(100);

  const [columns, setColumns] = useState(3);

  let isTabletPhone = DeviceInfo.isTablet();;
  useEffect(() => {
    function handleChange(result) {
      setWidth(result.screen.width);
      const isLandscape = isLandscapeFunction();
      if (isLandscape && isTabletPhone) {
        setColumns(3);
      } else if (!isLandscape && isTabletPhone) {
        setColumns(2);
      } else {
        setColumns(1);
      }
    }
    Dimensions.addEventListener("change", handleChange);
    return () => Dimensions.removeEventListener("change", handleChange);
  });


  useEffect(() => {
    console.log(columns);
    setImageWidth((width - 64 * columns + 15) / columns);
    setImageHeight(((width - 64 * columns + 15) / columns) * 0.6);
  }, [columns, width]);

  return (
    <View style={{ justifyContent: "center", alignItems: "center", flex: 1 }}>
      <Text>imageWidth {imageWidth}</Text>
      <Text>imageHeight {imageHeight}</Text>
    </View>
  );
};

export default App;