React Native實現(xiàn)京東下拉菜單

2019-8-3 更新成了TS版本的

我將項目升級成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)}
/>

注意下層級牙瓢,如果是多個的話框全,這個要放在上面哦

首先看看效果

示例.gif

基本思路

看動圖我們可以發(fā)現(xiàn)筐付,組件是由三部分組成的皂吮,一個是標題部分样眠,也就是用來點擊的地方贬养,一個是彈出來的那一塊昼捍,還以及一個遮罩層识虚。

標題部分

這部分是很簡單,就是一個文本和一個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'
                }
            ]}
        >
            {/* 結果的展示 */}
            {selectItems.length === 0 ? data.title : this.split(itemNames) + '(' + selectItems.length + ')'}
        </Text>
    </View>
</ZlTouchable>

在使用TouchableOpacity的時候妒茬,需要考慮到一個情況就是舷礼,用戶可能會快速的點擊,從而出現(xiàn)一些異辰即常現(xià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的時間可以延長,根據需要改變
            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;

這樣的話育拨,我們就可以解決用戶快速點擊的問題了谨履。

彈出菜單

這里的彈出菜單,我是這么想的熬丧,拿到數(shù)據后呢笋粟,先把菜單生成出來,放在標題部分的上面析蝴,高度話害捕,用父組件傳遞進來。這樣的話闷畸,就得這么寫了

    /**
     * 說明:生成下拉菜單
     * @author tangbin
     * @date 2019/3/29
     * @time 11:04
     */
    renderActivityPanel = () => {

        // 得到數(shù)據
        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>
        );
    };

把我們的選項用ScrollView包裹起來尝盼,這樣就能滾動了,然后佑菩,用動畫組件把整改菜單給包裹進去盾沫,并且在動畫組件設置相應的樣式,比如top要設置成負數(shù)殿漠,zIndex也要設置對應的等級赴精,然后我們就可設置相應的動畫了

動畫

首先,我們要設置點擊菜單的動畫

    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();
    };

然后呢渐苏,設置關閉的動畫

    // 關閉動畫
    closePanel = () => {
        const { rotationAnim } = this.state;
        this.isShowCouver = false;
        rotationAnim.setValue(1);
        // 這里只執(zhí)行彈窗的動畫,是因為遮罩層組件在切換的時候菇夸,已經被卸載了
        Animated.spring(
            rotationAnim,
            {
                toValue: 0,
                duration: 300,
                useNativeDriver: true // <-- 加上這一行
            }
        ).start();
    };

關閉動畫要把打開的動畫少一點琼富,因為遮罩層在關閉的時候,已經沒有了庄新,所以是不需要的鞠眉。

完整代碼看地址:
https://github.com/Tzng/React-Component/tree/master/react-native/ActionBar

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市择诈,隨后出現(xiàn)的幾起案子械蹋,更是在濱河造成了極大的恐慌,老刑警劉巖羞芍,帶你破解...
    沈念sama閱讀 211,290評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件哗戈,死亡現(xiàn)場離奇詭異,居然都是意外死亡荷科,警方通過查閱死者的電腦和手機唯咬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評論 2 385
  • 文/潘曉璐 我一進店門纱注,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人胆胰,你說我怎么就攤上這事狞贱。” “怎么了蜀涨?”我有些...
    開封第一講書人閱讀 156,872評論 0 347
  • 文/不壞的土叔 我叫張陵瞎嬉,是天一觀的道長。 經常有香客問我厚柳,道長氧枣,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,415評論 1 283
  • 正文 為了忘掉前任别垮,我火速辦了婚禮便监,結果婚禮上,老公的妹妹穿的比我還像新娘宰闰。我一直安慰自己茬贵,他們只是感情好簿透,可當我...
    茶點故事閱讀 65,453評論 6 385
  • 文/花漫 我一把揭開白布移袍。 她就那樣靜靜地躺著,像睡著了一般老充。 火紅的嫁衣襯著肌膚如雪葡盗。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,784評論 1 290
  • 那天啡浊,我揣著相機與錄音觅够,去河邊找鬼。 笑死巷嚣,一個胖子當著我的面吹牛喘先,可吹牛的內容都是我干的。 我是一名探鬼主播廷粒,決...
    沈念sama閱讀 38,927評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼窘拯,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了坝茎?” 一聲冷哼從身側響起涤姊,我...
    開封第一講書人閱讀 37,691評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎嗤放,沒想到半個月后思喊,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 44,137評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡次酌,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,472評論 2 326
  • 正文 我和宋清朗相戀三年恨课,在試婚紗的時候發(fā)現(xiàn)自己被綠了舆乔。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,622評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡庄呈,死狀恐怖蜕煌,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情诬留,我是刑警寧澤斜纪,帶...
    沈念sama閱讀 34,289評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站文兑,受9級特大地震影響盒刚,放射性物質發(fā)生泄漏。R本人自食惡果不足惜绿贞,卻給世界環(huán)境...
    茶點故事閱讀 39,887評論 3 312
  • 文/蒙蒙 一因块、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧籍铁,春花似錦涡上、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至增显,卻和暖如春雁佳,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背同云。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工糖权, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人炸站。 一個月前我還...
    沈念sama閱讀 46,316評論 2 360
  • 正文 我出身青樓星澳,卻偏偏與公主長得像,于是被迫代替她去往敵國和親旱易。 傳聞我的和親對象是個殘疾皇子禁偎,可洞房花燭夜當晚...
    茶點故事閱讀 43,490評論 2 348

推薦閱讀更多精彩內容

  • 發(fā)現(xiàn) 關注 消息 iOS 第三方庫、插件咒唆、知名博客總結 作者大灰狼的小綿羊哥哥關注 2017.06.26 09:4...
    肇東周閱讀 12,059評論 4 62
  • 文|阿魚魚_Ayuyu 37 誤會 我愣了一下届垫,忽然想到——剛才拿著刀從扶蘇帳中沖出來,毫不猶豫追到密林全释,又毫不猶...
    劉瑜_Demi閱讀 288評論 0 0
  • 20180429—20180506 本周八天 以后按周一到周日做檢視 1686踐行第五周檢視 【一装处,愛非堅持?...
    雨黎兒0730閱讀 239評論 0 0
  • 姓名:張獻忠 日精進打卡第360天 【打卡始于2016.11.01持續(xù)于2017.10.26】 【知~學...
    張獻忠閱讀 176評論 0 0
  • 我喜歡世界上的各種美食,但是我對面條并不十分感興趣,不過在特別的情況下也有例外妄迁。 就在前天寝蹈,和同事閑談時,我說就在...
    道形圖閱讀 598評論 2 7