Kev*_*vin 7 typescript react-native react-animated
我正在创建一个文本组件,默认情况下我希望它是 2 行,如果用户点击它,它将扩展到完整长度,如果用户再次点击它,它将折叠回 2 行。
到目前为止,我的返回函数中有类似的内容:
<TouchableWithoutFeedback
onPress={() => {
toggleExpansion();
}}
>
<Animated.View style={[{ height: animationHeight }]}>
<Text
style={styles.textStyle}
onLayout={event => setHeight(event.nativeEvent.layout.height)}
numberOfLines={numberOfLines}
>
{longText}
</Text>
</Animated.View>
</TouchableWithoutFeedback>
Run Code Online (Sandbox Code Playgroud)
我的状态变量和toggleExpansion函数如下所示:
const [expanded, setExpanded] = useState(false);
const [height, setHeight] = useState(0);
const [numberOfLines, setNumberOfLines] = useState();
const toggleExpansion = () => {
setExpanded(!expanded);
if (expanded) {
setNumberOfLines(undefined);
} else {
setNumberOfLines(2);
}
};
Run Code Online (Sandbox Code Playgroud)
到目前为止,这可以展开和折叠,但我不确定如何设置 Animated.timing 函数来为其设置动画。我尝试过这样的事情:
const animationHeight = useRef(new Animated.Value(0)).current;
useEffect(() => {
Animated.timing(animationHeight, {
duration: 1000,
toValue: height,
easing: Easing.linear
}).start();
}, [height]);
Run Code Online (Sandbox Code Playgroud)
但它并没有完全发挥作用。它根本不显示文本,当我尝试将新的 Animated.Value 初始化为比 2 行高度更大的数字(例如 50)时,无论我展开和折叠多少次,高度总是会被截断为 16 。动画展开和折叠文本的最佳方式是什么?
我需要为动态高度组件解决这个问题,文本可以解析 HTML,因此我们考虑了时髦的格式,例如额外的行。这将使用嵌入的 HTML 扩展视图。如果您只是想控制文本布局,您可以通过更改文本道具的状态来重新渲染组件。删除或更改渐变的颜色以匹配您的背景。
该组件使用“onLayout”监听器渲染全文视图并获取高度,初始视图容器设置为静态高度,如果渲染的文本视图的完整高度大于初始高度,则“读取显示“更多”按钮,并为切换设置完整高度值。
另外,如果有人对所使用的弹簧动画感到好奇,这里有一个很好的资源:https://medium.com/kaliberinteractive/how-i-transitioned-from-ease-to-spring-animations-5a09eeca0325
https://reactnative.dev/docs/animated#spring
import React, { useEffect, useState, useRef } from 'react';
import {
Animated,
StyleSheet,
Text,
TouchableWithoutFeedback,
View,
} from 'react-native';
import LinearGradient from 'react-native-linear-gradient';
const MoreText = (props) => {
// const [text, setText] = useState('');
const startingHeight = 160;
const [expander, setExpander] = useState(false);
const [expanded, setExpanded] = useState(false);
const [fullHeight, setFullHeight] = useState(startingHeight);
const animatedHeight = useRef(new Animated.Value(startingHeight)).current;
useEffect(() => {
// expanded?setText(props.text): setText(props.text.substring(0, 40));
Animated.spring(animatedHeight, {
friction: 100,
toValue: expanded?fullHeight:startingHeight,
useNativeDriver: false
}).start();
}, [expanded]);
const onTextLayout = (e) => {
let {x, y, width, height} = e.nativeEvent.layout;
height = Math.floor(height) + 40;
if(height > startingHeight ){
setFullHeight(height);
setExpander(true);
}
};
return (
<View style={styles.container}>
<Animated.View style={[styles.viewPort, { height: animatedHeight }]}>
<View style={styles.textBox} onLayout={(e) => {onTextLayout(e)}}>
<Text style={styles.text}>{props.text}</Text>
</View>
</Animated.View>
{expander &&
<React.Fragment>
<LinearGradient
colors={[
'rgba(22, 22, 22,0.0)', // Change this gradient to match BG
'rgba(22, 22, 22,0.7)',
'rgba(22, 22, 22,0.9)',
]}
style={styles.gradient}/>
<TouchableWithoutFeedback onPress={() => {setExpanded(!expanded)}}>
<Text style={styles.readBtn}>{expanded?'Read Less':'Read More'}</Text>
</TouchableWithoutFeedback>
</React.Fragment>
}
</View>
);
}
const styles = StyleSheet.create({
absolute: {
position: "absolute",
height: 60,
left: 0,
bottom: 20,
right: 0
},
container: {
flex: 1,
},
viewPort: {
flex: 1,
overflow: 'hidden',
top: 12,
marginBottom: 20,
},
textBox: {
flex: 1,
position: 'absolute',
},
text: {
color: '#fff',
alignSelf: 'flex-start',
textAlign: 'justify',
fontSize: 14,
fontFamily: 'Avenir',
},
gradient:{
backgroundColor:'transparent', // required for gradient
height: 40,
width: '100%',
position:'absolute',
bottom: 20
},
readBtn: {
flex: 1,
color: 'blue',
alignSelf: 'flex-end',
},
});
export default MoreText;
Run Code Online (Sandbox Code Playgroud)
这解决了你的问题
import * as React from 'react';
import { Text, View, StyleSheet, Image,Animated,TouchableWithoutFeedback ,Easing} from 'react-native';
export default function AssetExample() {
const [expanded, setExpanded] = React.useState(true);
const animationHeight = React.useRef(new Animated.Value(2)).current;
const toggleExpansion = () => {
setExpanded(!expanded);
};
React.useEffect(() => {
if (expanded) {
Animated.timing(animationHeight, {
duration: 1000,
toValue: 60,
easing: Easing.linear
}).start();
}
else{
Animated.timing(animationHeight, {
duration: 1000,
toValue: 5,
easing: Easing.linear
}).start();
}
}, [expanded]);
return (
<View style={styles.container}>
<TouchableWithoutFeedback
onPress={() => {
toggleExpansion();
}}
>
<Animated.View style={[{ height: animationHeight }]}>
<Text numberOfLines={expanded ? 30 : 2} ellipsizeMode="tail">
{' line 1'}
{'\n'}
{'line 2'}
{'\n'}
{'line 3'}
</Text>
</Animated.View>
</TouchableWithoutFeedback>
</View>
);
}
const styles = StyleSheet.create({
container: {
alignItems: 'center',
justifyContent: 'center',
padding: 24,
},
});
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
26174 次 |
最近记录: |