React Native 动画输入文本

3
我想在焦点TextInput动画上显示一个取消按钮。 我编写了以下代码,但是取消按钮不会在焦点时显示和跟随文本框移动。只有在动画结束后才会显示。
当取消按钮显示时,它不在同一行上与TextInput。 如何修复这个问题?
const { width } = Dimensions.get('window');
const PADDING = 16;
const SEARCH_FULL_WIDTH = width - PADDING * 2;  //search_width when unfocused
const SEARCH_SHRINK_WIDTH = width - PADDING - 90;  //search_width when focused

class Search extends React.Component {

constructor(props: IProps) {
  super(props);
  this.state = {
    inputLength: new Animated.Value(SEARCH_FULL_WIDTH),
    searchBarFocused: false,
  }
}

private onFocus = () => {
  Animated.timing(this.state.inputLength, {
    toValue: SEARCH_SHRINK_WIDTH,
    duration: 250,
  }).start(() => this.setState({ searchBarFocused: true }));
}

private onBlur = () => {
  Animated.timing(this.state.inputLength, {
    toValue: SEARCH_FULL_WIDTH,
    duration: 250,
  }).start(() => this.setState({ searchBarFocused: false }));
}


<View style={styles.searchContainer}>
<Animated.View style={[
  styles.search,
  {
    width: this.state.inputLength,
    position: 'absolute',
    left: 16,
    alignSelf: 'center'
  },
  searchBarFocused === true ? undefined : { justifyContent: 'center' }
]}>
  <Image source={searchIcon} style={styles.image} />
  <TextInput
    style={styles.searchInput}
    ....
    onBlur={this.onBlur}
    onFocus={this.onFocus}
  />
</Animated.View>

{searchBarFocused &&
  <Touchable style={styles.cancelSearch} onPress={this.cancelSearch}>
    <Text style={styles.cancelSearchText}>Cancel</Text>
  </Touchable>
}
</View>

const styles = StyleSheet.create({
  searchContainer: {
    flexDirection: 'row',
    height: 72,
    borderBottomColor: SOLITUDE_COLOR,
  },
  search: {
    flex: 1,
    flexDirection: 'row',
    height: 40,
    borderRadius: 6,
  },
  cancelSearch: {
    marginHorizontal: 16,
    textAlign: 'center',
    justifyContent: 'center'
  }
});

GIF: 当失去焦点和获得焦点时 vqhdHj

2个回答

4
这是您代码的略微修改版。
import React from "react";
import {
  Dimensions,
  View,
  Animated,
  TextInput,
  TouchableOpacity,
  StyleSheet,
} from "react-native";

const { width } = Dimensions.get("window");
const PADDING = 16;
const SEARCH_FULL_WIDTH = width - PADDING * 2; //search_width when unfocused
const SEARCH_SHRINK_WIDTH = width - PADDING - 90; //search_width when focused

const AnimatedTouchable = Animated.createAnimatedComponent(TouchableOpacity);

export default class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      inputLength: new Animated.Value(SEARCH_FULL_WIDTH),
      cancelPosition: new Animated.Value(0),
      opacity: new Animated.Value(0),
      searchBarFocused: false
    };
  }

  onFocus = () => {
    Animated.parallel([
      Animated.timing(this.state.inputLength, {
        toValue: SEARCH_SHRINK_WIDTH,
        duration: 250
      }),
      Animated.timing(this.state.cancelPosition, {
        toValue: 16,
        duration: 400
      }),
      Animated.timing(this.state.opacity, {
        toValue: 1,
        duration: 250
      })
    ]).start();
  };

  onBlur = () => {
    Animated.parallel([
      Animated.timing(this.state.inputLength, {
        toValue: SEARCH_FULL_WIDTH,
        duration: 250
      }),
      Animated.timing(this.state.cancelPosition, {
        toValue: 0,
        duration: 250
      }),
      Animated.timing(this.state.opacity, {
        toValue: 0,
        duration: 250
      })
    ]).start();
  };

  render() {
    const { searchBarFocused } = this.state;

    return (
      <View style={styles.searchContainer}>
        <Animated.View
          style={[
            styles.search,
            {
              width: this.state.inputLength,
              position: "absolute",
              left: 16,
              alignSelf: "center"
            },
            searchBarFocused === true ? undefined : { justifyContent: "center" }
          ]}
        >
          <TextInput
            style={styles.searchInput}
            onBlur={this.onBlur}
            onFocus={this.onFocus}
            placeholder="Type something"
          />
        </Animated.View>

        <AnimatedTouchable
          style={[styles.cancelSearch, { right: this.state.cancelPosition }]}
          onPress={() => null}
        >
          <Animated.Text
            style={[styles.cancelSearchText, { opacity: this.state.opacity }]}
          >
            Cancel
          </Animated.Text>
        </AnimatedTouchable>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  searchContainer: {
    flexDirection: "row",
    height: 72,
    borderBottomColor: "#00000033",
    paddingTop: 100
  },
  search: {
    flex: 1,
    flexDirection: "row",
    height: 40,
    borderRadius: 6,
    backgroundColor: "red"
  },
  cancelSearch: {
    position: "absolute",
    marginHorizontal: 16,
    textAlign: "center",
    justifyContent: "center",
    alignSelf: "center"
  }
});

textinput-animation


我可以问你一个问题吗:如何使文本占位符像动画一样移动?我们不会使用TextInput的“placeholder”,对吧? - ninh_nguyen
是的,使用占位符可能无法做太多事情。您可能需要使用绝对定位的文本组件。 - 10101010

0
你只有在动画完成后才设置searchBarFocused。由于取消按钮是根据 searchBarFocused 有条件地呈现的,因此它仅在动画结束时出现。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接