Wie animieren Sie die Höhe in React Native, wenn Sie die Größe des Inhalts nicht kennen?

Lesezeit: 10 Minuten

Benutzeravatar von Poyan
Pojan

Wie animieren Sie in React-Native die Größe einer Ansicht, wenn Sie die Größe ihres Inhalts nicht kennen?

Angenommen, die Inhaltshöhe der Ansicht kann zwischen 0 und 400 pt liegen, und der Inhalt kann dynamisch wachsen und schrumpfen, und Sie möchten alle Änderungen an der Höhe animieren.

Grundsätzlich möchte ich das Verhalten von LayoutAnimation reproduzieren ohne Verwendung von LayoutAnimation aber mit Animated.

Ich denke, was mir entgeht, ist, dass ich nicht weiß, wie ich auf eine Zielhöhe hin animieren soll, da ich die Höhe des Inhalts nicht kenne.

  • Sie mit Übersetzungswerten animieren, überprüfen Sie dies: http://stackoverflow.com/questions/55339044/…

    – yathavan

    8. Januar 2021 um 6:13 Uhr

ich benutze LayoutAnimation Fügen Sie dazu kurz vor der Zustandsänderung, die die Änderung der Höhe Ihrer Komponente bewirkt, Folgendes hinzu:

LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);

Sie können verschiedene Voreinstellungen verwenden:

  • LayoutAnimation setzt eine globale Animation auf alles, diese Methode ist nur, wenn Sie eine sehr einfache App haben, in der 1 Aktion gleichzeitig stattfindet.

    – Ericjam

    8. Juni 2018 um 22:32 Uhr

  • LayoutAnimation hat immer noch viele schwerwiegende Probleme sowohl auf iOS als auch auf Android. Wenn Sie erwägen, verschiedene mobile Geräte zu unterstützen, schlage ich die ganze Zeit Animated API vor.

    – Samitha Nanayakkara

    3. April 2020 um 9:32 Uhr

  • LayoutAnimation ist auf Android sehr fehlerhaft und hat in meinen Apps zu diversen Abstürzen in der Produktion geführt. Ich musste es ersetzen (bzw Platform.OS === 'ios' ? LayoutAnimation.configureNext(LayoutAnimation.create(50, 'easeInEaseOut', 'opacity')) : null;) und ersetzen Sie es durch nur iOS-Anrufe.

    – Walter Monecke

    21. April 2020 um 9:10 Uhr


  • Ich habe unten eine Antwort für alle gegeben, die in einer ähnlichen Situation wie ich beim Umgang mit Animationen sind. Es könnte Umgang mit der Höhe des Inhalts und verwenden Animated Komponente. Schaut gerne mal vorbei ;D Cheers!

    – Flügel Choy

    12. November 2020 um 4:45 Uhr

Benutzeravatar von Wing Choy
Flügel Choy

Hallo zusammen, hoffe es ist noch nicht zu spät…

für alle, die sich mit React Native Animation auf Sichthöhe beschäftigen.
Ich weiß, dass es sehr nervig ist, denn:

✖️ React Native Animation scheint keine Unterstützung von Layoutstilen (z. B. Breite und Höhe)
✖️ LayoutAnimation sieht kompliziert aus zu untersuchen
✖️ Möchten Sie eine offizielle Methode zum Animieren verwenden, anstatt ein Paket eines Drittanbieters zu installieren
✖️ Manchmal kann der Inhalt groß sein, um Ihre Ansichtsstile zu beeinträchtigen

Also hier ist meine Lösung für dich (Klassenkomponenten Weg):

Setzen Sie zuerst den animierten Wert in state:

state = { height: new Animated.Value(0) };

Stellen Sie als Nächstes Ihre animierte Ansicht ein max height mit Animationsinterpolation:

const maxHeight = this.state.height.interpolate({ 
  inputRange: [0, 1], 
  outputRange: [0, 2000]  // <-- any value larger than your content's height
});
return (<Animated.View style={[styles.box, { maxHeight: maxHeight }]} />); 
// any other fixed styles in styles.box

Setzen Sie danach die Animation in die function du hast angerufen,
oder componentDidMount wenn Sie möchten, dass es angezeigt wird, sobald es gerendert wurde:

// or in any function that users interact
componentDidMount() {
  Animated.timing(this.state.formHeight, {
    toValue: 1,
    duration: 500,           // <-- animation duration
    easing: Easing.linear,   // <-- or any easing function
    useNativeDriver: false   // <-- need to set false to prevent yellow box warning
  }).start();
}

Beachten Sie, dass nicht einstellen useNativeDriver zu true da es von Layoutstilen nicht unterstützt wird.


Probe

Nachfolgend finden Sie ein Beispiel, mit dem Sie interagieren können.
fühlen sich frei Kopieren und Einfügen zu deinem React Native Projekt zum Ausprobieren:

import React, { PureComponent } from 'react';
import { Animated, Button, Easing, View, Text, StyleSheet } from 'react-native';

class AnimateBox extends PureComponent {
  state = { opacity: new Animated.Value(0), height: new Animated.Value(0) };

  showContent = () => {
    const { opacity, height } = this.state;

    Animated.timing(height, {
      toValue: 1,
      duration: 500,
      easing: Easing.linear,
      useNativeDriver: false  // <-- neccessary
    }).start(() => {
      Animated.timing(opacity, {
        toValue: 1,
        duration: 500,
        easing: Easing.linear,
        useNativeDriver: false  // <-- neccessary
      }).start();
    });
  };

  render() {
    const { opacity, height } = this.state;
    const maxHeight = height.interpolate({ 
      inputRange: [0, 1], 
      outputRange: [0, 1000]  // <-- value that larger than your content's height
    });

    return (
      <View style={styles.box}>
        <Animated.View style={{ opacity: opacity, maxHeight: maxHeight }}>
          <Text style={styles.content}>
            Lorem Ipsum is simply a dummy text of the printing and typesetting industry.
            Lorem Ipsum has been the industry's standard dummy text ever since the 1500s,
            when an unknown printer took a galley of type and scrambled it to make a type specimen book.
            It has survived not only five centuries, but also the leap into electronic typesetting,
            remaining essentially unchanged. It was popularised in the 1960s with the release of
            Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
          </Text>
        </Animated.View>
        <View style={styles.spacing}>
          <Button title="Show content" onPress={this.showContent} />
        </View>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  box: {
    backgroundColor: '#fff',
    marginHorizontal: 15,
    paddingHorizontal: 15
  },
  spacing: {
    paddingVertical: 10
  },
  content: {
    fontSize: 16,
    lineHeight: 30,
    color: '#555'
  }
});


export default AnimateBox;

Viel Spaß beim Codieren 🙂


Weitere Erläuterungen (bearbeitet am 03.02.2021)

Wie in der React Native-Dokumentation erwähnt:
https://reactnative.dev/docs/animations#caveats

Nicht alles, was Sie mit Animated tun können, wird derzeit vom nativen Treiber unterstützt. Die Haupteinschränkung besteht darin, dass Sie nur Nicht-Layout-Eigenschaften animieren können: Dinge wie Transformation und Deckkraft funktionieren, aber Flexbox- und Positionseigenschaften nicht.

Deaktivieren useNativeDriver kann andere Stile als animieren opacity und transformaber erhöhen Sie tatsächlich die Arbeitslast auf dem JS-Thread, da der JS-Thread die UI für jeden Frame berechnen muss.

Und hier im Blog von React Native 0.62:
https://reactnative.dev/blog/2020/03/26/version-0.62#deprecations

Das Festlegen von useNativeDriver ist jetzt erforderlich, um das Umschalten der Standardeinstellung in Zukunft zu unterstützen.

Sie müssen die Einstellung vornehmen useNativeDriver in Animationsoptionen ein React native v0.62 oder höher, um Warnungen zu vermeiden.

  • Wirklich? warum es für mich sagt “Stileigenschaft ‘Höhe’ wird vom nativen animierten Modul nicht unterstützt”. Ich möchte heulen

    – Charitha Goonewardena

    3. Februar 2021 um 2:36 Uhr

  • Hi @CharithaGoonewardena, ich denke du hast das vielleicht eingestellt useNativeDriver auf wahr, was zu dieser Warnung führt. Ich habe der Antwort eine Erklärung hinzugefügt. Sieh es dir gerne an oder kopiere den Beispielcode in dein Projekt, um ihn zu bearbeiten. Prost!

    – Flügel Choy

    3. Februar 2021 um 7:35 Uhr


  • Das funktioniert, aber Sie müssen nicht wirklich interpolieren. Sie können einfach auf 2000 anstelle von 1 animieren und maxHeight auf this.state.formHeight setzen

    – John Kendall

    19. Februar 2021 um 15:54 Uhr

  • Ja natürlich @Johnkendall 🙂 Die Interpolation wird nur verwendet, um maxHeight und opacity mit demselben animierten Wert in meinem Beispiel zu behandeln. Es liegt an Ihnen, den maximalen Wert festzulegen, wenn Sie keine anderen animierten Stile haben.

    – Flügel Choy

    21. Februar 2021 um 6:44 Uhr

  • In Android-Animation ist überhaupt kein Übergang. Es geht einfach direkt zum Wert. Jemand ist darauf gestoßen? IOS funktioniert gut

    – Necmettin Sargin

    13. Juli 2021 um 9:38 Uhr

Benutzeravatar von Tierna D. Jack Lawless
Tierna D. Jack Lawless

Sie müssen eine Art Größenskalierung hinzufügen, wahrscheinlich mit Prozentsätzen, um den besten Effekt zu erzielen.

Das erste, was Sie zuerst verwenden müssten Animated.View Anstatt von View.

Als nächstes müssten Sie eine Transformation auf den Stil der Ansicht anwenden, sagen wir, es sieht so aus wie unten. Dies ist der Teil, der die Bewegung aktualisiert, ändert und erzeugt.

        <Animated.View style={[ styles.someStyleYouMade,
          {
            transform: [
              // scaleX, scaleY, scale, theres plenty more options you can find online for this.
              {  scaleX: ViewScaleValue } // this would be the result of the animation code below and is just a number.
            ]
          } 
        ]}
        >

Dieser nächste Teil ist im Grunde ein animiertes API-Beispiel, Sie würden so etwas schreiben (individuell nach Ihren Wünschen) und wenn dieses Skript aufgerufen wird, wird es auf die von Ihnen angegebene Weise animiert.

  Animated.timing(                    // Animate over time
    this.state.ViewScale,             // The animated value to drive, this would be a new Animated.Value(0) object.
    {
      toValue: 100,                   // Animate the value
      duration: 5000,                 // Make it take a while
    }
  ).start();

Schließlich möchten Sie wahrscheinlich eine Interpolation auf den Wert anwenden, damit er so individuell wie möglich aussieht.

(Das geht in deine render() Funktion aber vor der return(). das ViewScaleValue wird in die gehen Animated.View verwandeln)

const ViewScaleValue = this.state.ViewScale.interpolate({
  inputRange: [0, 25, 50, 75, 100],
  outputRange: [0, .5, 0.75, 0.9, 1]
});

all dieser Code würde machen ViewScaleValueeine einfache Zahl, animieren Sie von 0-100, gehen Sie schnell und dann langsam (aufgrund der Interpolation) und wenden Sie jede Iteration der Animation auf die an Animated.View verwandeln.

Lesen Sie die animierte API daneben, um ein gutes Verständnis dafür zu bekommen.

  • Wie kann ich mit dieser Methode die Höhe ohne Skalierung anpassen? Es scheint nur Skalenoptionen verfügbar zu sein.

    – CyberMew

    14. März 2019 um 14:33 Uhr

  • Wenn die animierte Ansicht einen Nullwert hat, ist sie einfach unsichtbar. Trotzdem nimmt sie den Platz ein, der erforderlich ist, wenn der Inhalt sichtbar ist

    – Samiksha Jagtap

    16. Oktober 2019 um 6:49 Uhr

  • Warum %? Können Sie erklären, wie viel Prozent OP helfen, ihr Ziel zu erreichen?

    – png

    30. August 2021 um 21:38 Uhr

Benutzeravatar von sbärben
bärben

Die Methode, die ich gewählt habe, besteht darin, Layout-Durchläufe aufzuwenden, um die Höhe der “abgeschnittenen” Komponente und die Höhe der “volle Größe”-Komponente zu erhalten (Sie brauchen einen Weg, damit die abgeschnittene Höhe deterministisch ist, normalerweise indem Sie wissen, wie man a “Zeile” des Inhalts). Bevor Sie diese Werte haben, rendern Sie diese im Wesentlichen als zwei separate Ansichten, die ausgeblendet sind:

hidden: {
  position: 'absolute',
  left: 0,
  top: 0,
  opacity: 0,
},

Verwenden Sie onLayout, um ihre Höhen zu erfassen:

const onLayoutTruncated = ({nativeEvent}: LayoutChangeEvent) => {
  if (!doneProcessing) {
    truncatedHeight = nativeEvent.layout.height;
    checkIfDoneProcessingLayout();
  }
};

const onLayoutFull = ({nativeEvent}: LayoutChangeEvent) => {
  if (!doneProcessing) {
    fullHeight = nativeEvent.layout.height;
    checkIfDoneProcessingLayout();
  }
};

checkIfDoneProcessingLayout() werde prüfen ob beides truncatedHeight und fullHeight gesetzt sind, und nehmen Sie eine Zustandsänderung vor, wenn beide gesetzt sind (doneProcessing = true).

Von dort aus sollten Sie die abgeschnittene Ansicht einblenden und zwischen beiden Höhenwerten mit an animieren können Animated.Value und Interpolation:

const expandingHeight = animatedValue.interpolate({
  inputRange: [0, 1],
  outputRange: [truncatedHeight, fullHeight],
});

Lösen Sie die Erweiterungs-/Reduzierungsanimation beim Klicken mit aus Animated.timing

Animated.timing(animatedValue, {toValue: isExpanded ? 0 : 1, easing: SOME_EASING_FUNCTION, duration: SOME_DURATION}).start();

Ich verwende eine eigene Komponente mit @react-spring/native

giphy

etwas wie das

import React from 'react';
import {View, ViewProps} from 'react-native';

interface GetDimensionsOfThisContainerProps extends ViewProps {
  children: React.ReactChild[];
  onDimensions: ({width, height}: {width: Number; height: Number}) => void;
}

export const GetDimensionsOfThisContainer: React.FC<
  GetDimensionsOfThisContainerProps
> = ({children, onDimensions, ...props}: GetDimensionsOfThisContainerProps) => {
  return (
    <View
      onLayout={event =>
        onDimensions({
          width: Math.round(event.nativeEvent.layout.width),
          height: Math.round(event.nativeEvent.layout.height),
        })
      }
      style={{position: 'absolute', width: '100%'}}
      {...props}>
      {children}
    </View>
  );
};

      <GetDimensionsOfThisContainer
        onDimensions={({height: _height}) => {
          if (dynamicHeight !== _height) setDynamicHeight(_height);
        }}>
       {children}
      </GetDimensionsOfThisContainer>

Quelle: https://gist.github.com/sturmenta/af790331f6bd27322ecd73ee723c8c60

Benutzeravatar von Joachim Feltkamp
Joachim Feltkamp

Basierend auf der Lösung von @Wing Choi möchte ich meine verbesserte Lösung teilen. Das sollte Plug&Play funktionieren.

  • Anstatt eine maxHeight zu verwenden (nicht so schön für Animationen), habe ich das onLayout-Event verwendet, um immer die genaue Höhe zu haben. (Wird bei allen inneren und äußeren Änderungen des Layers ausgelöst)
  • Anstatt die Ebene einfach mit einer Schaltfläche zu öffnen, habe ich eine Eigenschaft “open” (bool) hinzugefügt, um die Ebene von einer übergeordneten Komponente aus zu steuern.
import React, { PureComponent } from 'react';
import { Animated, Easing, View } from 'react-native';
import PropTypes from "prop-types";

class AnimateBox extends PureComponent {
  constructor(props) {
    super(props);
    this.state = {
      init: false,
      opacity: (this.props.open) ? 1 : 0,
      height: 1000
    };
  }

  componentDidUpdate(prevProps, prevState, snapshot) {
    if (this.state.init && prevState.open !== this.props.open) {
      this.showContent();
    }
  }

  adjustHeight(layout) {
    const height = Math.round(layout.height);

    this.setState({
      init: true,
      opacity: new Animated.Value((this.props.open) ? 1 : 0),
      height: new Animated.Value((this.props.open) ? height : 0),
      interpol: {
        inputRange: [0, 1],
        outputRange: [0, height]
      }
    });
  }

  showContent = () => {
    const { opacity, height } = this.state;

    Animated.timing(height, {
      toValue: (this.props.open) ? 1 : 0,
      duration: 400,
      easing: Easing.out(Easing.ease),
      useNativeDriver: false
    }).start(() => {
      Animated.timing(opacity, {
        toValue: (this.props.open) ? 1 : 0,
        duration: 300,
        easing: Easing.linear,
        useNativeDriver: false
      }).start();
    });
  };

  render() {
    const { opacity, height, interpol } = this.state;
    let animHeight = height;
    if (this.state.init) {
      animHeight = height.interpolate(interpol);
    }
    return (
      <Animated.View style={{ position: 'relative', opacity: opacity, height: animHeight, overflow: 'hidden' }}>
        <View style={{position: 'absolute', top: 0, left: 0, right: 0}}
              onLayout={(event) => { this.adjustHeight(event.nativeEvent.layout)}} >
          {this.props.children}
        </View>
      </Animated.View>);
  }
}

AnimateBox.propTypes = {
  open: PropTypes.bool
};

AnimateBox.defaultProps = {
  open: false
}

export default AnimateBox;

1434370cookie-checkWie animieren Sie die Höhe in React Native, wenn Sie die Größe des Inhalts nicht kennen?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy