有没有一种方法可以“淡入”列表中的项目?

时间:2019-04-22 09:10:56

标签: react-native

我正在设置一个呈现平面列表的组件,并且试图使平面列表项目“淡入”动画以获得更令人印象深刻的显示

这是显示项目的渲染搜索建议的组件

import React, { Component } from 'react'
import { View, Text, TextInput, FlatList, Image, TouchableOpacity } from 'react-native'
import { inject, observer } from 'mobx-react/native'
import { Button } from '../../components'
import Style from './style'
import I18n from '../../i18n'
import Icon from 'react-native-vector-icons/MaterialIcons'
import Api from '../../utils/Api'
import _ from 'lodash'

let mounted = false
@inject('UserStore', 'NavigationStore')
@observer
class SearchProducts extends Component {
  constructor(props) {
    super(props)
    this.state = {
      searchAutoComplete: [],
      showAutoComplete: false,
      currentSearch: '',
      searchTimeoutId: null,
    }
    this.autoCompleteTimeout = null
    this.storedResults = []
  }

  componentWillMount() {
    mounted = true
  }
  componentWillUnmount() {
    mounted = false
    clearTimeout(this.autoCompleteTimeout)
  }
  _renderCategory = ({ item }) => {
    return (
      <View style={Style.featuredView}>
        <Image source={item.image} style={Style.featuredImage} />
        <Text style={{ textAlign: 'center', color: '#9B999A' }}>{item.title}</Text>
      </View>
    )
  }

  _renderSuggestion = ({ item, index }) => {
    const splittedName = item.split(' ')
    let splittedSearch = this.state.currentSearch.toUpperCase().split(' ')
    splittedSearch = splittedSearch.map(x => x.trim()).filter(x => x.length > 1)
    let suggestion = []
    if (splittedSearch.length == 0) {
      suggestion = splittedName.map((word, index) => <Text key={index}>{word} </Text>)
    } else {
      let highlightedWords = []
      splittedName.forEach((word, index) =>
        splittedSearch.forEach(wordFromSearch => {
          const currentWord = word.toUpperCase()
          const isAlreadyHighlighted = highlightedWords.includes(currentWord)
          if ((currentWord.includes(wordFromSearch.toUpperCase()) && this.state.currentSearch.length > 0) || isAlreadyHighlighted) {
            let v = (
              <Text key={index} style={{ color: '#2eb872' }}>
                {word}{' '}
              </Text>
            )
            if (!isAlreadyHighlighted) {
              highlightedWords.push(currentWord)
            }
            suggestion[index] = v
          } else {
            let v = <Text key={index}>{word} </Text>
            suggestion[index] = v
          }
        })
      )
    }

    return (
      <TouchableOpacity
        style={Style.suggestionView}
        onPress={() => {
          this.props.UserStore.addRecentSearch(item)
          this.props.NavigationStore.navigate({ routeName: 'SearchResult', params: { search: item } })
          this.autoCompleteTimeout = setTimeout(() => {
            if (mounted) this.setState({ showAutoComplete: false })
          }, 400)
        }}
      >
        <Icon name='search' size={20} style={{}} />
        <Text style={{ marginLeft: 20, textAlign: 'left', color: '#9B999A' }}>{suggestion}</Text>
      </TouchableOpacity>
    )
  }

  getSuggestions = async currentSearch => {
    try {
      const response = await Api.serachOutoCompleate(currentSearch)
      let searchAutoComplete = response.suggestions.products.map(product => product.product_title)
      response.suggestions.categories.forEach(categories => searchAutoComplete.push(categories))
      response.suggestions.warehouses.forEach(warehouse => searchAutoComplete.push(warehouse.warehouse_name))
      response.suggestions.upcs.forEach(upcs => searchAutoComplete.push(upcs.product_title))
      response.suggestions.tags.forEach(tags => searchAutoComplete.push(tags.product_title))
      this.storedResults[currentSearch] = searchAutoComplete
      if (mounted && currentSearch && searchAutoComplete) this.setState({ currentSearch: currentSearch, searchAutoComplete: searchAutoComplete })
      else this.setState({ currentSearch: currentSearch })
    } catch (error) {
      console.log(error)
    }
  }

  _onSearchChange = _.debounce(currentSearch => {
    if (currentSearch === '') {
      this.setState({ filter: [], currentSearch })
    } else {
      if (this.storedResults[currentSearch]) {
        this.setState({ currentSearch })
        let searchAutoComplete = this.storedResults[currentSearch]
        if (mounted && currentSearch && searchAutoComplete) this.setState({ searchAutoComplete })
      } else {
        this.getSuggestions(currentSearch)
      }
    }
  }, 250)

  render() {
    I18n.locale = this.props.UserStore.user.lang
    const recent = this.props.UserStore.RecentSearches
    return (
      <View style={Style.container}>
        <View style={Style.search_container}>
          <TextInput
            style={Style.search_input}
            underlineColorAndroid='transparent'
            placeholder={I18n.t('search_products')}
            returnKeyType='search'
            autoCorrect={false}
            onChangeText={this._onSearchChange}
            onFocus={() => this.setState({ showAutoComplete: true })}
            onSubmitEditing={event => {
              if (event.nativeEvent.text.length) this.props.UserStore.addRecentSearch(event.nativeEvent.text)
              this.props.NavigationStore.navigate({ routeName: 'SearchResult', params: { search: event.nativeEvent.text } })
            }}
            onKeyPress={() => this.suggestionTimeout && clearTimeout(this.suggestionTimeout)}
            blurOnSubmit
          />
        </View>
        {this.state.currentSearch.length > 0 && this.state.showAutoComplete && this.state.searchAutoComplete.length > 0 ? (
          <View style={{ paddingVertical: 10 }}>
            <FlatList initialNumToRender={20} data={this.state.searchAutoComplete} keyExtractor={(item, index) => item.toString()} renderItem={this._renderSuggestion} keyboardShouldPersistTaps='always' />
          </View>
        ) : (
          <View>
            {recent.length > 0 ? (
              <View>
                <View style={Style.whiteBorder} />
                <View style={Style.searchHistory}>
                  <Text style={Style.searchHistory_header}>{I18n.t('recent_searches')}</Text>
                  {recent.map((title, index) => (
                    <Button
                      key={index}
                      style={Style.recentSearch}
                      onPress={() => {
                        this.props.UserStore.addRecentSearch(title)
                        this.props.NavigationStore.navigate({ routeName: 'SearchResult', params: { search: title } })
                      }}
                    >
                      <Icon name='schedule' style={Style.recentSearchIcon} />
                      <Text style={Style.recentSearchText}>{title}</Text>
                    </Button>
                  ))}
                </View>
              </View>
            ) : null}
          </View>
        )}
      </View>
    )
  }
}

export default SearchProducts

我希望输出结果会在平面列表中显示出淡入淡出的动画效果 而且我不知道如何实现

1 个答案:

答案 0 :(得分:0)

这可以通过使用动画API来完成。 首先从react-native导入Animated,然后将fade: new Animated.Value(0)添加到构造函数中的状态。

现在从

更改FlatList周围的视图
<View style={{ paddingVertical: 10 }}>

对此

<Animated.View style={{ paddingVertical: 10, opacity: this.state.fade }}>

最后,在列表装入时添加此块以开始动画:

componentDidMount() {
    Animated.timing(this.state.fade, {
        duration: 500,
        toValue: 1,
        useNativeDrivers: true
    }).start();
}

如果您希望在用户每次搜索时都对FlatList进行动画处理,则必须将该块移动到程序逻辑的另一部分,并记住在动画播放之前将fade值设置回0。