Как получить измерение нескольких представлений с помощью onLayout только с одной функцией в React Native?

Я лично считаю, что самый аккуратный способ (а не самый быстрый) - с рекурсией.

function convert(num) { 
  if(num < 1){ return "";}
  if(num >= 40){ return "XL" + convert(num - 40);}
  if(num >= 10){ return "X" + convert(num - 10);}
  if(num >= 9){ return "IX" + convert(num - 9);}
  if(num >= 5){ return "V" + convert(num - 5);}
  if(num >= 4){ return "IV" + convert(num - 4);}
  if(num >= 1){ return "I" + convert(num - 1);}  
}
console.log(convert(39)); 
//Output: XXXIX

Это будет поддерживать только числа 1-40, но его можно легко расширить, следуя шаблону.

2
задан Pouya92 5 March 2019 в 05:47
поделиться

1 ответ

Вы не можете сделать это с помощью одной функции onLayout, так как вы используете две различные функции в текущей настройке. Так что это можно сделать с двумя. Вам просто нужно немного абстрагировать код, и тогда можно будет заставить его работать.

Если мы думаем о сетке, которую вы строите таким образом, мы можем легко найти каждую ячейку в сетке, если будем следовать прямому соглашению об именах XY, где X - строка, а Y - столбец.

+----+----+----+
| 11 | 12 | 13 |
+----+----+----+
| 21 | 22 | 23 |
+----+----+----+
| 31 | 32 | 33 |
+----+----+----+

Используя эту идею, мы можем изменить ваши две onLayout функции таким образом:

getExactPos = (e, key) => { // pass a key as well now
  const { width, height, x, y } = e.nativeEvent.layout;
  let position = {};
  position.gridXstart = x;
  position.gridXend = x + width;
  position.gridYstart = y;
  position.gridYend = y + height;
  this.setState({ [key]: position }); // notice that we use the key to store it in state
}

getExactPosRow = (e, key) => {  // pass a key as well now
  const { y } = e.nativeEvent.layout;
  this.setState({ [key]: y });  // notice that we use the key to store it in state
};

Мы установим ключи, используемые в этой функции, в constructViews функция ниже. Теперь с их помощью мы можем построить функцию, которая, в свою очередь, построит сетку:

constructViews = () => {
  let rows = [];
  for (let i = 1; i < 4; i++) {
    let row = [];
    for (let j = 1; j < 4; j++) {
      let stateKey = `${i}${j}`;
      let styleKey = `box${stateKey}`;
      row.push(
        <View onLayout={ (e) => this.getExactPos(e, stateKey)} style={styles[styleKey]} key={stateKey}><Text>{this.state[styleKey]}</Text></View>
      );
    }
    rows.push(
      <View onLayout={e => this.getExactPosRow(e, `${i}`)} style={styles[`row${i}`]} key={i}>{row}</View>
    );
  }
  return rows;
}

В этой функции у нас есть вложенное for-loop, которое создает сетку. Обратите внимание, что мы создаем и передаем ключи двум созданным нами функциям onLayout. Мы можем расширить идею использования ключей дальше, динамически получая правильные стили и правильный текст.

Вот оно в рабочем POC. Это должно дать вам достаточно, чтобы реализовать то, что вы хотите. Я не внедрил никаких средств реагирования на жесты и оставлю это на ваше усмотрение.

import React from 'react';
import { Text, View, StyleSheet, Button } from 'react-native';

export default class App extends React.Component {
  state = {
    box11: 'Box 11',
    box12: 'Box 12',
    box13: 'Box 13',
    box21: 'Box 21',
    box22: 'Box 22',
    box23: 'Box 23',
    box31: 'Box 31',
    box32: 'Box 32',
    box33: 'Box 33'
  }

    getExactPos = (e, key) => {
      const { width, height, x, y } = e.nativeEvent.layout;
      let position = {};
      position.gridXstart = x;
      position.gridXend = x + width;
      position.gridYstart = y;
      position.gridYend = y + height;
      this.setState({ [key]: position });
    }

  getExactPosRow = (e, key) => {
    const { y } = e.nativeEvent.layout;
    this.setState({
      [key]: y
    });
  };

  constructViews = () => {
    let rows = [];
    for (let i = 1; i < 4; i++) {
      let row = [];
      for (let j = 1; j < 4; j++) {
        let stateKey = `${i}${j}`;
        let styleKey = `box${stateKey}`;
        row.push(
          <View onLayout={ (e) => this.getExactPos(e, stateKey)} style={styles[styleKey]} key={stateKey}><Text>{this.state[styleKey]}</Text></View>
        );
      }
      rows.push(
        <View onLayout={e => this.getExactPosRow(e, `${i}`)} style={styles[`row${i}`]} key={i}>{row}</View>
      );
    }
    return rows;
  }

  render () {
    return (
      <View style={{ justifyContent: 'center', alignItems: 'center', flex: 1 }}>
        <View style={{ flex: 1 }}></View>
        <Button onPress={() => console.log(this.state)} title={'console log state'} />
        <View style={{ flex: 4, backgroundColor: 'red', marginLeft: 20, marginRight: 20 }} >
          {this.constructViews()}
        </View>
        <View style={{ flex: 1 }}></View>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  row1: { flexDirection: 'row', flex: 1, backgroundColor: 'red', width: '100%' },
  row2: { flexDirection: 'row', flex: 1, backgroundColor: 'blue', width: '100%' },
  row3: { flexDirection: 'row', flex: 1, backgroundColor: 'green', width: '100%' },
  box11: { flex: 1, backgroundColor: 'yellow', justifyContent: 'center', alignItems: 'center' },
  box12: { flex: 1, backgroundColor: 'orange', justifyContent: 'center', alignItems: 'center' },
  box13: { flex: 1, backgroundColor: 'gray', justifyContent: 'center', alignItems: 'center' },
  box21: { flex: 1, backgroundColor: 'green', justifyContent: 'center', alignItems: 'center' },
  box22: { flex: 1, backgroundColor: 'red', justifyContent: 'center', alignItems: 'center' },
  box23: { flex: 1, backgroundColor: 'blue', justifyContent: 'center', alignItems: 'center' },
  box31: { flex: 1, backgroundColor: 'purple', justifyContent: 'center', alignItems: 'center' },
  box32: { flex: 1, backgroundColor: 'skyblue', justifyContent: 'center', alignItems: 'center' },
  box33: { flex: 1, backgroundColor: '#124567', justifyContent: 'center', alignItems: 'center' }
});

Здесь вы можете увидеть, как он работает в этой закуске https://snack.expo.io/@andypandy/dynamic-grid-using-onlayout

0
ответ дан Andrew 5 March 2019 в 05:47
поделиться
Другие вопросы по тегам:

Похожие вопросы: