Closed wangchongwei closed 11 months ago
now, it is not fluent.
@wangchongwei when you press "low"/"high" buttons you don't need to use values from useKeyboardAnimation
hook. Can you provide a code example so that I can tell you more what needs to be changed?
/**
* test input
*/
import {useCallback, useEffect, useRef, useState} from 'react';
import {
FlatList,
ListRenderItemInfo,
Pressable,
StyleSheet,
Text,
TextInput,
View,
Keyboard,
} from 'react-native';
import {SafeAreaProvider} from 'react-native-safe-area-context';
import {useReanimatedKeyboardAnimation} from 'react-native-keyboard-controller';
import Animated, {useAnimatedStyle} from 'react-native-reanimated';
const TEXT =
'apple banana cat dog elephant fish goat horse igloo jacket kangaroo leaf moon noodles orange pineapple rabbit scarf telephone tree UFO volcano water x-ray yogurt zebra amazing beautiful clever delicious enormous fast funny gentle hungry intelligent jealousy kind lovely nervous noisy olympics polite quiet responsible sad talented ugly Vancouver Washington yesterday yourself';
type Item = {
text: string;
left: boolean;
};
const WORDS = TEXT.split(' ')
.map(v => v.trim())
.filter(v => v != null && v != '');
function genItems() {
const items: Item[] = [];
for (let i = 0; i < 20; i++) {
let s = '';
const count = Math.floor(Math.random() * 20 + 5);
for (let j = 0; j < count; j++) {
const index = Math.floor(Math.random() * WORDS.length);
s = s + ' ' + WORDS[index];
}
items.push({
text: s,
left: Math.random() < 0.5,
});
}
return items;
}
function Content() {
const [items, setItems] = useState<Item[]>(genItems());
const [inputText, setInputText] = useState('');
const [showLowView, setShowLowView] = useState(false);
const [showHightView, setShowHighView] = useState(false);
const {height} = useReanimatedKeyboardAnimation();
const [currentHeight, setCurrentHeight] = useState(0);
const [currentHighHeight, setCurrentHighHeight] = useState(0);
const refAnimatedView = useRef();
const send = useCallback(
(text: string) => {
const item: Item = {
text: text,
left: Math.random() < 0.5,
};
const values = [item];
values.push(...items);
setItems(values);
},
[items],
);
const renderItem = useCallback((item: ListRenderItemInfo<Item>) => {
return (
<View style={styles.itemWrapper}>
<View style={[styles.itemContainer, item.item.left ? styles.itemLeft : styles.itemRight]}>
<View style={styles.avatar}>
<Text style={styles.avatarText}>{item.index + 1}</Text>
</View>
<Text style={[styles.text, item.item.left ? styles.textRight : styles.textLeft]}>
{item.item.text}
</Text>
</View>
</View>
);
}, []);
useEffect(() => {
if (showLowView) {
setCurrentHeight(40);
setCurrentHighHeight(0);
} else if (showHightView) {
setCurrentHighHeight(400);
setCurrentHeight(0);
} else {
setCurrentHeight(0);
setCurrentHighHeight(0);
}
}, [height, showLowView, showHightView]);
console.log('height ====>', height.value);
const fakeView = useAnimatedStyle(
() => ({
height: Math.abs(height.value),
}),
[],
);
const showLow = () => {
Keyboard.dismiss();
setShowLowView(true);
setShowHighView(false);
};
const showHigh = () => {
Keyboard.dismiss();
setShowLowView(false);
setShowHighView(true);
};
return (
<View style={{flex: 1, backgroundColor: 'white'}}>
<FlatList data={items} renderItem={renderItem} style={styles.list} inverted />
<View style={styles.inputRow}>
<TextInput
style={styles.input}
multiline
onChangeText={setInputText}
value={inputText}
autoFocus={false}
onFocus={() => {
setShowHighView(false);
setShowLowView(false);
}}
/>
<Pressable
style={styles.send}
android_ripple={{color: '#DBDBDB88'}}
onPress={() => {
const text = inputText;
if (text && text.length) {
send(text);
setInputText('');
}
}}>
<Text style={styles.sendText}>SEND</Text>
</Pressable>
<Pressable
style={styles.send}
android_ripple={{color: '#DBDBDB88'}}
onPress={() => {
showLow();
}}>
<Text style={styles.sendText}>Low</Text>
</Pressable>
<Pressable
style={styles.send}
android_ripple={{color: '#DBDBDB88'}}
onPress={() => {
showHigh();
}}>
<Text style={styles.sendText}>High</Text>
</Pressable>
</View>
<Animated.View ref={refAnimatedView} style={fakeView} />
<Animated.View style={{backgroundColor: 'red', height: currentHeight}} />
<Animated.View style={{backgroundColor: 'green', height: currentHighHeight}} />
</View>
);
}
export default function TestKeyboard() {
return (
<SafeAreaProvider>
<Content />
</SafeAreaProvider>
);
}
const styles = StyleSheet.create({
list: {
flex: 1,
},
itemWrapper: {
padding: 4,
},
itemContainer: {
padding: 12,
backgroundColor: 'lightgrey',
borderRadius: 6,
},
itemLeft: {
flexDirection: 'row',
},
itemRight: {
flexDirection: 'row-reverse',
},
avatar: {
width: 80,
height: 80,
backgroundColor: 'grey',
borderRadius: 6,
alignItems: 'center',
justifyContent: 'center',
},
avatarText: {
color: 'white',
fontWeight: 'bold',
fontSize: 36,
},
text: {
fontSize: 18,
color: 'black',
textAlign: 'left',
textAlignVertical: 'top',
flex: 1,
},
textLeft: {
marginRight: 6,
},
textRight: {
marginLeft: 6,
},
inputRow: {
margin: 4,
gap: 4,
alignItems: 'center',
flexDirection: 'row',
},
send: {
width: 70,
height: 50,
backgroundColor: '#2196f3',
borderRadius: 6,
alignItems: 'center',
justifyContent: 'center',
},
sendText: {
textAlign: 'center',
textAlignVertical: 'center',
color: 'white',
},
input: {
flex: 1,
backgroundColor: 'white',
color: 'black',
borderWidth: 1,
borderColor: 'grey',
borderRadius: 4,
},
});
thanks a lot.
@wangchongwei and what is the desired output? Right now code works exactly like you described? Can you share a screenshot of what should happen when you press low/high buttons?
i hope like that. when i click the right button, bottom view will change. and i hope it is smoothly
Okay, I will look into the problem when I have a time:
But basically you'll need:
useDerivedValue
and switch between values from keyboard or your own value;withTiming
to make a transition between 2 states smooth.Yes, thanks again.
@wangchongwei here is a modified variant of your code:
import {useCallback, useEffect, useRef, useState} from 'react';
import {
FlatList,
ListRenderItemInfo,
Pressable,
StyleSheet,
Text,
TextInput,
View,
Keyboard,
} from 'react-native';
import {SafeAreaProvider} from 'react-native-safe-area-context';
import {KeyboardProvider, useReanimatedKeyboardAnimation} from 'react-native-keyboard-controller';
import Animated, {runOnJS, useAnimatedStyle, useDerivedValue, useSharedValue, withTiming} from 'react-native-reanimated';
const TEXT =
'apple banana cat dog elephant fish goat horse igloo jacket kangaroo leaf moon noodles orange pineapple rabbit scarf telephone tree UFO volcano water x-ray yogurt zebra amazing beautiful clever delicious enormous fast funny gentle hungry intelligent jealousy kind lovely nervous noisy olympics polite quiet responsible sad talented ugly Vancouver Washington yesterday yourself';
type Item = {
text: string;
left: boolean;
};
const WORDS = TEXT.split(' ')
.map(v => v.trim())
.filter(v => v != null && v != '');
function genItems() {
const items: Item[] = [];
for (let i = 0; i < 20; i++) {
let s = '';
const count = Math.floor(Math.random() * 20 + 5);
for (let j = 0; j < count; j++) {
const index = Math.floor(Math.random() * WORDS.length);
s = s + ' ' + WORDS[index];
}
items.push({
text: s,
left: Math.random() < 0.5,
});
}
return items;
}
function Content() {
const [items, setItems] = useState<Item[]>(genItems());
const [inputText, setInputText] = useState('');
const [showLowView, setShowLowView] = useState(false);
const [showHightView, setShowHighView] = useState(false);
const prevKeyboardHeight = useRef(0);
const keyboard = useReanimatedKeyboardAnimation();
const ownKeyboardHeight = useSharedValue(0);
const [currentHeight, setCurrentHeight] = useState(0);
const [currentHighHeight, setCurrentHighHeight] = useState(0);
const [showOwnKeyboard, setShowOwnKeyboard] = useState(false);
const height = useDerivedValue(() => showOwnKeyboard ? ownKeyboardHeight.value : keyboard.height.value);
const refAnimatedView = useRef();
const send = useCallback(
(text: string) => {
const item: Item = {
text: text,
left: Math.random() < 0.5,
};
const values = [item];
values.push(...items);
setItems(values);
},
[items],
);
const renderItem = useCallback((item: ListRenderItemInfo<Item>) => {
return (
<View style={styles.itemWrapper}>
<View style={[styles.itemContainer, item.item.left ? styles.itemLeft : styles.itemRight]}>
<View style={styles.avatar}>
<Text style={styles.avatarText}>{item.index + 1}</Text>
</View>
<Text style={[styles.text, item.item.left ? styles.textRight : styles.textLeft]}>
{item.item.text}
</Text>
</View>
</View>
);
}, []);
useEffect(() => {
if (showLowView) {
Keyboard.dismiss();
const currentKeyboardHeight = keyboard.height.value;
// save current keyboard size as a previous one - later will be re-used on back transitions
// our keyboard -> system keyboard
prevKeyboardHeight.current = currentKeyboardHeight;
// fit our keyboard view to match system keyboard layout
ownKeyboardHeight.value = currentKeyboardHeight;
// start smooth transition
ownKeyboardHeight.value = withTiming(currentKeyboardHeight - 40, { duration: 250 });
setShowOwnKeyboard(true);
// setCurrentHeight(40);
// setCurrentHighHeight(0);
} else if (showHightView) {
setCurrentHighHeight(400);
setCurrentHeight(0);
} else {
ownKeyboardHeight.value = withTiming(prevKeyboardHeight.current, { duration: 250 }, (finished) => {
// when layout is identical again - start to consume system keyboard layout metrics
runOnJS(setShowOwnKeyboard)(false);
});
setCurrentHeight(0);
setCurrentHighHeight(0);
}
}, [height, showLowView, showHightView]);
console.log('height ====>', height.value);
const fakeView = useAnimatedStyle(
() => ({
height: Math.abs(height.value),
}),
[],
);
const showLow = () => {
setShowLowView(true);
setShowHighView(false);
};
const showHigh = () => {
Keyboard.dismiss();
setShowLowView(false);
setShowHighView(true);
};
return (
<View style={{flex: 1, backgroundColor: 'white'}}>
<FlatList data={items} renderItem={renderItem} style={styles.list} inverted />
<View style={styles.inputRow}>
<TextInput
style={styles.input}
multiline
onChangeText={setInputText}
value={inputText}
autoFocus={false}
onFocus={() => {
setShowHighView(false);
setShowLowView(false);
}}
/>
<Pressable
style={styles.send}
android_ripple={{color: '#DBDBDB88'}}
onPress={() => {
const text = inputText;
if (text && text.length) {
send(text);
setInputText('');
}
}}>
<Text style={styles.sendText}>SEND</Text>
</Pressable>
<Pressable
style={styles.send}
android_ripple={{color: '#DBDBDB88'}}
onPress={() => {
showLow();
}}>
<Text style={styles.sendText}>Low</Text>
</Pressable>
<Pressable
style={styles.send}
android_ripple={{color: '#DBDBDB88'}}
onPress={() => {
showHigh();
}}>
<Text style={styles.sendText}>High</Text>
</Pressable>
</View>
<Animated.View ref={refAnimatedView} style={fakeView} />
<Animated.View style={{backgroundColor: 'red', height: currentHeight}} />
<Animated.View style={{backgroundColor: 'green', height: currentHighHeight}} />
</View>
);
}
export default function TestKeyboard() {
return (
<KeyboardProvider>
<SafeAreaProvider>
<Content />
</SafeAreaProvider>
</KeyboardProvider>
);
}
const styles = StyleSheet.create({
list: {
flex: 1,
},
itemWrapper: {
padding: 4,
},
itemContainer: {
padding: 12,
backgroundColor: 'lightgrey',
borderRadius: 6,
},
itemLeft: {
flexDirection: 'row',
},
itemRight: {
flexDirection: 'row-reverse',
},
avatar: {
width: 80,
height: 80,
backgroundColor: 'grey',
borderRadius: 6,
alignItems: 'center',
justifyContent: 'center',
},
avatarText: {
color: 'white',
fontWeight: 'bold',
fontSize: 36,
},
text: {
fontSize: 18,
color: 'black',
textAlign: 'left',
textAlignVertical: 'top',
flex: 1,
},
textLeft: {
marginRight: 6,
},
textRight: {
marginLeft: 6,
},
inputRow: {
margin: 4,
gap: 4,
alignItems: 'center',
flexDirection: 'row',
},
send: {
width: 70,
height: 50,
backgroundColor: '#2196f3',
borderRadius: 6,
alignItems: 'center',
justifyContent: 'center',
},
sendText: {
textAlign: 'center',
textAlignVertical: 'center',
color: 'white',
},
input: {
flex: 1,
backgroundColor: 'white',
color: 'black',
borderWidth: 1,
borderColor: 'grey',
borderRadius: 4,
},
});
Here is a demo how it works:
I modified only keyboard -> low transition. I hope you can get an idea of how it should be done and can add other transitions on your own 😎
I'm going to close the issue (I hope I answered the question). Feel free to open a new one if it's needed 🙌
https://github.com/kirillzyusko/react-native-keyboard-controller/assets/25812026/076e7879-1dc4-4286-aeba-eba0297f7510
the bottom need input emoji icon.
how can i change the botton view?
thank you!