react-native 使状态栏 'barStyle' 可动画化

react-native make status bar 'barStyle' animatable

我正在尝试使状态栏的 barStyle 动画化,以便在滚动时可以将 barStyle 类型从 'dark-content' 更改为 'light-content'。

首先,我制作了状态栏动画:

const AnimatedStatusBar = Animated.createAnimatedComponent(StatusBar);

其次,设置动画值:

scroll = new Animated.Value(0);

  tabY = this.nScroll.interpolate({
    inputRange: [0, SCROLL_HEIGHT, SCROLL_HEIGHT],
    outputRange: [0, 0, 1]
  });
  headerBg = this.scroll.interpolate({
    inputRange: [0, SCROLL_HEIGHT, SCROLL_HEIGHT],
    outputRange: ["black", 'white'],
    extrapolate: "clamp"
  });

最后,如果 this.HeaderBg 已更改,请更改 barStyle:

<AnimatedStatusBar barStyle={this.headerBg === 'transparent'? 'dark-content' : 'light-content'} translucent={true} /> 

我觉得我的代码应该可以工作,但它没有像我预期的那样工作。

知道如何在动画更改时更改状态栏 barStyle 的类型吗?

顺便说一句,我没有使用钩子。我想知道如何使用 class 个组件。

我们只能通过使用变量来设置状态栏的动画。(通过切换)

我们以为变量

state = {
  dark: true,
};

最初,这是真的。所以状态栏样式应该是深色的。

<StatusBar
    barStyle={dark ? 'dark-content' : 'light-content'}
    translucent
    backgroundColor="transparent"
/>

切换是在滚动方法内部完成的。这里我使用 100 作为偏移量。

onScroll = ({nativeEvent}) => {
  let y = nativeEvent.contentOffset.y;
  this.scroll.setValue(y); // set scroll animation value here
  const {dark} = this.state;
  let scrollValue = y;
  if (scrollValue > 100 && dark) {
    this.setState({dark: false});
  }
  if (scrollValue < 100 && !dark) {
    this.setState({dark: true});
  }
};

示例代码

import React, {Component} from 'react';
import {
  View,
  StatusBar,
  StyleSheet,
  ScrollView,
  Dimensions,
  Animated,
} from 'react-native';
const {height} = Dimensions.get('window');

export default class Home extends Component {
  scroll = new Animated.Value(0);
  state = {
    dark: true,
  };
  onScroll = ({nativeEvent}) => {
    let y = nativeEvent.contentOffset.y;
    this.scroll.setValue(y); // set scroll animation value here
    const {dark} = this.state;
    let scrollValue = y;
    if (scrollValue > 100 && dark) {
      this.setState({dark: false});
    }
    if (scrollValue < 100 && !dark) {
      this.setState({dark: true});
    }
  };
  render() {
    const {dark} = this.state;
    return (
      <View style={styles.container}>
        <StatusBar
          barStyle={dark ? 'dark-content' : 'light-content'}
          translucent
          backgroundColor="transparent"
        />
        <ScrollView
          style={styles.ScrollView}
          contentContainerStyle={styles.scrollContainer}
          onScroll={this.onScroll}>
          <View style={styles.item} />
        </ScrollView>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  ScrollView: {
    flex: 1,
  },
  scrollContainer: {
    height: height * 2,
    backgroundColor: '#000',
  },
  item: {
    height: 100,
    backgroundColor: '#fff',
  },
});

您应该使用 react-native-iphone-x-helper 来获取状态栏高度,这样您的应用程序就可以在 iphoneX 和正常 [ 上正常工作=26=]

代码:

import React, { Component } from "react";
import {
  View,
  StatusBar,
  StyleSheet,
  ScrollView,
  Dimensions,
  Animated,
} from "react-native";
const { height } = Dimensions.get("window");
import { getStatusBarHeight } from "react-native-iphone-x-helper";

const statusBarHeight = getStatusBarHeight();

export default class App extends Component {
  scroll = new Animated.Value(0);
  state = {
    dark: true,
  };
  onScroll = ({ nativeEvent }) => {
    let y = nativeEvent.contentOffset.y;
    this.scroll.setValue(y); // set scroll animation value here
    const { dark } = this.state;
    let scrollValue = y;
    if (scrollValue > statusBarHeight && dark) {
      this.setState({ dark: false });
    }
    if (scrollValue < statusBarHeight && !dark) {
      this.setState({ dark: true });
    }
  };
  render() {
    const { dark } = this.state;
    return (
      <View style={styles.container}>
        <StatusBar
          barStyle={dark ? "dark-content" : "light-content"}
          translucent
          backgroundColor="transparent"
        />
        <ScrollView
          style={styles.ScrollView}
          scrollEventThrottle={16}
          contentContainerStyle={styles.contentContainerStyle}
          onScroll={this.onScroll}
        >
          <View style={styles.item} />
        </ScrollView>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  ScrollView: {
    flex: 1,
  },
  contentContainerStyle: {
    height: height * 2,
    backgroundColor: "#000",
  },
  item: {
    height: 100,
    backgroundColor: "#FFFFFF",
  },
});

StatusBar 不是呈现状态栏的实际组件。它更像是一个方便的副作用组件,在呈现时,将强制调用将状态栏设置为在 prop 中传递的颜色。出于这个原因,你不能为它设置动画,因为它不渲染任何东西

此外,您不可能在 "light-content" 和 "dark-content" 之间设置动画,因为一个是深色背景的白色文本,另一个是白色背景的深色文本,它们之间没有中间值

您可以将背景颜色从一种更改为另一种(无需插值!)。您可以仅使用 imperative api

来实现它
class App extends React.Component {

  lastColor = null

  componentDidMount() {
    this.nScroll.addListener(({ value }) => {
      if (value < SCROLL_HEIGHT) {
        this.setStatusBarColor('black')
      } else {
        this.setStatusBarColor('white')
      }
    });
  }

  setStatusBarColor = (newColor) => {
    if (newColor !== this.lastColor) {
      StatusBar.setBackgroundColor(newColor)
    }
  }

  ///...
}

请注意,在这种情况下,您不需要渲染 <StatusBar />,因为所有颜色更改都是强制处理的

如果您希望状态栏通过插值改变颜色,您唯一的选择是将其设置为半透明 StatusBar.setTranslucent(true) 然后使用简单的 <View /> 绘制您自己的状态栏并为其背景颜色设置动画