1. 程式人生 > >react-native 之SwipeableFlatList 側滑單項解決方案

react-native 之SwipeableFlatList 側滑單項解決方案

react-native 側滑元件SwipeableFlatList 單項側滑解決

SwipeableFlatList 元件是 rn 0.50 出的 提供android ios 側滑刪除

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * @format
 * @flow
 */

import React, { Component } from 'react';
import { Platform, StyleSheet, Text, View, SwipeableFlatList, TouchableHighlight } from 'react-native'
; const CITY_NAMES = ['北京', '上海', '廣州', '杭州', '蘇州']; export default class App extends Component<Props> { render() { return ( <View style={styles.container}> <SwipeableFlatList //1資料的獲取和渲染 data={CITY_NAMES} renderItem={(data) => <View style={styles.item}> <Text style={styles.text}>{data.item}</Text> </View>} //2建立側滑選單
renderQuickActions={() => this.getQuickActions()}//建立側滑選單 maxSwipeDistance={80}//可展開(滑動)的距離 bounceFirstRowOnMount={false}//進去的時候不展示側滑效果 /> </View> ); } //側滑選單渲染 getQuickActions = () => { return <View style={styles.quickAContent}> <TouchableHighlight onPress={() => alert("確認刪除?"
)} > <View style={styles.quick}> <Text style={styles.delete}>刪除</Text> </View> </TouchableHighlight> </View> }; } const styles = StyleSheet.create({ container: { flex: 1, }, item: { backgroundColor: '#aeffb1', height: 100, marginRight: 15, marginLeft: 15, marginBottom: 10, alignItems: 'center', justifyContent: 'center', elevation: 5,//漂浮的效果 borderRadius: 5,//圓角 }, text: { color: '#444444', fontSize: 20, }, //側滑選單的樣式 quickAContent: { flex: 1, flexDirection: 'row', justifyContent: 'flex-end', marginRight: 15, marginBottom: 10, }, quick: { backgroundColor: "#ff1d49", flex: 1, alignItems: 'flex-end',//水平靠右 justifyContent: 'center',//上下居中 width: 100, borderRadius: 5, elevation: 5,//漂浮的效果 }, delete: { color: "#d8fffa", marginRight: 30 } });

bug點在於 該元件api 說明不提供關閉側滑功能 以及只支援單個側滑(及開啟一個側滑關閉上面的側滑)
分析原始碼

在node_modules/react-native/Libraies/Experimental/SwipeableRow/ 下面


SwipeableFlatList
看到 render 仍是FlatList 看到他裡面renderItem

_renderItem = (info: Object): ?React.Element<any> => {

    const slideoutView = this.props.renderQuickActions(info);
    const key = this.props.keyExtractor(info.item, info.index);

//就有無側滑
    // If renderQuickActions is unspecified or returns falsey, don't allow swipe
    if (!slideoutView) {
      return this.props.renderItem(info);
    }

    let shouldBounceOnMount = false;
    if (this._shouldBounceFirstRowOnMount) {
      this._shouldBounceFirstRowOnMount = false;
      shouldBounceOnMount = true;
    }

    return (
      <SwipeableRow
        slideoutView={slideoutView}
        //這裡我們看到他實際上是每個開啟關閉都是有的但是flatlist不重新整理 
        isOpen={key === this.state.openRowKey}
        maxSwipeDistance={this._getMaxSwipeDistance(info)}
        onOpen={() => this._onOpen(key)}
        onClose={() => this._onClose(key)}
        shouldBounceOnMount={shouldBounceOnMount}
        onSwipeEnd={this._setListViewScrollable}
        onSwipeStart={this._setListViewNotScrollable}>
        {this.props.renderItem(info)}
      </SwipeableRow>
    );
  };
 _onOpen(key: any): void {
    this.setState({
      openRowKey: key,
    });
  }

  _onClose(key: any): void {
    this.setState({
      openRowKey: null,
    });
  }
在 SwipeableRow元件中

UNSAFE_componentWillReceiveProps(nextProps: Object): void {
    /**
     * We do not need an "animateOpen(noCallback)" because this animation is
     * handled internally by this component.
     */
     也是做了isOpen 更新會出處罰這關閉item
    if (this.props.isOpen && !nextProps.isOpen) {
      this._animateToClosedPosition();
    }
  },

看了什麼實際上SwipeableFlatList 是做了只支援單項了操作但是為什麼能開啟多個側滑那
原因在於flatlist 的data 是陣列引用問題 data如果引用不變是不會觸發flatlist的重新整理

這裡就需要用到一個 flatlist extraData 的屬性

extraData
如果有除data以外的資料用在列表中(不論是用在renderItem還是頭部或者尾部元件中),請在此屬性中指定。同時此資料在修改時也需要先修改其引用地址(比如先複製到一個新的 Object 或者陣列中),然後再修改其值,否則介面很可能不會重新整理。

我們修改原始碼

 render(): React.Node {
    return (
      <FlatList
        {...this.props}
        ref={ref => {
          this._flatListRef = ref;
        }}
        //就加入這行效果就可行了
        extraData={{
          ...this.state,
          ...this.props.extraData
        }}
        onScroll={this._onScroll}
        renderItem={this._renderItem}
      />
    );
  }

這裡我們封裝一個新的SwipeableFlatList 來避免修改原始碼的方式

import { SwipeableFlatList, FlatList } from 'react-native'
import React from 'react'

export default class fixSwipeadFlatList extends SwipeableFlatList {
    render(): React.Node {
        return (
            <FlatList
                {...this.props}
                ref={ref => {
                    this._flatListRef = ref;
                }}
                extraData={this.state}
                onScroll={this._onScroll}
                renderItem={this._renderItem}
            />
        );
    }
}

還有 當你單擊完手動關閉側滑 我們看到 SwipeableFlatList 是提供了 我們自己使用引用去手動調關閉方法

_onClose(key: any): void {
    this.setState({
      openRowKey: null,
    });

手動關閉側滑

<SwipeableFlatList
          //1資料的獲取和渲染
          data={CITY_NAMES}
          renderItem={(data) => <View style={styles.item}>
            <Text style={styles.text}>{data.item}</Text>
          </View>}
 ref={ref => {
  this._flatListRef = ref;
}}
          //2建立側滑選單
          renderQuickActions={() => this.getQuickActions()}//建立側滑選單
          maxSwipeDistance={80}//可展開(滑動)的距離
          bounceFirstRowOnMount={false}//進去的時候不展示側滑效果
        />

  <TouchableHighlight
        onPress={() =>this._flatListRef._onClose()}
      >
        <View style={styles.quick}>
          <Text style={styles.delete}>刪除</Text>
        </View>
      </TouchableHighlight>

//如有理解有誤 敬請諒解