ReactNative ActivityIndicator не отображается, когда анимация свойства инициирует false

Я играю с реакцией на родной язык и получаю странное поведение.

Когда я пытаюсь показать ActitvityIndicator для Android, для его анимирующего свойства значение true с переменной showProgress в состоянии, это не работает, если переменная запущена как false.

В приведенном ниже примере, если свойство анимации ActivityIndicator начинается с true, тогда кнопки делают ActivityIndicator скрытым или отображаются правильно.

import React, { Component } from 'react';
import {
  Text,
  View,
  StyleSheet,
  TextInput,
  TouchableHighlight,
  ActivityIndicator
} from 'react-native';

export class Login extends Component {

    constructor(props) {
        super(props);

        this.state = {
            showProgress: true
        };
    }

    render() {
        return (
            <View>

                <TouchableHighlight onPress={this.progressOff.bind(this)}>
                    <Text>progressOff</Text>
                </TouchableHighlight>

                <TouchableHighlight onPress={this.progressOn.bind(this)}>
                    <Text>progressOn</Text>
                </TouchableHighlight>

                <ActivityIndicator animating={this.state.showProgress} size="large"/>
            </View>
        );
    }

    progressOff() {
        this.setState({showProgress: false}); 
    }

    progressOn() {
        this.setState({showProgress: true});
    }
}

Но если я использую приведенный ниже код, с анимирующим свойством, начинающимся с значения false, кнопка, отображающая ActivityIndicator, не работает:

import React, { Component } from 'react';
import {
  Text,
  View,
  StyleSheet,
  TextInput,
  TouchableHighlight,
  ActivityIndicator
} from 'react-native';

export class Login extends Component {

    constructor(props) {
        super(props);

        this.state = {
            showProgress: false
        };
    }

    render() {
        return (
            <View>

                <TouchableHighlight onPress={this.progressOff.bind(this)}>
                    <Text>progressOff</Text>
                </TouchableHighlight>

                <TouchableHighlight onPress={this.progressOn.bind(this)}>
                    <Text>progressOn</Text>
                </TouchableHighlight>

                <ActivityIndicator animating={this.state.showProgress} size="large"/>
            </View>
        );
    }

    progressOff() {
        this.setState({showProgress: false}); 
    }

    progressOn() {
        this.setState({showProgress: true});
    }
}

Что мне здесь не хватает?

Ответ 1

Это, кажется, ошибка в React Native. Код с начальным состоянием showProgress: false работает на iOS, но не на Android.

Я открыл вопрос о github, если вы хотите следить за развитием: https://github.com/facebook/react-native/issues/9023

Вариант 1

Обходной путь, который я использовал, - это использовать переменную showProgress для отображения совершенно другого представления с помощью ActivityIndicator:

render() {
    if (this.state.showProgress) {
        return this.renderLoadingView();
    } else {
        return this.renderMainView();
    }
}

Вариант 2

Вы также можете установить непрозрачность ActivityIndicator в соответствии с состоянием:

render() {
    return (
        <View>

            <TouchableHighlight onPress={this.progressOff.bind(this)}>
                <Text>progressOff</Text>
            </TouchableHighlight>

            <TouchableHighlight onPress={this.progressOn.bind(this)}>
                <Text>progressOn</Text>
            </TouchableHighlight>

            <ActivityIndicator style={{opacity: this.state.showProgress ? 1.0 : 0.0}} animating={true} size="large"/>
        </View>
    );
}

Однако при использовании этого метода анимация spinner не всегда начинается с той же позиции.

Ответ 2

Это ошибка React-Native для индикатора активности компонента. Я не уверен, что fb уже решил это, но вы можете попробовать это.

 constructor(props) {
        super(props);
        this.state = {
            opacity: 0
        };
    }

чтобы показать, что он использует this.setState({opacity: 1}) и снова спрятать this.setState({opacity: 0}) в ваших вызываемых функциях

и в рендере, где вы используете индикатор активности

 <ActivityIndicator
    animating={true}
    color="#ffffff"
    style={{height: 80, marginTop: 10, opacity: this.state.opacity }}
    size="large"/>

Ответ 3

Если в вашем проекте вы можете использовать сторонние компоненты, я рекомендую использовать реакцию-native-load-spinner-overlay

Легко решить наши проблемы, поскольку этот компонент использует аналогичный способ показать или скрыть Activity с помощью свойства visible.

Ответ 4

Я попробовал другой подход, который, как мне кажется, более "реагирует" на решение проблем. Таким образом, проблема с решением по opacity заключается в том, что если вы просто установите его на 0, это все равно будет анимация, поэтому это не лучшее решение, влияющее на производительность вашего приложения.

Я создал отдельный компонент, который я назвал <Loading/>, вот код:

import { ActivityIndicator } from "react-native"
import React from "react"
import PropTypes from "prop-types"

const Loading = (props) =>
    props.animating
        ? <ActivityIndicator style={props.style} 
               importantForAccessibility='auto' size={props.size} 
                     color={props.size} /> : null

Loading.propTypes = {
    animating: PropTypes.bool.isRequired,
    style: PropTypes.oneOfType([PropTypes.style, PropTypes.object]),
}

export default Loading

Использование:

<Loading animating={true} importantForAccessibility='auto' size="large" color="#A02BFF" style={styles.loading} />

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

Ответ 5

Другой способ, который я нашел эффективным, чтобы обойти эту проблему без большого количества кода:

{ this.state.showProgress &&
  <ActivityIndicator animating={true} size="large"/>
}

Ответ 6

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

<View style={{alignItems: 'center', justifyContent: 'center', flex: 1, backgroundColor: 'white'}}>
  <ActivityIndicator
    animating={true}
    style={
      {
        alignItems: 'center',
        justifyContent: 'center',
        opacity: this.state.loading ? 1 : 0
      }}
    size="large"
  />
</View>

Ответ 8

В моем случае для реагирования на нативную версию 0.59.10 тип свойства size отличается для Android и iOS, поэтому для этого мне пришлось проверить платформу следующим образом, и это сработало.

<ActivityIndicator 
                size={Platform.OS === "ios" ? 0 : "large"} //This platform check worked.
                color={props.color} 
                animating={props.animating}
                style={props.style}
                />