2019-8-3 更新成了TS版本的
我將項(xiàng)目升級成TS版本了,可以看這里
https://github.com/Tzng/React-Component/tree/master/react-native/ActionsBarTs
具體的用法是這樣的:
<ActionBarItem
bannerAction={flag => this.changeBar(flag, 'aaa')}
isActive={activeBar === 'aaa'}
data={deplist}
themeColor={theme.themeColor}
handleSubmit={(data, type) => this.onSelectSubmit(data, 'aaa', type)}
/>
注意下層級,如果是多個的話,這個要放在上面哦
首先看看效果

基本思路
看動圖我們可以發(fā)現(xiàn),組件是由三部分組成的,一個是標(biāo)題部分,也就是用來點(diǎn)擊的地方,一個是彈出來的那一塊,還以及一個遮罩層。
標(biāo)題部分
這部分是很簡單,就是一個文本和一個Icon
<ZlTouchable
onPress={this.openOrClosePanel}
style={{
flex: 1,
height: 40,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: themeColor
}}
>
<View
style={{
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
}}
>
<Text
style={[
styles.title_style,
{
color: '#fff'
}
]}
>
{/* 結(jié)果的展示 */}
{selectItems.length === 0 ? data.title : this.split(itemNames) + '(' + selectItems.length + ')'}
</Text>
</View>
</ZlTouchable>
在使用TouchableOpacity的時候,需要考慮到一個情況就是,用戶可能會快速的點(diǎn)擊,從而出現(xiàn)一些異?,F(xiàn)象,所以要對點(diǎn)擊事件進(jìn)行點(diǎn)擊間隔限制操作,所以這里是用的一個自己寫的ZlTouchable組件來完成的
代碼:
import React from 'react';
import { TouchableOpacity } from 'react-native';
class ZlTouchable extends React.Component<any> {
constructor(props) {
super(props);
this.lastClickTime = 0;
}
onPress() {
const { onPress } = this.props;
const clickTime = Date.now();
if (!this.lastClickTime || Math.abs(this.lastClickTime - clickTime) > 300) { // 350的時間可以延長,根據(jù)需要改變
this.lastClickTime = clickTime;
if (onPress) {
onPress();
} else {
return '';
}
}
return '';
}
render() {
const { activeOpacity, style, disabled, children } = this.props;
return (
<TouchableOpacity
onPress={() => this.onPress()}
activeOpacity={activeOpacity || 0.85}
style={style}
disabled={disabled}
>
{children}
</TouchableOpacity>);
}
}
export default ZlTouchable;
這樣的話,我們就可以解決用戶快速點(diǎn)擊的問題了。
彈出菜單
這里的彈出菜單,我是這么想的,拿到數(shù)據(jù)后呢,先把菜單生成出來,放在標(biāo)題部分的上面,高度話,用父組件傳遞進(jìn)來。這樣的話,就得這么寫了
/**
* 說明:生成下拉菜單
* @author tangbin
* @date 2019/3/29
* @time 11:04
*/
renderActivityPanel = () => {
// 得到數(shù)據(jù)
const { data: { items } } = this.props;
// 得到最大高度
const { maxHeight, themeColor } = this.props;
const { rotationAnim } = this.state;
return (
<View
style={{
position: 'absolute',
left: 0,
right: 0,
top: 38, // 決定了彈窗距離頂部的距離
bottom: 0
}}
>
<Animated.View
style={{
position: 'absolute',
left: 0,
right: 0,
top: -(maxHeight + 50),
width,
zIndex: 20,
transform: [
{ translateY: rotationAnim.interpolate({
inputRange: [0, 1],
outputRange: [0, maxHeight + 50]
}) },
]
}}
>
<View style={{ height: maxHeight }}>
<ScrollView
style={{
position: 'absolute',
top: 0,
bottom: 0,
left: 0,
right: 0,
backgroundColor: 'white',
}}
>
{items.map(item => (
<ZlTouchable
key={item.id}
style={{ flex: 1, height: 39 }}
onPress={() => this.itemOnPress(item)}
>
{this.renderChcek(item, themeColor)}
</ZlTouchable>
))}
</ScrollView>
</View>
<View
style={{
flex: 1,
flexDirection: 'row',
justifyContent: 'space-between'
}}
>
<ZlTouchable style={styles.cancel_button} onPress={this.openOrClosePanel}>
<View style={styles.button_text_view}>
<Text style={styles.cancel_button_text}>取消</Text>
</View>
</ZlTouchable>
<ZlTouchable style={styles.warning_button} onPress={this.handleSubmit}>
<View style={styles.button_text_view}>
<Text style={styles.warning_button_text}>確定</Text>
</View>
</ZlTouchable>
</View>
<View style={GlobalStyles.line} />
</Animated.View>
</View>
);
};
把我們的選項(xiàng)用ScrollView包裹起來,這樣就能滾動了,然后,用動畫組件把整改菜單給包裹進(jìn)去,并且在動畫組件設(shè)置相應(yīng)的樣式,比如top要設(shè)置成負(fù)數(shù),zIndex也要設(shè)置對應(yīng)的等級,然后我們就可設(shè)置相應(yīng)的動畫了
動畫
首先,我們要設(shè)置點(diǎn)擊菜單的動畫
openPanel = () => {
const { rotationAnim, fadeAnim } = this.state;
this.isShowCouver = true;
rotationAnim.setValue(0);
Animated.parallel([
// 使用寬松函數(shù)讓數(shù)值隨時間動起來。
Animated.spring( // 隨時間變化而執(zhí)行動畫
rotationAnim, // 動畫中的變量值
{
toValue: 1, // 透明度最終變?yōu)?,即完全不透明
duration: 300, // 讓動畫持續(xù)一段時間
useNativeDriver: true // <-- 加上這一行
}
),
// 使用寬松函數(shù)讓數(shù)值隨時間動起來。
Animated.spring( // 隨時間變化而執(zhí)行動畫
fadeAnim, // 動畫中的變量值
{
toValue: 0.5, // 透明度最終變?yōu)?,即完全不透明
duration: 300, // 讓動畫持續(xù)一段時間
useNativeDriver: true // <-- 加上這一行
}
)
]).start();
};
然后呢,設(shè)置關(guān)閉的動畫
// 關(guān)閉動畫
closePanel = () => {
const { rotationAnim } = this.state;
this.isShowCouver = false;
rotationAnim.setValue(1);
// 這里只執(zhí)行彈窗的動畫,是因?yàn)檎谡謱咏M件在切換的時候,已經(jīng)被卸載了
Animated.spring(
rotationAnim,
{
toValue: 0,
duration: 300,
useNativeDriver: true // <-- 加上這一行
}
).start();
};
關(guān)閉動畫要把打開的動畫少一點(diǎn),因?yàn)檎谡謱釉陉P(guān)閉的時候,已經(jīng)沒有了,所以是不需要的。
完整代碼看地址:
https://github.com/Tzng/React-Component/tree/master/react-native/ActionBar