Реагировать на собственный многоколонный баннер вставки FlatList - PullRequest
5 голосов
/ 15 июня 2019

Я использую мультиколонку FlatList в своем приложении React Native для отображения элементов, как показано ниже (левое изображение). Я пытаюсь интегрировать баннер AdMob в приложение, как это делали многие другие приложения, и вставить рекламный баннер в середину списка, как показано ниже (правое изображение).

Насколько я могу судить, FlatList не поддерживает этот тип макета "из коробки". Мне интересно, что было бы полезно для реализации этой функции и не влияет на производительность приложения.

(Примечание: список поддерживает функцию «подтянуть-обновить» и бесконечную загрузку при приближении к концу списка.).

Заранее благодарю за любые предложения.

enter image description here

Ответы [ 2 ]

5 голосов
/ 17 июня 2019

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

Допустим, у нас есть следующая структура данных:

const DATA = 
[{ id: 1, title: "Item One"}, { id: 2, title: "Item Two"}, { id: 3, title: "Item Three"}, 
{ id: 4, title: "Item Four"}, { id: 5, title: "Item Five"}, { id: 6, title: "Item Six"}, 
{ id: 7, title: "Item Seven"}, { id:8, title: "Item Eight"}, { id: 9, title: "Item Nine"}, 
{ id: 10, title: "Item Ten"}, { id: 11, title: "Item eleven"}, 
{ id: 12, title: "Item Twelve"}, { id: 13, title: "Item Thirteen"}];

Как я уже сказал, мы не используем свойство numColumns вместо этого, мы реструктурируем наши данные, чтобы мы могли представить наш список так, как мы хотим,В этом случае мы хотим иметь 3 столбца, а после шести элементов мы хотим показывать рекламный баннер.

Модификация данных:

  modifyData(data) { 
    const  numColumns = 3;
    const addBannerAfterIndex = 6;
    const arr = [];
    var tmp = [];
    data.forEach((val, index) => {
      if (index % numColumns == 0 && index != 0){
        arr.push(tmp);
        tmp = [];
      }
      if (index % addBannerAfterIndex == 0 && index != 0){
        arr.push([{type: 'banner'}]);
        tmp = [];
      }
      tmp.push(val);
    });
    arr.push(tmp);
    return arr; 
  }

Теперь мы можем отобразить наши преобразованные данные:

Основная функция визуализации:

render() {
    const newData = this.modifyData(DATA); // here we can modify the data, this is probably not the spot where you want to trigger the modification 
    return (
      <View style={styles.container}>
        <FlatList 
        data={newData}
        renderItem={({item, index})=> this.renderItem(item, index)}
        /> 
      </View>
    );
}

Функция RenderItem:

Я удалил некоторые встроенные стили, чтобы сделать их более понятными.

renderItem(item, index) {
    // if we have a banner item we can render it here 
    if (item[0].type == "banner"){
      return (
         <View key={index} style={{width: WIDTH-20, flexDirection: 'row'}}>
        <Text style={{textAlign: 'center', color: 'white'}}> YOUR AD BANNER COMPONENT CAN BE PLACED HERE HERE </Text>
      </View>
      )
    }

    //otherwise we map over our items and render them side by side 
     const columns = item.map((val, idx) => {
      return (
        <View style={{width: WIDTH/3-20, justifyContent: 'center', backgroundColor: 'gray', height: 60, marginLeft: 10, marginRight: 10}} key={idx}>
          <Text style={{textAlign: 'center'}}> {val.title} </Text>
        </View>
      )
    });
    return (
      <View key={index} style={{width: WIDTH, flexDirection: 'row', marginBottom: 10}}>
      {columns}
      </View>
    )
  }

Выход:

output

Пример работы:

https://snack.expo.io/SkmTqWrJS

1 голос
/ 18 июня 2019

Я бы порекомендовал этот прекрасный пакет https://github.com/Flipkart/recyclerlistview

На самом деле, мы обрабатывали тысячи списков данных в нашем приложении, flatlist смог справиться с этим довольно хорошо, но все же мы искали высокую производительностьКомпонент listview для плавного рендеринга и эффективного использования памятиМы наткнулись на этот пакет.Поверьте мне, это здорово.

Что касается вашего вопроса, этот пакет имеет функцию рендеринга нескольких представлений из коробки.Он также получил хорошую документацию.

Таким образом, пакет имеет три важных шага для настройки просмотра списка.

  • DataProvider - Функция конструктора, определяющая данные для каждого элемента
  • LayoutProvider - Функция конструктора, которая определяет макет (высоту / ширину) каждого элемента
  • RowRenderer - точно так же, как свойство renderItem в flatlist.

Базовый код выглядит следующим образом:

import React, { Component } from "react";
import { View, Text, Dimensions } from "react-native";
import { RecyclerListView, DataProvider, LayoutProvider } from "recyclerlistview";

const ViewTypes = {
    FULL: 0,
    HALF_LEFT: 1,
    HALF_RIGHT: 2
};

let containerCount = 0;

class CellContainer extends React.Component {
    constructor(args) {
        super(args);
        this._containerId = containerCount++;
    }
    render() {
        return <View {...this.props}>{this.props.children}<Text>Cell Id: {this._containerId}</Text></View>;
    }
}


export default class RecycleTestComponent extends React.Component {
    constructor(args) {
        super(args);

        let { width } = Dimensions.get("window");

        //Create the data provider and provide method which takes in two rows of data and return if those two are different or not.


        let dataProvider = new DataProvider((r1, r2) => {
            return r1 !== r2;
        });

        //Create the layout provider
        //First method: Given an index return the type of item e.g ListItemType1, ListItemType2 in case you have variety of items in your list/grid

        this._layoutProvider = new LayoutProvider(
            index => {
                if (index % 3 === 0) {
                    return ViewTypes.FULL;
                } else if (index % 3 === 1) {
                    return ViewTypes.HALF_LEFT;
                } else {
                    return ViewTypes.HALF_RIGHT;
                }
            },
            (type, dim) => {
                switch (type) {
                    case ViewTypes.HALF_LEFT:
                        dim.width = width / 2;
                        dim.height = 160;
                        break;
                    case ViewTypes.HALF_RIGHT:
                        dim.width = width / 2;
                        dim.height = 160;
                        break;
                    case ViewTypes.FULL:
                        dim.width = width;
                        dim.height = 140;
                        break;
                    default:
                        dim.width = 0;
                        dim.height = 0;
                }
            }
        );

        this._rowRenderer = this._rowRenderer.bind(this);

        //Since component should always render once data has changed, make data provider part of the state


        this.state = {
            dataProvider: dataProvider.cloneWithRows(this._generateArray(300))
        };
    }

    _generateArray(n) {
        let arr = new Array(n);
        for (let i = 0; i < n; i++) {
            arr[i] = i;
        }
        return arr;
    }

    //Given type and data return the view component

    _rowRenderer(type, data) {
        //You can return any view here, CellContainer has no special significance
        switch (type) {
            case ViewTypes.HALF_LEFT:
                return (
                    <CellContainer style={styles.containerGridLeft}>
                        <Text>Data: {data}</Text>
                    </CellContainer>
                );
            case ViewTypes.HALF_RIGHT:
                return (
                    <CellContainer style={styles.containerGridRight}>
                        <Text>Data: {data}</Text>
                    </CellContainer>
                );
            case ViewTypes.FULL:
                return (
                    <CellContainer style={styles.container}>
                        <Text>Data: {data}</Text>
                    </CellContainer>
                );
            default:
                return null;
        }
    }

    render() {
        return <RecyclerListView layoutProvider={this._layoutProvider} dataProvider={this.state.dataProvider} rowRenderer={this._rowRenderer} />;
    }
}
const styles = {
    container: {
        justifyContent: "space-around",
        alignItems: "center",
        flex: 1,
        backgroundColor: "#00a1f1"
    },
    containerGridLeft: {
        justifyContent: "space-around",
        alignItems: "center",
        flex: 1,
        backgroundColor: "#ffbb00"
    },
    containerGridRight: {
        justifyContent: "space-around",
        alignItems: "center",
        flex: 1,
        backgroundColor: "#7cbb00"
    }
};

В LayoutProvider вы можете возвращать несколько типов представлений, основанных на индексе, или вы можете добавить объект viewType в массив данных, отображая представления на основе этого.

this._layoutProvider = new LayoutProvider(
            index => {
                if (index % 3 === 0) {
                    return ViewTypes.FULL;
                } else if (index % 3 === 1) {
                    return ViewTypes.HALF_LEFT;
                } else {
                    return ViewTypes.HALF_RIGHT;
                }
            },
            (type, dim) => {
                switch (type) {
                    case ViewTypes.HALF_LEFT:
                        dim.width = width / 2;
                        dim.height = 160;
                        break;
                    case ViewTypes.HALF_RIGHT:
                        dim.width = width / 2;
                        dim.height = 160;
                        break;
                    case ViewTypes.FULL:
                        dim.width = width;
                        dim.height = 140;
                        break;
                    default:
                        dim.width = 0;
                        dim.height = 0;
                }
            }
        );

tl; dr: Проверьте https://github.com/Flipkart/recyclerlistview и используйте layoutProvider для визуализации другого вида.

Запустите перекус: https://snack.expo.io/B1GYad52b

...