cocos2dx[2.x](2)--菜單按鈕CCMenu/CCMenuItem

【嘮叨】
菜單按鈕在遊戲中是經常被用到的,比如主菜單界面的菜單選項,暫停遊戲時的菜單選項等等。cocos2dx引擎同樣爲我們提供了CCMenu菜單的功能,幷包含了一些簡單的菜單項CCMenuItem。且菜單項附帶觸碰按鈕時,自動放大的效果。
溫馨提示:本節內容比較多,需要大家慢慢分析,不要急於求成。
本節組織結構如下:
一、介紹CCMenu。
二、介紹CCMenuItem,及其具體的六個子類。
三、代碼實戰。

【Demo下載】
https://github.com/shahdza/Cocos_LearningTest/tree/master/demo_%E8%8F%9C%E5%8D%95CCMenu%E3%80%81CCMenuItem

【3.x】
(1)去掉“CC”
(2)其他函數的增加與刪除稍微做了變化,可以自己在開發過程中掌握。

【菜單CCMenu】
菜單CCMenu是專門用來承載菜單按鈕的CCLayer圖層,圖層中的子節點只能夠是菜單項CCMenuItem或其子類。通常先創建菜單項CCMenuItem,然後使用一個或多個菜單項生成菜單CCMenu,最後把CCMenu加入當前CCLayer圖層。
繼承關係如下:
這裏寫圖片描述

如果直接在層中添加CCMenuItem也可以正常顯示,但是無法響應回調函數,因爲CCMenu是繼承至CCLayer,也就繼承了觸摸的相關事件,而CCMenuItem只是從CCNode繼承而來,並不響應觸摸,因此無法調用回調函數。
由於CCMenu的父類爲CCLayer,所以錨點爲(0,0),且無法設置錨點。CCMenu的默認原點座標爲屏幕正中心(winSize.width/2, winSize.height/2)。
而對於CCMenuItem是添加在CCMenu層中的,所以CCMenuItem的位置是相對於CCMenu層的偏移位置。CCMenuItem相對於CCMenu的偏移量默認爲(0,0),且菜單項的錨點默認爲(0.5,0.5)。

如下圖所示:

這裏寫圖片描述這裏寫圖片描述

值得注意的是:CCMenu包含了多個子菜單項,每個子菜單項的位置都不一樣,如果定義了CCMenu的位置,那它作爲父節點會影響到所有的子菜單項的位置,所以一般我們都是吧CCMenu的位置設置在CCPointZero,然後設置CCMenuItem的位置(也就是相對父節點的偏移量)來定位整個菜單。

常用操作如下:
class CC_DLL CCMenu : public CCLayerRGBA
{
/**
 *     創建菜單的三個常用方法
 */
    //創建一個空菜單
    static CCMenu* create();

    //CCMenu::create(item1,item2,item3,NULL);
    //用CCMenuItem菜單項創建菜單,最後以NULL表示結束.
    static CCMenu* create(CCMenuItem* item, ...);

    //用一個包含CCMenuItem的CCArray數組來創建菜單
    static CCMenu* createWithArray(CCArray* pArrayOfItems);


/**
 *     菜單佈局方式
 *     注意:使用以下函數進行菜單佈局時,將會把整體菜單項的相對於CCMenu的偏移座標設置到(0,0)。
 *             所以佈局後,應該設置CCMenu菜單的座標爲屏幕正中心(winSize.width/2, winSize.height/2),效果更加。
 *     alignItemsVertically , alignItemsHorizontally , 
 *     alignItemsInColumns , alignItemsInRows
 */
    //讓menu的所有item豎着佈局
    //item1
    //item2
    //item3
    void alignItemsVertically(); //默認間隙:5個像素
    void alignItemsVerticallyWithPadding(float padding); //相連兩個item間隔爲padding


    //讓menu的所有item橫着佈局
    //item1  item2    item3
    void alignItemsHorizontally(); //默認間隙:5個像素
    void alignItemsHorizontallyWithPadding(float padding); //相連兩個item間隔爲padding


    //將items進行分組,然後按列(columns)進行排列
    //每一組在同一行,參數columns表示每一組的菜單項個數,並以NULL表示結束。
    //alignItemsInColumns(3,2,1,NULL);
    //item1 item2 item3
    //  item4 item5
    //      item6
    void alignItemsInColumns(unsigned int columns, ...);


    //將items進行分組,然後按行(rows)進行排列。與上述類似。
    //alignItemsInRows(3,2,1,NULL);
    //item1
    //          item4
    //item2                 item6
    //          item5
    //item3
    void alignItemsInRows(unsigned int rows, ...);


/**
 *     添加、刪除item菜單項
 *     addChild , removeChild
 */
    virtual void addChild(CCNode * child);
    virtual void addChild(CCNode * child, int zOrder);
    virtual void addChild(CCNode * child, int zOrder, int tag);
    virtual void removeChild(CCNode* child, bool cleanup);


/**
 *     設置菜單是否可用
 *     setEnabled
 */
    virtual void setEnabled(bool value) { m_bEnabled = value; };
    virtual bool isEnabled() { return m_bEnabled; }
};

【菜單項CCMenuItem】
CCMenuItem繼承自CCNode,所以它的子類菜單項都可以使用CCNode的相關操作。
CCMenuItem是所有菜單項的父類,建議不要直接使用該類,因爲它並不包含具體顯示的功能。
作爲其它菜單項的父類,主要提供了一下三個功能:
(1)提供了基本按鈕的狀態:正常、選中、禁用。
(2)爲按鈕實現了基本的回調函數機制。當玩家點積按鈕後,就會調用執行相應的回調函數。
(3)觸碰菜單項,附有自動放大效果。

菜單項的子類可以分成三類,總共六個:
    (1)文字菜單項:CCMenuItemLabel、CCMenuItemAtlasFont、CCMenuItemFont;
    (2)圖片菜單項:CCMenuItemSprite、CCMenuItemImage;
    (3)切換菜單項:CCMenuItemToggle。
繼承關係如下圖所示:

這裏寫圖片描述

1、CCMenuItemLabel
CCMenuItemLabel是一個包含了文字標籤的菜單項按鈕,CCLabel的三個標籤CCLabelBMFont ,CCLabelAtlas,CCLabelTTF對象,都可以放置在該按鈕對象中。
常用操作如下:

class CC_DLL CCMenuItemLabel : public CCMenuItem
{
/**
 *     創建CCMenuItemLabel
 *     支持字體標籤類:CCLabelBMFont , CCLabelAtlas , CCLabelTTF 
 */
    //用label字體標籤創建,不設置回調響應事件。
    //label可以是CCLabelBMFont , CCLabelAtlas , CCLabelTTF三種文字標籤。
    static CCMenuItemLabel* create(CCNode *label);

    //用label字體標籤創建,並設置回調響應事件。
    //      target:執行當前按鈕的對象,一般爲this。表示由CCLayer圖層執行回調響應事件。
    //      selector:使用菜單回調函數menu_selector。一般在當前CCLayer圖層中定義。
    //create( label, this , menu_selector( HelloWorld::func1 ) );
    static CCMenuItemLabel * create(CCNode*label, CCObject* target, SEL_MenuHandler selector);


/**
 *     屬性設置
 *     setString , setEnabled , setDisabledColor , setLabel
 */
    //設置內部字體標籤(CCLabel)的顯示文字內容
    void setString(const char * label);

    //設置該CCMenuItemLabel對象是否可用
    virtual void setEnabled(bool enabled);
    virtual bool isSelected();

    //禁用時的顏色
    virtual void setDisabledColor(ccColor3B&);
    virtual const ccColor3B& getDisabledColor();

    //被渲染的字體,可以是CCLabelBMFont , CCLabelAtlas , CCLabelTTF。
    virtual void setLabel(CCNode*);
    virtual CCNode* getLabel();
};

2、CCMenuItemAtlasFont
CCMenuItemAtlasFont的父類爲CCMenuItemLabel。
和父類的區別在於:該類在創建時,只要設置顯示內容、使用的字體資源.png即可。它默認使用CCLabelAtlas來創建文字標籤的菜單項按鈕。而省去了父類創建label的步驟。
該類和父類相比,並未做其他屬性或函數的擴展。
常用操作如下:

class CC_DLL CCMenuItemFont : public CCMenuItemLabel
{
/**
 *     創建CCMenuItemFont
 */
    //創建基於CCLabelAtlas字體標籤的CCMenuItemAtlasFont,不帶回調響應事件。
    //create("20140818" , "digit.png" , 20 , 20 , '0' );
    //create("20140818" , "digit.png" , 20 , 20 , '0' , this , menu_selector( HelloWorld::func2 ) );
    static CCMenuItemAtlasFont* create(const char *value, const char *charMapFile, int itemWidth, int itemHeight, char startCharMap);
    static CCMenuItemAtlasFont* create(const char *value, const char *charMapFile, int itemWidth, int itemHeight, char startCharMap, CCObject* target, SEL_MenuHandler selector);
};

3、CCMenuItemFont
CCMenuItemAtlasFont的父類爲CCMenuItemLabel。
和父類的區別在於:該類在創建時,只要設置顯示內容即可。它默認使用CCLabelTTF來創建文字標籤的菜單項按鈕。而省去了父類創建label的步驟。
和父類相比,可以設置字體大小。

常用操作如下:
class CC_DLL CCMenuItemFont : public CCMenuItemLabel
{
/**
 *     創建CCMenuItemFont
 */
    //create(要顯示的字符串)
    //create(要顯示的字符串,執行當前按鈕的對象,回調函數)
    //      target:執行當前按鈕的對象,一般爲this。表示由CCLayer圖層執行回調響應事件。
    //      selector:使用菜單回調函數menu_selector。一般在當前CCLayer圖層中定義。
    //create( "hello" , this , menu_selector( HelloWorld::func3 ) );
    static CCMenuItemFont * create(const char *value);
    static CCMenuItemFont * create(const char *value, CCObject* target, SEL_MenuHandler selector);


/**
 *     屬性設置
 */
    //這是一個全局靜態方法,用來設置新創建CCMenuItemFont時的默認字體大小的
    //在不進行設置時,創建的CCMenuItemFont,默認大小爲32。
    //CCMenuItemFont::setFontSize(32);
    static void setFontSize(unsigned int s);
    static unsigned int fontSize();

    //這是一個全局靜態方法,用來設置新創建CCMenuItemFont時的默認字體資源.fnt的
    //在不進行設置時,創建的CCMenuItemFont,默認字體爲"Marker Felt"。
    //CCMenuItemFont::setFontName("Arial");
    static void setFontName(const char *name);
    static const char *fontName();

    //設置該對象的字體大小及使用的字體資源名.fnt
    void setFontSizeObj(unsigned int s);
    unsigned int fontSizeObj();
    void setFontNameObj(const char* name);
    const char* fontNameObj();
};

4、CCMenuItemSprite
CCMenuItemSprite是一個由精靈對象組成的菜單按鈕。
此類的內部屬性提供了三個精靈對象,分別表示按鈕的三個狀態:正常、選中、禁用。每種狀態都分別對應了一個精靈圖片。
精靈是引擎中最爲豐富和自由的元素,因此類CCMenuItemSprite算得上是將精靈和按鈕功能的結合體。

常用操作如下:
class CC_DLL CCMenuItemSprite : public CCMenuItem
{
/**
 *     創建CCMenuItemSprite
 */
    //參數:
    //      normalSprite:  正常時的默認精靈normalSprite
    //      selectedSprite:被選中時的精靈selectedSprite
    //      disabledSprite:禁用時的精靈disabledSprite
    //      target:執行當前按鈕的對象,一般爲this。表示由CCLayer圖層執行回調響應事件。
    //      selector:使用菜單回調函數menu_selector。一般在當前CCLayer圖層中定義。
    //CCSprite* normalSprite = CCSprite::create("sp1.png");
    //CCSprite* selectedSprite = CCSprite::create("sp2.png");
    //CCSprite* disabledSprite = CCSprite::create("sp3.png");
    //create(normalSprite, selectedSprite, disabledSprite, this, menu_selector(HelloWorld::func4) );
    static CCMenuItemSprite * create(CCNode* normalSprite, CCNode* selectedSprite, CCNode* disabledSprite = NULL);
    static CCMenuItemSprite * create(CCNode* normalSprite, CCNode* selectedSprite, CCObject* target, SEL_MenuHandler selector);
    static CCMenuItemSprite * create(CCNode* normalSprite, CCNode* selectedSprite, CCNode* disabledSprite, CCObject* target, SEL_MenuHandler selector);


/**
 *     設置三種狀態的精靈CCSprite
 */
    //正常時的默認圖片normalSprite
    //被選中時的圖片selectedSprite
    //禁用時的圖片disabledSprite
    virtual void setNormalImage(CCNode* normalSprite);
    virtual CCNode* getNormalImage();
    virtual void setSelectedImage(CCNode* selectedSprite);
    virtual CCNode* getSelectedImage();
    virtual void setDisabledImage(CCNode* disabledSprite);
    virtual CCNode* getDisabledImage();


/**
 *     設置選中、禁用
 */
    virtual void selected(); //選中
    virtual void unselected(); //取消選中
    virtual void setEnabled(bool bEnabled); //是否啓用。false禁用。
};

5、CCMenuItemImage
CCMenuItemImage繼承自CCMenuItemSprite,並沒有太大的變化。只是提供了更爲簡捷的方式,將原本按鈕中的精靈對象換爲了三張紋理圖片。無需創建精靈對象,就可以直接創建一個精靈按鈕對象。
與父類相比,省去了創建CCSprite精靈對象的過程。實際上在create創建的過程中,已經幫你做了創建CCSprite的過程了。

常用操作如下:
class CC_DLL CCMenuItemImage : public CCMenuItemSprite
{
/**
 *     創建CCMenuItemImage
 */
    //與CCMenuItemSprite創建方式差不多。就是參數變成了圖片資源(如*.png)
    //create("sp1.png", "sp2.png", "sp3.png", this, menu_selector(HelloWorld::func5) );
    static CCMenuItemImage* create(const char *normalImage, const char *selectedImage);
    static CCMenuItemImage* create(const char *normalImage, const char *selectedImage, const char *disabledImage);
    static CCMenuItemImage* create(const char *normalImage, const char *selectedImage, CCObject* target, SEL_MenuHandler selector);
    static CCMenuItemImage* create(const char *normalImage, const char *selectedImage, const char *disabledImage, CCObject* target, SEL_MenuHandler selector);

/**
 *     屬性設置
 */
    //用CCSpriteFrame精靈幀,設置正常時的精靈幀Normal
    void setNormalSpriteFrame(CCSpriteFrame* frame);
    //用CCSpriteFrame精靈幀,設置選中時的精靈幀Selected
    void setSelectedSpriteFrame(CCSpriteFrame* frame);
    //用CCSpriteFrame精靈幀,設置禁用時的精靈幀Disabled
    void setDisabledSpriteFrame(CCSpriteFrame* frame);
};

6、CCMenuItemToggle
CCMenuItemToggle是比較特殊的。它在內部擁有一個CCMenuItem菜單項數組,用來負責展示不同的菜單項按鈕狀態。因爲使用了一個菜單按鈕的數組,所以此類的對象可以實現狀態的切換。此類是一個菜單項按鈕對象的集合,能夠包含很多的菜單項按鈕狀態,方便開發者進行切換。
例如,CCMenuItemToggle可以用來做開關按鈕。

常用操作如下:
class CC_DLL CCMenuItemToggle : public CCMenuItem
{
/**
 *     創建CCMenuItemToggle
 *     create 或 createWithTarget
 */
    //使用一個菜單項創建CCMenuItemToggle對象
    //CCMenuItemFont* item = CCMenuItemFont::create("hello");
    //CCMenuItemToggle::create(item);
    static CCMenuItemToggle* create(CCMenuItem *item);

    //使用菜單項參數列表創建,以NULL結束列表
    //item1 = CCMenuItemFont::create("hello");
    //item2 = CCSprite::create("sp1.png"):
    //createWithTarget(this, menu_selector(HelloWorld::func6), item1, item2, NULL);
    static CCMenuItemToggle* createWithTarget(CCObject* target, SEL_MenuHandler selector, CCMenuItem* item, ...);  

    //使用包含菜單項的數組創建
    //createWithTarget(this, menu_selector(HelloWorld::func6), pArray);
    static CCMenuItemToggle * createWithTarget(CCObject* target, SEL_MenuHandler selector, CCArray* menuItems);


/**
 *     菜單項數組集合相關
 *     setSelectedIndex , selectedItem ,
 *     setSubItems , addSubItem
 */
    //設置當前選中的CCMenuItem的索引值(即數組下標)
    virtual void setSelectedIndex(unsigned int );
    virtual unsigned int getSelectedIndex();

    //返回當前選中的菜單項
    CCMenuItem* selectedItem(); 

    //設置CCMenuItem菜單項數組集合
    virtual void setSubItems(CCArray* );
    virtual CCArray* getSubItems();

    //添加新的子菜單項
    void addSubItem(CCMenuItem *item); 
};

【代碼實戰】
首先,在實戰的過程中會遇到有關回調函數的概念,這裏就簡單來說一下什麼事回調函數。
回調函數其實就是:當按鈕被觸碰時,會執行相應的函數。類似於鼠標點擊綁定的click響應事件處理函數。

1、在HelloWorldScene.h中添加如下兩個回調函數

    //添加回調響應函數
    void menuItemFont2Func(CCObject* sender); //更改標籤內容
    void menuItemToggleFunc(CCObject* sender); //更改狀態:正常,選中,禁用

2、編寫測試代碼

    bool HelloWorld::init()
    {
        if ( !CCLayer::init() )
        {
            return false;
        }

    //獲取可視區域尺寸大小
        CCSize mysize = CCDirector::sharedDirector()->getVisibleSize();
    //獲取可視區域的原點位置
        CCPoint origin = CCDirector::sharedDirector()->getVisibleOrigin();
    //屏幕正中心位置
        CCPoint midPos = ccp(mysize.width/2, mysize.height/2);



    /*
     * 創建CCMenuItemLabel
     *     使用CCLabelTTF創建
     */
        CCLabelTTF* lb1 = CCLabelTTF::create("aaaaaa", "Arial", 32);
        CCMenuItemLabel* menuItemLabel = CCMenuItemLabel::create(lb1);
        //設置位置
        menuItemLabel->setPosition( ccp(120, mysize.height-50) ); 

    /*
     * 創建CCMenuItemAtlasFont
     *     創建方式與CCLabelAtlas類似
     */
        CCMenuItemAtlasFont* menuItemAtlas = CCMenuItemAtlasFont::create("20140818", "fonts/digit.png", 20, 20, '0');
        menuItemAtlas->setPosition( ccp(120, mysize.height-120) );


    /*
     * 創建CCMenuItemFont
     *     創建了兩個,有無附帶回調響應函數
     */
        //設置CCMenuItemFont創建時的默認字體大小
        CCMenuItemFont::setFontSize(50);

        //不帶回調響應函數,tag編號爲1
        CCMenuItemFont* menuItemFont1 = CCMenuItemFont::create("11111");
        menuItemFont1->setTag(1);

        //觸碰後,執行回調函數menuItemFont2Func。更改menuItemFont1的內容
        CCMenuItemFont* menuItemFont2 = CCMenuItemFont::create("Change1", this, menu_selector(HelloWorld::menuItemFont2Func) ); //回調

        menuItemFont2->setFontSizeObj(32); //設置字體大小
        menuItemFont1->setPosition( ccp(120, mysize.height-190) ); //設置位置
        menuItemFont2->setPosition( ccp(120, mysize.height-260) ); //設置位置


    /*
     * 創建CCMenu,tag編號爲100
     *     菜單項menuItemLabel, menuItemAtlas, menuItemFont1, menuItemFont2
     */
        CCMenu* menu = CCMenu::create(menuItemLabel, menuItemAtlas, menuItemFont1, menuItemFont2, NULL);

        //設置位置爲(0,0),與HelloWorld層重合
        menu->setPosition(CCPointZero); 

        //將CCMenu菜單添加到CCLayer中, tag編號爲100
        this->addChild(menu, 0, 100); 


    /*
     * 創建CCMenuItemSprite
     *     參數爲CCSprite精靈
     */
        CCSprite* sp1 = CCSprite::create("sp1.png");
        CCSprite* sp2 = CCSprite::create("sp2.png");
        CCSprite* sp3 = CCSprite::create("sp3.png");
        CCMenuItemSprite* menuItemSprite = CCMenuItemSprite::create(sp1, sp2, sp3 );

        menuItemSprite->setPosition( ccp(mysize.width/2 + 50, mysize.height/2 + 50) );
        menu->addChild(menuItemSprite); //添加到菜單層中
        menuItemSprite->setTag(2); //tag編號爲2

    /*
     * 創建CCMenuItemImage
     *     參數變成紋理圖片png
     */
        //使用CCMenuItemImage創建一個關閉程序的菜單項按鈕
        CCMenuItemImage* menuItemImage = CCMenuItemImage::create("CloseNormal.png", "CloseSelected.png", this, menu_selector(HelloWorld::menuCloseCallback) ); //回調
        menuItemImage->setPosition( ccp(mysize.width - 40, mysize.height - 40) );
        menu->addChild(menuItemImage); //添加到菜單層中


    /*
     * 創建CCMenuItemToggle
     *     參數爲CCMenuItem子類
     */
        CCMenuItemFont::setFontSize(20);
        CCMenuItemFont* menuItemFont3 = CCMenuItemFont::create("Toggle_Normal");
        CCMenuItemFont* menuItemFont4 = CCMenuItemFont::create("Toggle_Selected");
        CCMenuItemImage* menuItemImage2 = CCMenuItemImage::create("sp3.png", "sp1.png");

        //創建CCMenuItemToggle,回調函數:更改menuItemSprite的狀態。
        CCMenuItemToggle* menuItemToggle = CCMenuItemToggle::createWithTarget(this, menu_selector(HelloWorld::menuItemToggleFunc), 
                                                                                    menuItemFont3, menuItemFont4, NULL ); //菜單項參數列表
        menuItemToggle->setPosition( ccp(mysize.width/2 + 50, mysize.height/2 - 50) ); //設置位置

        //將menuItemImage2添加到menuItemToggle中
        menuItemToggle->addSubItem(menuItemImage2);

        menu->addChild(menuItemToggle); //添加到菜單層中


        return true;
    }

3、編寫回調響應函數的代碼

 /*
     *     回調函數menuItemFont2Func
     */

    //變化menuItemFont1的內容
    void HelloWorld::menuItemFont2Func(CCObject* sender)
    {

    //獲取menuItemFont2
        CCMenuItemFont* menuItemFont2 = (CCMenuItemFont*)sender;

    //從CCLayer中獲取CCMenu菜單
        CCMenu* menu = (CCMenu*)this->getChildByTag(100);

    //獲取menuItemFont1,其tag爲1
        //!!!注意!!!
        //      tag是相對父節點而言的:this的子節點中沒有tag爲1,而menuItemFont1是menu中tag爲1的子節點。
        CCMenuItemFont* menuItemFont1 = (CCMenuItemFont*)menu->getChildByTag(1);


    //更改menuItemFont1的內容
        //獲取menuItemFont2顯示的標籤內容
        CCLabelTTF* lb = (CCLabelTTF*)menuItemFont2->getLabel();

        //strcmp判斷是否等於Change1
        if( strcmp( lb->getString() , "Change1") == 0 ) { 
            lb->setString("Change2");
            menuItemFont1->setString("22222");
        }else {
            lb->setString("Change1");
            menuItemFont1->setString("11111");
        }
    }


    /*
     *     回調函數menuItemToggleFunc
     */

    //更改狀態:正常,選中,禁用
    void HelloWorld::menuItemToggleFunc(CCObject* sender)
    {

    //獲取menuItemToggle
        CCMenuItemToggle* menuItemToggle = (CCMenuItemToggle*)sender;

    //從CCLayer中獲取CCMenu菜單
        CCMenu* menu = (CCMenu*)this->getChildByTag(100);

    //獲取menuItemSprite
        CCMenuItemSprite* menuItemSprite = (CCMenuItemSprite*)menu->getChildByTag(2);


    //根據menuItemToggle當前被選中的是哪一項,來設置menuItemSprite的狀態
        switch( menuItemToggle->getSelectedIndex() ) {
            case 0: //正常
                menuItemSprite->setEnabled(true);
                break;
            case 1: //選中
                menuItemSprite->selected();
                break;
            case 2: //禁用
                menuItemSprite->setEnabled(false);
                break;
        }
    }

4、運行結果截圖
這裏寫圖片描述
點擊Change1按鈕,執行回調函數menuItemFont2Func。“11111”變成“22222”。
這裏寫圖片描述
點擊“Toggle_Normal”按鈕,精靈圖片變成選中時的圖片。
這裏寫圖片描述
再次點擊“Toggle_Selected”按鈕,精靈圖片變成禁用時的圖片。
這裏寫圖片描述

轉載網址:http://blog.51cto.com/shahdza/1541815

發佈了7 篇原創文章 · 獲贊 1 · 訪問量 7426
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章