容器層的使用
GUI 控件我們大致可以分爲兩類,**普通控件** 和 容器控件,普通控件指的是一些常用的控件,如 UIButton,UILabel,UISlider 和 UITextField 等控件,而容器控件如 UILayout,UIScrollView,UIListView,UIPageView 等,這些容器控件都有一個特點,它可以作爲容器,包含其它控件,雖然所有的控件都能夠包含其它控件,但有些控件的職責非常單一,如按鈕標籤等,並不經常向其添加其它控件。以下詳細介紹容器控件的使用方法。
UILayout (Panel)
Panel 作爲最主要的容器層,前面我們說過,由 CocoStudio UI 編輯器所創建的 UI 是基於 Panel 來佈局的,要想熟練的使用 UI 控件,瞭解 Panel 以及其屬性也是重中之重,既然是容器,容器裏面總得有些內容了,Panel 對應得控件名稱爲 UILayout。
Size widgetSize = m_pWidget->getSize();
UILayout *background = dynamic_cast<UILayout*>(m_pUiLayer->getWidgetByName("background_Panel"));
// Create the layout
UILayout* layout = UILayout::create();
layout->setSize(Size(280, 150));
Size backgroundSize = background->getSize();
layout->setPosition(Point((widgetSize.width - backgroundSize.width) / 2 +
(backgroundSize.width - layout->getSize().width) / 2,
(widgetSize.height - backgroundSize.height) / 2 +
(backgroundSize.height - layout->getSize().height) / 2));
m_pUiLayer->addWidget(layout);
UIButton* button = UIButton::create();
button->setTouchEnabled(true);
button->loadTextures("cocosgui/animationbuttonnormal.png", "cocosgui/animationbuttonpressed.png", "");
button->setPosition(Point(button->getSize().width / 2, layout->getSize().height - button->getSize().height / 2));
layout->addChild(button);
UIButton* textButton = UIButton::create();
textButton->setTouchEnabled(true);
textButton->loadTextures("cocosgui/backtotopnormal.png", "cocosgui/backtotoppressed.png", "");
textButton->setTitleText("Text Button");
textButton->setPosition(Point(layout->getSize().width / 2, layout->getSize().height / 2));
layout->addChild(textButton);
UIButton* button_scale9 = UIButton::create();
button_scale9->setTouchEnabled(true);
button_scale9->loadTextures("cocosgui/button.png", "cocosgui/buttonHighlighted.png", "");
button_scale9->setScale9Enabled(true);
button_scale9->setSize(Size(100, button_scale9->getContentSize().height));
button_scale9->setPosition(Point(layout->getSize().width - button_scale9->getSize().width / 2, button_scale9->getSize().height / 2));
layout->addChild(button_scale9);
如上面代碼所示,我們創建了一個 layout
控件,然後在其中添加了三個控件。m_pUiLayer
是當前場景的一個
UILayer ,前面我們介紹過,所有的 UI 控件,都是放在 UILayer 裏面,UILayer 管理所有的控件,並添加到當前場景中去。顯示效果如下:
我們設置了 layout 的 size 屬性,也就是給它一個大小,但是並沒有顯示出來效果,默認是透明的,我們可以爲這個層設置顏色:
layout->setBackGroundColorType(LAYOUT_COLOR_SOLID);
layout->setBackGroundColor(Color3B(128, 128, 128));
除了設置純色之外,還可以設計漸變顏色:
layout->setBackGroundColorType(LAYOUT_COLOR_GRADIENT);
layout->setBackGroundColor(Color3B(64, 64, 64), Color3B(192, 192, 192));
當然,除了設置顏色之外,還可以設置我們想要的背景圖片:
layout->setSize(Size(280, 150));
layout->setClippingEnabled(true);
layout->setBackGroundImage("cocosgui/Hello.png");
如上圖顯示,我們設置了 size 並且設置了 背景圖片,但是不要忘了調用 setClippingEnabled
方法根據
size 進行裁剪,如果忘了調用,那麼會向下面所顯示的一樣。
除了以上使用方式,還有其它玩法:
layout->setBackGroundImageScale9Enabled(true);
layout->setBackGroundImage("cocosgui/green_edit.png");
使用九宮格圖片做爲背景,注意啓用此功能。
UILayout 顯示顏色的模式有三種
LayoutBackGroundColorType | 說明 |
---|---|
LAYOUT_COLOR_NONE | 透明,沒有顏色顯示 |
LAYOUT_COLOR_SOLID | 實體,可以設置顏色 |
LAYOUT_COLOR_GRADIENT | 漸變顏色 |
UIPanel 控件的佈局方案
UILayout 是作爲佈局之用,以上都只是修改背景圖片,下面除了手動擺放座標位置的絕對定位,還提供了哪些佈局方案呢。
LayoutType | 說明 |
---|---|
LAYOUT_ABSOLUTE | 絕對佈局 |
LAYOUT_LINEAR_VERTICAL | 垂直平鋪 |
LAYOUT_LINEAR_HORIZONTAL | 橫向平鋪 |
LAYOUT_RELATIVE | 相對佈局 |
layout->setLayoutType(LAYOUT_LINEAR_VERTICAL);
// 或者
layout->setLayoutType(LAYOUT_LINEAR_HORIZONTAL);
// 或者
layout->setLayoutType(LAYOUT_RELATIVE);
注意:除了絕對定位之外,如果設置了其它佈局方案,那麼 UIPanel 會忽略其內部控件本身設置的位置。而此時可以使用提供的 UILayoutParameter
來設置位置關係,根據佈局方案提供了幾種佈局參數, UILinearLayoutParameter
和 UIRelativeLayoutParameter
。下面介紹如何實用佈局參數來配合佈局設計界面顯示效果。
layout->setLayoutType(LAYOUT_LINEAR_VERTICAL);
// .... 省略控件創建代碼,同前文控件一樣
UILinearLayoutParameter* lp1 = UILinearLayoutParameter::create();
lp1->setGravity(LINEAR_GRAVITY_CENTER_HORIZONTAL);
lp1->setMargin(UIMargin(0, 10, 0, 10));
UILinearLayoutParameter* lp2 = UILinearLayoutParameter::create();
lp2->setGravity(LINEAR_GRAVITY_CENTER_HORIZONTAL);
lp2->setMargin(UIMargin(20, 20, 0, 5));
UILinearLayoutParameter* lp3 = UILinearLayoutParameter::create();
lp3->setGravity(LINEAR_GRAVITY_CENTER_HORIZONTAL);
lp3->setMargin(UIMargin(0, 10, 0, 10));
button->setLayoutParameter(lp1);
textButton->setLayoutParameter(lp2);
button_scale9->setLayoutParameter(lp3);
顯示效果如下:
我們看到,分別創建了三個佈局參數 UILinearLayoutParameter
,設置了 Gravity
和 Margin
參數,然後給三個
UIPanel 的內部控件分別設置其佈局參數值,已達到如上效果。
這裏使用的方案是垂直平鋪,而每個佈局參數設置的 Gravity
值爲 LINEAR_GRAVITY_CENTER_HORIZONTAL
,也就是說水平劇中顯示,而
Margin 則標示控件四周邊緣的間距,注意以上的 lp2
的值爲 UIMargin(20,
20, 0, 5)
,其代表含義,距離左、上、右、下的間距。左值爲 20,可以看見 textButton
相對中間位置向右便宜少數。這是垂直佈局,而水平佈局除了方向不一,基本使用方式同垂直佈局同樣。兩者也都叫 線性佈局,使用同樣的線性佈局參數。下面再看看相對佈局:
layout->setLayoutType(LAYOUT_RELATIVE);
// 此處省略控件的創建步驟 ...
UIRelativeLayoutParameter* rp1 = UIRelativeLayoutParameter::create();
rp1->setAlign(RELATIVE_ALIGN_PARENT_TOP_RIGHT);
UIRelativeLayoutParameter* rp2 = UIRelativeLayoutParameter::create();
rp2->setAlign(RELATIVE_ALIGN_PARENT_LEFT_CENTER_VERTICAL);
UIRelativeLayoutParameter* rp3 = UIRelativeLayoutParameter::create();
rp3->setAlign(RELATIVE_ALIGN_PARENT_RIGHT_BOTTOM);
button->setLayoutParameter(rp1);
textButton->setLayoutParameter(rp2);
button_scale9->setLayoutParameter(rp3);
這裏創建了三個佈局屬性,設置了不同的 "停靠" 參數 Align
。
UIScrollView 滾動視圖
除了佈局容器,我們常用的還有滾動層容器,它可以擴大我們的顯示控件,當內容元素很多時,尤爲有用。可以設置爲兩個方向,橫向或者是豎向。
UIScrollView* scrollView = UIScrollView::create();
scrollView->setTouchEnabled(true);
scrollView->setSize(Size(280, 150));
Size backgroundSize = background->getContentSize();
scrollView->setPosition(Point((widgetSize.width - backgroundSize.width) / 2 +
(backgroundSize.width - scrollView->getSize().width) / 2,
(widgetSize.height - backgroundSize.height) / 2 +
(backgroundSize.height - scrollView->getSize().height) / 2));
m_pUiLayer->addWidget(scrollView);
UIImageView* imageView = UIImageView::create();
imageView->loadTexture("cocosgui/ccicon.png");
float innerWidth = scrollView->getSize().width;
float innerHeight = scrollView->getSize().height + imageView->getSize().height;
scrollView->setInnerContainerSize(Size(innerWidth, innerHeight));
imageView->setPosition(Point(innerWidth / 2, imageView->getSize().height / 2));
scrollView->addChild(imageView);
// 爲 scrollview 添加其它控件,省略
請看如圖效果,這裏創建了一個 ScrollView 控件,並且添加了一些內部元素,以完成佈局,控件內容超出顯示區域,我們可以通過上下拖動,來顯示上下未未顯示的不分。
注意: imageView 設置的位置在 scrollview 之外,可以通過 scrollview 的 setInnerContainerSize 方法設置包含內容的區域大小,在拖動的過程中,邊界檢查。
如果是設置橫向的拖動效果,我們只需要設置 InnerContainerSize 的 寬度大於控件的大小,高度相同,就能實現橫向的拖動效果。
UIListView
ListView 繼承自 ScrollView,所以 ScrollView 裏面有的功能,特性,在 ListView 中也都能體現出來。那麼 ListView 相比較 ScrollView 多了些什麼呢?還是先從使用方法上開始:
UIListView* lv = UIListView::create();
UIButton* model = UIButton::create();
model->loadTextures("cocosgui/animationbuttonnormal.png", "cocosgui/animationbuttonpressed.png", "");
lv->setItemModel(model);
for (int i=0; i<20; i++)
{
lv->pushBackDefaultItem();
}
lv->setItemsMargin(10);
lv->setGravity(LISTVIEW_GRAVITY_CENTER_HORIZONTAL);
lv->setSize(Size(100, 100));
lv->setBackGroundColorType(LAYOUT_COLOR_SOLID);
lv->setBackGroundColor(Color3B::GREEN);
lv->setPosition(Point(100, 100));
m_pUiLayer->addWidget(lv);
如圖,但不能很好的看到效果,這裏是類似 ScrollView 的實現,可以實現拖動,並且有二十個按鈕在這其中。先說說普通的屬性,通過 ItemsMargin
設置每個元素的間距,
通過 Gravity
設置佈局方案,這裏是橫向劇中顯示。
lv->setItemModel(model)
爲
ListView 設置了默認的項 (Default Item),然後通過一個 for 循環,添加了 20 次此默認的項,注意這 20 次並不是說, model 被添加了 20 次,二十在每次添加的時候都對 model 做了一個 克隆,它們擁有相同的屬性,但卻不是同一個對象。
除了使用 pushBackDefaultItem()
爲
ListView 添加項之外,我們還可以通過以下方法添加:
方法 | 說明 |
---|---|
pushBackDefaultItem() | 添加一個默認項 |
insertDefaultItem(int index) | 插入一個默認項,有序的 |
pushBackCustomItem(UIWidget* item) | 添加一個新項 |
insertCustomItem(UIWidget* item, int index) | 插入一個新項 |
以上是提供的一些添加項的方法,除了以上還有一些刪除的方法,獲取的方法,以便我們能夠靈活的操作其中的每個元素:
方法 | 說明 |
---|---|
removeItem(int index) | 移除一個項 |
removeLastItem() | 移除最後一個項 |
getItem(unsigned int index) | 根據索引獲取一個項 |
getItems() | 獲取所有項,返回 Array 集合 |
getIndex(UIWidget *item) | 獲取一個項的索引 |
UIPageView
除了可以滾動顯示的 ScrollView , 根據項來顯示列表的控件之外,還有可以根據 頁 來顯示 PageView。 PageVew 可以讓我們整頁整頁的顯示內容,並且可以做自動對齊,什麼是自動對齊,就像你的書翻頁,只翻了一半,它回自動幫你翻過去一樣。
UIPageView* pageView = UIPageView::create();
pageView->setTouchEnabled(true);
pageView->setSize(Size(240, 130));
Size backgroundSize = background->getContentSize();
pageView->setPosition(Point((widgetSize.width - backgroundSize.width) / 2 +
(backgroundSize.width - pageView->getSize().width) / 2,
(widgetSize.height - backgroundSize.height) / 2 +
(backgroundSize.height - pageView->getSize().height) / 2));
for (int i = 0; i < 3; ++i)
{
UILayout* layout = UILayout::create();
layout->setSize(Size(240, 130));
UIImageView* imageView = UIImageView::create();
imageView->setTouchEnabled(true);
imageView->setScale9Enabled(true);
imageView->loadTexture("cocosgui/scrollviewbg.png");
imageView->setSize(Size(240, 130));
imageView->setPosition(Point(layout->getSize().width / 2, layout->getSize().height / 2));
layout->addChild(imageView);
UILabel* label = UILabel::create();
label->setText(CCString::createWithFormat("page %d", (i + 1))->getCString());
label->setFontName(font_UIPageViewTest);
label->setFontSize(30);
label->setColor(Color3B(192, 192, 192));
label->setPosition(Point(layout->getSize().width / 2, layout->getSize().height / 2));
layout->addChild(label);
pageView->addPage(layout);
}
pageView->addEventListenerPageView(this, pagevieweventselector(UIPageViewTest::pageViewEvent));
m_pUiLayer->addWidget(pageView);
如圖顯示,創建了一個 PageView 對象 pageView,設置大小爲 "Size(240, 130)",這也就是它的顯示區域大小了。我們使用一個 for 循環,添加了三個同樣的元素 UILayout ,每個 UILayout 的大小也都是 Size(240,
130)
,所以 PageView 一次正好能夠顯示一個項的內容,也就是 "頁"。至於每個頁的 UILayout 裏面裝着什麼,那就是根據自己的需要而定了。然後使用 pageView->addPage(layout)
添加一個頁,需要注意的是,這裏所添加的必須是 UILayout
類型對象或者其派生類對象。
PageView 雖然實現了滑動,滾動的效果,但它並不是繼承自 ScrollView 的,而是直接繼承自 UILayout 的,那怎麼實現滾動的呢,它集成並且實現了 UIScrollInterface
類型,這賦予了它可以滾動的屬性。ScrollView
也是同樣。
各個控件組成了豐富的 GUI 界面,而容器層則是其骨架,通過它的佈局,來達到我們想要的效果。從 Panel 到 ScrollView ,Listview 和 PageView ,根據實際的需要靈活的組織可以讓我們的界面顯示的更爲友好。