react-native#LayoutAnimation JavaScript Examples
The following examples show how to use
react-native#LayoutAnimation.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: ClusteredMapView.js From guardioes-app with Apache License 2.0 | 6 votes |
ClusteredMapView.defaultProps = {
minZoom: 1,
maxZoom: 16,
extent: 512,
accessor: 'location',
animateClusters: true,
clusteringEnabled: true,
clusterPressMaxChildren: 100,
preserveClusterPressBehavior: true,
width: Dimensions.get('window').width,
height: Dimensions.get('window').height,
layoutAnimationConf: LayoutAnimation.Presets.spring,
edgePadding: { top: 10, left: 10, right: 10, bottom: 10 }
}
Example #2
Source File: ui.js From react-native-loop-game with MIT License | 6 votes |
initLayout = (duration = 200, type = 'linear') => {
if (type === 'spring') {
return LayoutAnimation.configureNext(LayoutAnimation.Presets.spring);
}
return LayoutAnimation.configureNext({
duration,
create: {
duration,
type: LayoutAnimation.Types[type],
property: LayoutAnimation.Properties.opacity,
},
update: {
duration,
type: LayoutAnimation.Types[type],
property: LayoutAnimation.Properties.opacity,
},
delete: {
duration,
type: LayoutAnimation.Types[type],
property: LayoutAnimation.Properties.opacity,
},
});
}
Example #3
Source File: BirthdayDataContext.js From Reminder-App with MIT License | 5 votes |
Birthday_reducer = (state, action) => {
switch (action.type) {
case "add_birthday":
LayoutAnimation.configureNext(LayoutAnimation.Presets.spring);
let data = [
...state,
{
text: `Tap to change the name`,
key: `key-${1 + Math.random() * 99}`,
height: 75,
Date: action.payload.time,
notificationId: action.payload.value,
},
];
storeData(data);
return data;
case "init_data":
if (action.payload === null) {
return [];
} else return action.payload;
case "delete_reminder":
case "delete_birthday":
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
data = state.filter((d) => d !== action.payload);
storeData(data);
return data;
case "edit":
data = state.filter((d) => {
if (d == action.payload.selecteditem) {
let tep = action.payload.selecteditem;
tep.Date = action.payload.time;
tep.text = action.payload.text;
tep.notificationId = action.payload.id;
return tep;
} else return d;
});
storeData(data);
return data;
default:
return state;
}
}
Example #4
Source File: ReminderDataContext.js From Reminder-App with MIT License | 5 votes |
Reminder_reducer = (state, action) => {
switch (action.type) {
case "add_reminder":
LayoutAnimation.configureNext(LayoutAnimation.Presets.spring);
let data = [
...state,
{
text: `Tap to edit`,
key: `key-${1 + Math.random() * 99}`,
height: 75,
Date: action.payload.time,
notificationId: action.payload.value,
},
];
storeData(data);
return data;
case "init_data":
if (action.payload === null) {
return [];
} else return action.payload;
case "delete_reminder":
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
data = state.filter((d) => d !== action.payload);
storeData(data);
return data;
case "snooze":
data = state.filter((d) => {
if (d.notificationId == action.payload.id) {
let tep = d;
tep.Date = action.payload.time;
tep.notificationId = action.payload.newid;
return tep;
} else return d;
});
storeData(data);
return data;
case "edit":
data = state.filter((d) => {
if (d == action.payload.selecteditem) {
let tep = action.payload.selecteditem;
tep.Date = action.payload.time;
tep.text = action.payload.text;
tep.notificationId = action.payload.id;
return tep;
} else return d;
});
storeData(data);
return data;
default:
return state;
}
}
Example #5
Source File: ClusteredMapView.js From guardioes-app with Apache License 2.0 | 5 votes |
componentWillUpdate(nextProps, nextState) {
if (!this.isAndroid && this.props.animateClusters && this.clustersChanged(nextState))
LayoutAnimation.configureNext(this.props.layoutAnimationConf)
}
Example #6
Source File: OnBoarding.js From reactnative-best-practice with MIT License | 5 votes |
export default function OnBoardingScreen() {
const navigation = useNavigation();
const {navigate} = navigation;
const skipContext = useContext(CTX);
const {_seen} = skipContext;
useEffect(() => {
LayoutAnimation.easeInEaseOut();
});
function _renderItem({item}) {
return (
<View style={[styles.slide, {backgroundColor: item.backgroundColor}]}>
<Text style={item.color}>{item.title}</Text>
<Image style={styles.image} source={item.image} />
<Text style={styles.text}>{item.text}</Text>
</View>
);
}
function _onDone() {
// User finished the introduction. Show real app through
// navigation or simply by controlling state
// this.setState({showRealApp: true});
_seen();
}
_renderNextButton = () => {
return (
<View style={styles.buttonCircle}>
<FontAwesome5
name="chevron-right"
color="#FFFFFF"
size={24}
style={{backgroundColor: 'transparent'}}
/>
</View>
);
};
_renderDoneButton = () => {
return (
<View style={styles.buttonCircle}>
<FontAwesome5
name="check-circle"
color="#FFFFFF"
size={24}
style={{backgroundColor: 'transparent'}}
/>
</View>
);
};
return (
<AppIntroSlider
renderItem={_renderItem}
slides={slides}
onDone={_onDone}
activeDotStyle={{backgroundColor: primaryColor}}
renderNextButton={_renderNextButton}
renderDoneButton={_renderDoneButton}
/>
);
}
Example #7
Source File: ReadMore.js From react-native-read-more with MIT License | 5 votes |
readmoreAnimation = LayoutAnimation.create( 300, LayoutAnimation.Types.easeOut, LayoutAnimation.Properties.opacity, )
Example #8
Source File: Birthday_Screen.js From Reminder-App with MIT License | 4 votes |
function My_List() {
const { state, add_birthday, delete_birthday, edit } = useContext(Context);
const { colors } = useTheme();
const [showmodel, setmodel] = useState(false);
const [selecteditem, setselecteditem] = useState(null);
useEffect(() => {
state.sort(function (a, b) {
var keyA = new Date(a.Date).getTime(),
keyB = new Date(b.Date).getTime();
if (keyA < keyB) return -1;
if (keyA > keyB) return 1;
return 0;
});
}, [state]);
useEffect(() => {
state.map((item) => {
edit({ selecteditem: item, text: item.text, time: item.Date });
});
}, []);
let itemRefs = new Map();
const chnage_model = (item) => {
LayoutAnimation.configureNext(
LayoutAnimation.create(
200,
LayoutAnimation.Types.linear,
LayoutAnimation.Properties.opacity
)
);
setselecteditem(item);
setmodel(!showmodel);
};
const hide_model = () => {
LayoutAnimation.configureNext(
LayoutAnimation.create(
200,
LayoutAnimation.Types.linear,
LayoutAnimation.Properties.opacity
)
);
setmodel(false);
setselecteditem(null);
};
function emptylist() {
return (
<View
style={{
justifyContent: "center",
alignItems: "center",
}}
>
<Text
style={[
styles.text,
{ fontSize: 25, textAlign: "center", color: colors.text },
]}
>
{"Click on the plus icon to add Birthday Reminder."}
</Text>
</View>
);
}
function footer() {
return (
<View
style={{
height: 75,
justifyContent: "center",
alignItems: "center",
}}
>
<TouchableOpacity
onPress={() => {
add_birthday();
}}
>
<AntDesign name="plus" size={34} color={colors.text} />
</TouchableOpacity>
</View>
);
}
if (showmodel) {
return (
<Model edit={edit} hide_model={hide_model} selecteditem={selecteditem} />
);
}
function header() {
return (
<View style={styles.TitleContainer}>
<Text style={[styles.text, { fontSize: 45, color: colors.text }]}>
Birthdays
</Text>
</View>
);
}
return (
<View style={styles.container}>
<FlatList
ListHeaderComponent={header}
ListEmptyComponent={emptylist}
style={{ flex: 0.8 }}
keyExtractor={(item) => item.key}
data={state}
renderItem={({ item, index }) => (
<Element
index={index}
item={item}
itemRefs={itemRefs}
deleteItem={(item) => {
delete_birthday(item);
}}
showmodel={chnage_model}
/>
)}
ListFooterComponent={footer}
/>
</View>
);
}
Example #9
Source File: Reminder_Screen.js From Reminder-App with MIT License | 4 votes |
function My_List() {
const { state, add_reminder, delete_reminder, edit } = useContext(Context);
const { colors } = useTheme();
const [showmodel, setmodel] = useState(false);
const [selecteditem, setselecteditem] = useState(null);
let itemRefs = new Map();
useEffect(() => {
state.map((item) => {
let ti = new Date(item.Date);
if (ti.getTime() <= Date.now()) {
delete_reminder(item);
}
});
state.sort(function (a, b) {
var keyA = new Date(a.Date).getTime(),
keyB = new Date(b.Date).getTime();
if (keyA < keyB) return -1;
if (keyA > keyB) return 1;
return 0;
});
}, [state]);
const chnage_model = (item) => {
LayoutAnimation.configureNext(
LayoutAnimation.create(
200,
LayoutAnimation.Types.linear,
LayoutAnimation.Properties.opacity
)
);
setselecteditem(item);
setmodel(!showmodel);
};
const hide_model = () => {
LayoutAnimation.configureNext(
LayoutAnimation.create(
200,
LayoutAnimation.Types.linear,
LayoutAnimation.Properties.opacity
)
);
setmodel(false);
setselecteditem(null);
};
function emptylist() {
return (
<View
style={{
justifyContent: "center",
alignItems: "center",
}}
>
<Text
style={[
styles.text,
{ fontSize: 25, textAlign: "center", color: colors.text },
]}
>
{
"Looks like you have no reminder! \n Click on the plus icon to add one."
}
</Text>
</View>
);
}
function footer() {
return (
<View
style={{
height: 75,
justifyContent: "center",
alignItems: "center",
}}
>
<TouchableOpacity
onPress={() => {
add_reminder();
}}
>
<AntDesign name="plus" size={34} color={colors.text} />
</TouchableOpacity>
</View>
);
}
if (showmodel) {
return (
<Model edit={edit} hide_model={hide_model} selecteditem={selecteditem} />
);
}
function header() {
return (
<View style={styles.TitleContainer}>
<Text style={[styles.text, { fontSize: 45, color: colors.text }]}>
Reminders
</Text>
</View>
);
}
return (
<View style={styles.container}>
<FlatList
ListHeaderComponent={header}
ListEmptyComponent={emptylist}
style={{ flex: 0.8 }}
keyExtractor={(item) => item.key}
data={state}
renderItem={({ item, index }) => (
<Element
index={index}
item={item}
itemRefs={itemRefs}
deleteItem={(item) => {
delete_reminder(item);
}}
showmodel={chnage_model}
/>
)}
ListFooterComponent={footer}
// onDragEnd={({ data }) => this.setState({ data })}
// activationDistance={10}
/>
</View>
);
}
Example #10
Source File: LoginScreen.js From geometry_3d with MIT License | 4 votes |
function LoginScreen(props) {
const { navigate } = useNavigation();
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [errorMessage, setErrorMessage] = useState("");
const [visible, setVisible] = useState(false);
const handleLogin = () => {
setVisible(() => true);
fb.auth
.signInWithEmailAndPassword(email, password)
.then(() => {
props.reduxSetCurrentUser({
email: email,
password: password,
});
setVisible(() => false);
//console.log(props.currentUser);
})
.catch((error) => {
setErrorMessage(error.message);
setVisible(() => false);
});
};
useEffect(() => {
LayoutAnimation.easeInEaseOut();
});
return visible ? (
<LoadingScreen />
) : (
<KeyboardAwareScrollView
resetScrollToCoords={{ x: 0, y: 0 }}
contentContainerStyle={styles.container}
enableOnAndroid={true}
keyboardShouldPersistTaps="handled"
scrollEnabled={true}
enableAutomaticScroll={Platform.OS === "ios"}
>
<StatusBar barStyle="light-content"></StatusBar>
<ScrollView keyboardShouldPersistTaps={'handled'} style={{backgroundColor: 'black'}}>
<Text style={styles.greeting}>{"Hello! \nWelcome back"}</Text>
<View style={styles.errorMessage}>
<Text style={styles.error}>{errorMessage}</Text>
</View>
<View style={styles.form}>
<View>
<Text style={styles.inputTitle}>Email Address</Text>
<TextInput
style={styles.input}
autoCapitalize="none"
onChangeText={(emailInput) => setEmail(() => emailInput.trim())}
value={email}
></TextInput>
</View>
<View>
<Text textBreakStrategy={"simple"} style={styles.inputTitle}>Password</Text>
<TextInput
style={styles.input}
secureTextEntry
autoCapitalize="none"
onChangeText={(passwordInput) => setPassword(() => passwordInput.trim())}
value={password}
></TextInput>
</View>
<TouchableOpacity style={styles.button} onPress={handleLogin}>
<Text textBreakStrategy={"simple"} style={{ color: "white", fontWeight: "500" }}>Sign in</Text>
</TouchableOpacity>
<TouchableOpacity style={{...styles.button, marginTop: 10, backgroundColor: "#2bffea"}} onPress={() => {
navigate("App", {}, NavigationActions.navigate({routeName: "HomeScreen"}))
}}>
<Text textBreakStrategy={"simple"} style={{ color: "black", fontWeight: "500" }}>Guest session</Text>
</TouchableOpacity>
<TouchableOpacity
style={{ alignSelf: "center", marginTop: 32 }}
onPress={() => navigate("Register")}
>
<Text textBreakStrategy={"simple"} style={{ color: "white", fontSize: 13 }}>
First time?
<Text textBreakStrategy={"simple"} style={{ color: "#478eff", fontWeight: "500" }}>
{" "}
Sign up!
</Text>
</Text>
</TouchableOpacity>
</View>
</ScrollView>
</KeyboardAwareScrollView>
);
}
Example #11
Source File: RegisterScreen.js From geometry_3d with MIT License | 4 votes |
export default function RegisterScreen() {
const navigate = useNavigation();
const [name, setName] = useState("");
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [errorMessage, setErrorMessage] = useState("");
const [visible, setVisible] = useState(false);
const handleRegister = () => {
if (errorMessage === "") {
setVisible(() => true);
fb.auth
.createUserWithEmailAndPassword(email, password)
.then((userCredentials) => {
setVisible(() => false);
fb.userCollection.doc(userCredentials.user.uid).set({
scenes: [],
uid: userCredentials.user.uid
});
return userCredentials.user.updateProfile({
displayName: name,
});
})
.catch((error) => {
setVisible(() => false);
setErrorMessage(error);
});
}
};
useEffect(() => {
LayoutAnimation.easeInEaseOut();
});
return visible ? (
<LoadingScreen />
) : (
<KeyboardAwareScrollView
resetScrollToCoords={{ x: 0, y: 0 }}
contentContainerStyle={styles.container}
enableOnAndroid={true}
keyboardShouldPersistTaps="handled"
scrollEnabled={true}
enableAutomaticScroll={Platform.OS === "ios"}
>
<StatusBar barStyle="light-content"></StatusBar>
<ScrollView
keyboardShouldPersistTaps={"handled"}
style={{
height: "100%",
backgroundColor: 'black'
}}
>
<TouchableOpacity style={styles.back} onPress={() => navigate.goBack()}>
<Ionicons name="ios-arrow-round-back" color="white" size={32} />
</TouchableOpacity>
<Text style={styles.greeting}>{"Become one of us"}</Text>
<View style={styles.errorMessage}>
<Text style={styles.error}>{errorMessage.message}</Text>
</View>
<View style={styles.form}>
<View>
<Text style={styles.inputTitle}>Name</Text>
<TextInput
style={styles.input}
autoCapitalize="none"
onChangeText={(nameInput) => setName(() => nameInput.trim())}
value={name}
></TextInput>
</View>
<View>
<Text style={styles.inputTitle}>Email Address</Text>
<TextInput
style={styles.input}
autoCapitalize="none"
onChangeText={(emailInput) => setEmail(() => emailInput.trim())}
value={email}
></TextInput>
</View>
<View>
<Text style={styles.inputTitle}>Password</Text>
<TextInput
style={styles.input}
secureTextEntry
autoCapitalize="none"
onChangeText={(password) => setPassword(() => password.trim())}
value={password}
></TextInput>
</View>
<View>
<Text style={styles.inputTitle}>Confirm Password</Text>
<TextInput
style={styles.input}
secureTextEntry
autoCapitalize="none"
onChangeText={(passwordInput) => {
//setPasswordConfirm(passwordInput)
if (passwordInput != password)
setErrorMessage(() => "Incorrect Passwords");
else setErrorMessage(() => "");
}}
></TextInput>
</View>
<TouchableOpacity style={styles.button} onPress={handleRegister}>
<Text style={{ color: "white", fontWeight: "500" }}>Register</Text>
</TouchableOpacity>
</View>
</ScrollView>
</KeyboardAwareScrollView>
);
}
Example #12
Source File: ReadMore.js From react-native-read-more with MIT License | 4 votes |
ReadMore = ({
numberOfLines,
style,
wrapperStyle,
children,
seeMoreStyle,
seeMoreText,
seeLessStyle,
seeLessText,
animate,
customTextComponent: TextComponent,
ellipsis,
allowFontScaling,
onExpand,
onCollapse,
expandOnly,
seeMoreOverlapCount,
debounceSeeMoreCalc,
onReady,
seeMoreContainerStyleSecondary,
onSeeMoreBlocked,
debug,
...restProps
}) => {
const [additionalProps, setAdditionalProps] = useState({});
// hiddenTextLinesWithSeeLess comes from hidden component two
const [hiddenTextLinesWithSeeLess, setHiddenTextLinesWithSeeLess] = useState(
[],
);
const [textWidth, setTextWidth] = useState(0);
const [truncatedLineOfImpact, setTruncatedLineOfImpact] = useState('');
const [truncatedLineOfImpactWidth, setTruncatedLineOfImpactWidth] =
useState(0);
const [lines, setLines] = useState([]);
const [collapsedLines, setCollapsedLines] = useState([]);
const [seeMoreRightPadding, setSeeMoreRightPadding] = useState(0);
// mount or unmount hidden components
const [mountHiddenTextOne, setMountHiddenTextOne] = useState(false);
const [mountHiddenTextTwo, setMountHiddenTextTwo] = useState(false);
const [mountHiddenTextThree, setMountHiddenTextThree] = useState(false);
const [mountHiddenTextFour, setMountHiddenTextFour] = useState(false);
const [mountHiddenTextFive, setMountHiddenTextFive] = useState(false);
const [mountHiddenTextSix, setMountHiddenTextSix] = useState(false);
// initial measurement is in progress
const [isMeasured, setIsMeasured] = useState(false);
const [isReady, setIsReady] = useState(false);
// logic decisioning params
const [seeMore, setSeeMore] = useState(false);
const [collapsed, setCollapsed] = useState(true);
const [afterCollapsed, setAfterCollapsed] = useState(true);
// copy of children with only text
const [collapsedChildren, setCollapsedChildren] = useState(null);
const [reconciledLineOfImpact, setReconciledLineOfImpact] = useState('');
// eslint-disable-next-line prettier/prettier
const [reconciledLineOfImpactWidth, setReconciledLineOfImpactWidth] = useState(0);
// width of see more component
const [seeMoreWidth, setSeeMoreWidth] = useState(0);
const [hideEllipsis, setHideEllipsis] = useState(false);
// eslint-disable-next-line react-hooks/exhaustive-deps
const log = useCallback(logClosure(debug), [debug]);
const onSeeMoreViewLayout = useCallback(
({
nativeEvent: {
layout: {width},
},
}) => {
setSeeMoreWidth(width);
},
[setSeeMoreWidth],
);
const onTextLayoutOne = useCallback(
({nativeEvent: {lines: _lines}}) => {
setLines(_lines);
setMountHiddenTextOne(false);
setMountHiddenTextTwo(true);
},
[setLines, setMountHiddenTextOne],
);
const onTextLayoutTwo = useCallback(
({nativeEvent: {lines: _lines}}) => {
setHiddenTextLinesWithSeeLess(_lines);
setMountHiddenTextTwo(false);
setMountHiddenTextThree(true);
},
[
setHiddenTextLinesWithSeeLess,
setMountHiddenTextTwo,
setMountHiddenTextThree,
],
);
const onLayoutHiddenTextThree = useCallback(
event => {
const _event = event; // clone event
const _width = _event?.nativeEvent?.layout?.width || 0;
setTextWidth(_width);
setMountHiddenTextThree(false);
},
[setTextWidth, setMountHiddenTextThree],
);
const onTextLayoutHiddenTextThree = useCallback(
event => {
const _event = event; // clone event
if (collapsed) {
const _lines = _event?.nativeEvent?.lines || [];
setCollapsedLines(_lines);
}
},
[setCollapsedLines, collapsed],
);
const onLayoutFour = useCallback(
({
nativeEvent: {
layout: {width},
},
}) => {
setTruncatedLineOfImpactWidth(width);
setMountHiddenTextFour(false);
setMountHiddenTextFive(true);
},
[
setTruncatedLineOfImpactWidth,
setMountHiddenTextFour,
setMountHiddenTextFive,
],
);
const onLayoutHiddenTextFive = useCallback(() => {
setMountHiddenTextFive(false);
setMountHiddenTextSix(true);
}, [setMountHiddenTextFive, setMountHiddenTextSix]);
const onTextLayoutHiddenTextFive = useCallback(
({nativeEvent: {lines: _lines}}) => {
const _lineOfImpact = _lines[numberOfLines - 1];
setReconciledLineOfImpact(_lineOfImpact?.text?.trimEnd?.() || '');
},
[numberOfLines, setReconciledLineOfImpact],
);
const onLayoutHiddenTextSix = useCallback(
({
nativeEvent: {
layout: {width},
},
}) => {
setMountHiddenTextSix(false);
setReconciledLineOfImpactWidth(reconciledLineOfImpact ? width : 0);
},
[
setReconciledLineOfImpactWidth,
setMountHiddenTextSix,
reconciledLineOfImpact,
],
);
const toggle = useCallback(() => {
if (onSeeMoreBlocked) {
onSeeMoreBlocked();
} else {
setCollapsed(prev => !prev);
}
}, [setCollapsed, onSeeMoreBlocked]);
const updateLineOfImpact = useCallback(
(_text = '', resetCollapsedChildren = true) => {
setHideEllipsis(!_text?.length);
setTruncatedLineOfImpact(_text || '');
if (!_text?.length) {
// reset width if no text
// otherwise an effect will update the width
setTruncatedLineOfImpactWidth(0);
setReconciledLineOfImpactWidth(0);
setSeeMoreRightPadding(0);
setIsMeasured(true);
}
if (resetCollapsedChildren) {
setCollapsedChildren(null);
}
},
[
setHideEllipsis,
setTruncatedLineOfImpact,
setTruncatedLineOfImpactWidth,
setCollapsedChildren,
setIsMeasured,
],
);
const measureSeeMoreLine = useCallback(() => {
if (
numberOfLines < 1 ||
!lines.length ||
!collapsedLines.length ||
!seeMore ||
!seeMoreWidth
) {
log('terminating measurements for see more - 1');
return;
}
if (!lines[numberOfLines - 1] || !collapsedLines[numberOfLines - 1]) {
log('terminating measurements for see more - 2');
return;
}
// find line of impact
let _lineOfImpact = lines[numberOfLines - 1];
_lineOfImpact.index = numberOfLines - 1;
if (Platform.OS === 'ios') {
const modifiedIndex = lines.findIndex((_line, index) => {
if (index < numberOfLines - 1 || !_line.text?.trimEnd?.()) {
return false;
}
return collapsedLines[numberOfLines - 1].text.includes(_line.text);
});
if (modifiedIndex !== -1) {
_lineOfImpact = lines[modifiedIndex];
_lineOfImpact.index = modifiedIndex;
}
}
const _trimmedText = _lineOfImpact?.text?.trimEnd?.();
// calculate how many characters to cut off if any
// trim right before -> spaces and \n
// width from line, textWidth, seeMoreWidth
if (_trimmedText?.length && !textWidth) {
// textWidth is being measured
return;
}
// case 1
log('case 1');
// if no text after right trim
// hide ellipsis
// move see more to beginning
if (!_trimmedText?.length) {
return updateLineOfImpact(_trimmedText);
}
const availableWidth = textWidth - seeMoreWidth;
// case 2
log('case 2');
// text is there but no need to put \n
// enough space for see more text on right side
if (_lineOfImpact.width < availableWidth) {
return updateLineOfImpact(_trimmedText);
}
const seeMoreTextLength =
`${ellipsis} ${seeMoreText}`.length + seeMoreOverlapCount;
// case 3
log('case 3');
// many spaces at the end of text
// so still no need to cutoff the text at end with \n
const spaceDifference = _lineOfImpact?.text?.length - _trimmedText?.length;
if (spaceDifference >= seeMoreTextLength) {
return updateLineOfImpact(_trimmedText);
}
// case 4
log('case 4');
// create collapsed children with \n at the point
const linesTillImpact = Array(_lineOfImpact.index + 1)
.fill({})
.map((_e, index) => lines[index]);
const charactersBeforeSeeMore = linesToCharacters(linesTillImpact);
const charactersLengthTillSeeMore =
charactersBeforeSeeMore?.trimEnd?.()?.length || 0;
// text break position for collapsed text
const textBreakPosition = charactersLengthTillSeeMore - seeMoreTextLength;
const _truncatedText =
_trimmedText
?.substr(0, _trimmedText.length - seeMoreTextLength)
?.trimEnd?.() || '';
// go to this position and insert \n
let charactersToTraverse = textBreakPosition;
let nodeFound = false;
const modifiedChildrenObjects = getTextByChildren(children, TextComponent)
?.map(_childObject => {
if (nodeFound) {
return _childObject;
}
if (_childObject.content.length > charactersToTraverse) {
// this node is the one
nodeFound = true;
const childContent = insertAt(
_childObject.content,
'\n',
charactersToTraverse,
);
return {
type: _childObject?.type,
content: childContent,
child:
_childObject?.type === 'string'
? childContent
: React.cloneElement(
_childObject,
_childObject.props,
childContent,
),
};
}
charactersToTraverse =
charactersToTraverse - _childObject.content.length;
return _childObject;
})
?.map(_updatedObjects => {
return _updatedObjects.child;
});
if (nodeFound) {
setCollapsedChildren(modifiedChildrenObjects);
return updateLineOfImpact(_truncatedText, false);
}
// todo: inform user
// error case
return updateLineOfImpact(_trimmedText);
}, [
numberOfLines,
lines,
collapsedLines,
seeMore,
textWidth,
seeMoreWidth,
ellipsis,
seeMoreText,
seeMoreOverlapCount,
children,
TextComponent,
updateLineOfImpact,
log,
]);
const textProps = afterCollapsed
? {
numberOfLines,
ellipsizeMode: 'clip',
}
: {};
const commonHiddenComponentProps = {
...additionalProps,
style: StyleSheet.flatten([
Array.isArray(style) ? StyleSheet.flatten(style) : style,
styles.hiddenTextAbsolute,
]),
};
const hiddenComponentPropsLineOfImpact = {
...additionalProps,
style: StyleSheet.flatten([
Array.isArray(style) ? StyleSheet.flatten(style) : style,
styles.hiddenTextAbsoluteCompact,
]),
};
// use after measured here
const seeMoreTextHidingStyle = !isMeasured
? styles.transparentColor
: styles.transparentBackground;
const seeMoreContainerStyle = [
hideEllipsis
? styles.seeMoreContainerEllpisisHidden
: styles.seeMoreContainer,
{
marginRight: seeMoreRightPadding,
},
];
useEffect(() => {
const _seeMore = lines.length > numberOfLines;
setSeeMore(_seeMore);
if (!lines?.length) {
return;
}
if (!_seeMore) {
log('no measurement is needed');
onReady();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [numberOfLines, lines]);
useEffect(() => {
if (collapsed === afterCollapsed) {
return;
}
const callback = collapsed ? onCollapse : onExpand;
if (animate) {
LayoutAnimation.configureNext(readmoreAnimation, callback);
} else {
callback();
}
setAfterCollapsed(collapsed);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [collapsed]);
useEffect(() => {
const handle = setTimeout(() => {
// to commence measurement chain
// we should mount component 1
// also reset isMeasured
setMountHiddenTextOne(true);
}, debounceSeeMoreCalc);
return () => clearTimeout(handle);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [
// re calc if any of these params change
numberOfLines,
style,
wrapperStyle,
children,
seeMoreStyle,
seeMoreText,
seeLessStyle,
seeLessText,
ellipsis,
additionalProps,
]);
useEffect(() => {
// a map of additional props to be passed down
// in hidden text components other than style
// for accurate measurements
const _additionalProps = {};
// pick selected params
if (allowFontScaling !== undefined) {
_additionalProps.allowFontScaling = allowFontScaling;
}
setAdditionalProps(_additionalProps);
}, [allowFontScaling]);
useEffect(() => {
if (mountHiddenTextTwo && !seeMoreWidth && collapsedLines?.length) {
return;
}
// only start measurement after component 2 is unmounted and see more width is calculated
// since component 1 mounts -> unmounts -> mounts component 2
// then component 2 unmounts itself
// and then all measurement params are available
const handle = setTimeout(measureSeeMoreLine, debounceSeeMoreCalc);
return () => clearTimeout(handle);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [mountHiddenTextTwo, seeMoreWidth, collapsedLines, textWidth]);
useEffect(() => {
if (!truncatedLineOfImpact) {
return;
}
setMountHiddenTextFour(true);
}, [truncatedLineOfImpact]);
useEffect(() => {
if (
!(truncatedLineOfImpactWidth || reconciledLineOfImpactWidth) ||
!seeMoreWidth ||
!textWidth
) {
return;
}
const _width =
reconciledLineOfImpactWidth || truncatedLineOfImpactWidth || 0;
let _seeMoreRightPadding = textWidth - _width - seeMoreWidth;
_seeMoreRightPadding = _seeMoreRightPadding < 0 ? 0 : _seeMoreRightPadding;
setSeeMoreRightPadding(_seeMoreRightPadding);
setIsMeasured(true);
}, [
truncatedLineOfImpactWidth,
reconciledLineOfImpactWidth,
seeMoreWidth,
textWidth,
]);
useEffect(() => {
if (!isMeasured || isReady) {
return;
}
const handle = setTimeout(() => {
setIsReady(true);
onReady();
}, debounceSeeMoreCalc);
return () => clearTimeout(handle);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isMeasured, isReady]);
return (
<View style={wrapperStyle}>
{/* text component to measure see if see more is applicable and get lines */}
{mountHiddenTextOne && (
<TextComponent
{...commonHiddenComponentProps}
onTextLayout={onTextLayoutOne}>
{children || ''}
</TextComponent>
)}
{/* text component to measure lines with see less */}
{mountHiddenTextTwo && (
<TextComponent
{...commonHiddenComponentProps}
onTextLayout={onTextLayoutTwo}>
{children || ''}
{/* 3 spaces before see less are intentional */}
{` ${seeLessText}`}
</TextComponent>
)}
{/* extract width of line of impact without see more line */}
{mountHiddenTextFour && (
<TextComponent
{...hiddenComponentPropsLineOfImpact}
onLayout={onLayoutFour}>
{truncatedLineOfImpact}
</TextComponent>
)}
{mountHiddenTextThree && (
<TextComponent
{...commonHiddenComponentProps}
numberOfLines={numberOfLines}
ellipsizeMode={'clip'}
onLayout={onLayoutHiddenTextThree}
onTextLayout={onTextLayoutHiddenTextThree}>
{children || ''}
</TextComponent>
)}
{/* extract line of impact with collapsed children for remeasurement of right padding on android */}
{mountHiddenTextFive && (
<TextComponent
{...commonHiddenComponentProps}
numberOfLines={numberOfLines + 1}
onLayout={onLayoutHiddenTextFive}
onTextLayout={onTextLayoutHiddenTextFive}>
{collapsedChildren || ''}
{/* no see less here since it's in collapsed state replicating original component */}
</TextComponent>
)}
{/* extract width of reconciled line of impact without see more line */}
{mountHiddenTextSix && (
<TextComponent
{...hiddenComponentPropsLineOfImpact}
onLayout={onLayoutHiddenTextSix}>
{reconciledLineOfImpact}
</TextComponent>
)}
{/* actual text component */}
<TextComponent
{...additionalProps}
{...restProps}
style={style}
{...textProps}>
{seeMore && collapsed
? collapsedChildren || children || ''
: children || ''}
{seeMore && !collapsed && !expandOnly && (
<TextComponent
{...additionalProps}
{...restProps}
onPress={toggle}
style={seeLessStyle}>
{hiddenTextLinesWithSeeLess.length > lines.length ? '\n' : ' '}
{seeLessText}
</TextComponent>
)}
</TextComponent>
{/* See more component */}
{seeMore && collapsed && afterCollapsed && (
<View
style={[seeMoreContainerStyle, seeMoreContainerStyleSecondary]}
onLayout={onSeeMoreViewLayout}>
{!hideEllipsis && (
<TextComponent
key={`${isMeasured}-${hideEllipsis}`}
{...additionalProps}
{...restProps}
onPress={toggle}
style={[
style,
seeMoreTextHidingStyle,
hideEllipsis ? styles.transparentColor : {},
]}>
{`${ellipsis} `}
</TextComponent>
)}
<TextComponent
{...additionalProps}
{...restProps}
onPress={toggle}
style={[style, seeMoreStyle, seeMoreTextHidingStyle]}>
{seeMoreText}
</TextComponent>
</View>
)}
</View>
);
}
Example #13
Source File: VLCPlayerView.js From react-native-vlc with MIT License | 4 votes |
render() {
const {
onEnd,
style,
isAd,
type,
isFull,
uri,
title,
onLeftPress,
closeFullScreen,
showBack,
showTitle,
videoAspectRatio,
showGoLive,
onGoLivePress,
onReplayPress,
titleGolive,
showLeftButton,
showMiddleButton,
showRightButton,
errorTitle,
animationLayout,
videoStyle,
...otherProps
} = this.props;
const { isLoading, loadingSuccess, showControls, isError } = this.state;
let showAd = false;
let realShowLoading = false;
let source = {};
if (uri) {
if (uri.split) {
source = { uri: this.props.uri };
} else {
source = uri;
}
}
if (Platform.OS === 'ios') {
if ((loadingSuccess && isAd) || (isAd && type === 'swf')) {
showAd = true;
}
if (isLoading && type !== 'swf') {
realShowLoading = true;
}
} else {
if (loadingSuccess && isAd) {
showAd = true;
}
if (isLoading) {
realShowLoading = true;
}
}
return (
<TouchableOpacity
activeOpacity={1}
style={[styles.videoBtn, style, videoStyle]}
onPressOut={() => {
let currentTime = new Date().getTime();
if (this.touchTime === 0) {
this.touchTime = currentTime;
animationLayout && LayoutAnimation.configureNext(LayoutAnimation.Presets.linear);
this.setState({ showControls: !this.state.showControls });
} else {
if (currentTime - this.touchTime >= 500) {
this.touchTime = currentTime;
animationLayout && LayoutAnimation.configureNext(LayoutAnimation.Presets.linear);
this.setState({ showControls: !this.state.showControls });
}
}
}}>
<VLCPlayer
{...otherProps}
ref={ref => (this.vlcPlayer = ref)}
paused={this.state.paused}
style={[styles.video]}
source={source}
videoAspectRatio={videoAspectRatio}
onProgress={this.onProgress.bind(this)}
onEnd={this.onEnded.bind(this)}
onStopped={this.onEnded.bind(this)}
onPlaying={this.onPlaying.bind(this)}
onBuffering={this.onBuffering.bind(this)}
onPaused={this.onPaused.bind(this)}
progressUpdateInterval={250}
onError={this._onError}
onOpen={this._onOpen}
onLoadStart={this._onLoadStart}
/>
{realShowLoading &&
!isError && (
<View style={styles.loading}>
<ActivityIndicator size={'large'} animating={true} color="#fff" />
</View>
)}
{isError && (
<View style={[styles.loading, { backgroundColor: '#000' }]}>
<Text style={{ color: 'red' }}>{errorTitle}</Text>
<TouchableOpacity
activeOpacity={1}
onPress={this._reload}
style={{
width: 100,
alignItems: 'center',
justifyContent: 'center',
marginTop: 10,
}}>
<Icon name='reload' size={45} color="#fff" />
</TouchableOpacity>
</View>
)}
<View style={styles.topView}>
<View style={styles.backBtn}>
{showBack && (
<TouchableOpacity
onPress={() => {
if (isFull) {
closeFullScreen && closeFullScreen();
} else {
onLeftPress && onLeftPress();
}
}}
style={styles.btn}
activeOpacity={0.8}>
<Icon name={'chevron-left'} size={30} color="#fff" />
</TouchableOpacity>
)}
<View style={{ justifyContent: 'center', flex: 1, marginRight: 10 }}>
{showTitle &&
showControls && (
<Text style={{ color: '#fff', fontSize: 16 }} numberOfLines={1}>
{title}
</Text>
)}
</View>
{showAd && (
<View style={styles.ad}>
<TimeLimt
onEnd={() => {
onEnd && onEnd();
}}
/>
</View>
)}
</View>
</View>
<View style={[styles.bottomView]}>
{showControls && (
<ControlBtn
showSlider={!isAd}
showAd={showAd}
onEnd={onEnd}
title={title}
onLeftPress={onLeftPress}
paused={this.state.paused}
isFull={isFull}
currentTime={this.state.currentTime}
totalTime={this.state.totalTime}
onPausedPress={this._play}
onFullPress={this._toFullScreen}
onValueChange={value => {
this.changingSlider = true;
this.setState({
currentTime: value,
});
}}
onSlidingComplete={value => {
this.changingSlider = false;
if (Platform.OS === 'ios') {
this.vlcPlayer.seek(Number((value / this.state.totalTime).toFixed(17)));
} else {
this.vlcPlayer.seek(value);
}
}}
showGoLive={showGoLive}
onGoLivePress={onGoLivePress}
onReplayPress={onReplayPress}
titleGolive={titleGolive}
showLeftButton={showLeftButton}
showMiddleButton={showMiddleButton}
showRightButton={showRightButton}
/>
)}
</View>
</TouchableOpacity>
);
}
Example #14
Source File: FileUpload.native.js From blade with MIT License | 4 votes |
FileUpload = ({
title,
progress,
fileName,
fileTypes,
errorText,
helpText,
onFileSelectionError,
onFileSelected,
onFileRemoved,
}) => {
const [file, setFileName] = useState(fileName);
const hasUploadCompleted = progress >= MAX_PROGRESS_VALUE;
const handleFileRemoval = () => {
onFileRemoved();
};
useEffect(() => {
if (fileName) {
setFileName(fileName);
} else if (!fileName) {
setFileName('');
}
LayoutAnimation.easeInEaseOut();
}, [fileName]);
const handleFilePick = async () => {
try {
const document = await DocumentPicker.pick({
type: !fileTypes
? DocumentPicker.types.allFiles
: Object.keys(DocumentPicker.types).filter((type) => fileTypes.includes(type)),
});
setFileName(document.name);
onFileSelected({
uri: document.uri,
type: document.type,
name: document.name,
size: document.size,
});
} catch (err) {
if (DocumentPicker.isCancel(err)) {
// User when cancels the native selection
} else {
onFileSelectionError(err);
}
}
};
return (
<Size width="100%">
<View>
<Size height={6}>
<Flex alignItems="center" justifyContent="center">
{file ? (
<Space padding={[1, 1.5]}>
<UploadContainer>
<Flex flexDirection="row" alignItems="center">
<Space margin={[0, 0, 1, 0]}>
<View>
{hasUploadCompleted && !errorText ? (
<Space margin={[0, 1, 0, 0]}>
<View>
<CheckedCircle size="small" fill="positive.960" />
</View>
</Space>
) : null}
<Flex flex={2}>
<View>
<Text size="xsmall" color="shade.980">
{title}
</Text>
</View>
</Flex>
<TouchableOpacity onPress={handleFileRemoval}>
<Close size="small" fill="shade.800" />
</TouchableOpacity>
</View>
</Space>
</Flex>
<ProgressBar size="small" progress={progress} error={errorText} />
</UploadContainer>
</Space>
) : (
<Space padding={[1.25, 1.5]}>
<DashedButton onPress={handleFilePick} activeOpacity={0.7}>
<Flex flexDirection="row">
<View>
<UploadCloud fill="primary.800" size="small" />
<Space margin={[0, 0, 0, 0.5]}>
<View>
<Text size="xsmall" weight="bold" color="primary.800" maxLines={1}>
{title}
</Text>
</View>
</Space>
</View>
</Flex>
</DashedButton>
</Space>
)}
</Flex>
</Size>
{errorText || helpText ? (
<Space margin={[0.5, 0, 0, 0]}>
<View>
<Text size="xsmall" color={errorText ? 'negative.900' : 'shade.950'}>
{errorText || helpText}
</Text>
</View>
</Space>
) : null}
</View>
</Size>
);
}