由於XBMC一開始設計就是傾向於遙控輸入,自身的框架極其強大,容易擴展,用在電視盒上面剛好可以補充小公司在內容不足時的替代品。值得慶幸的是,XBMC的android 源碼也開源了,android 電視盒的開發者可以學習或者拿過來改造了。前一篇寫xbmc默認中文顯示的文章:點擊打開 。
XBMC官方網站:點擊打開 。
也可直接下載:
$ git clone git://github.com/xbmc/xbmc.git
XBMC的WIKI: 點擊打開 。
最近一直在負責xbmc 的擴展,大致對xbmc的結構比較清晰,今天不講結構目錄,網上大把。主講一些控件的使用的數據填充等。 大致會講到從一個界面的形成到界面上的元素的交互這方面,基本可以滿足一般開發者對現有XBMC簡單的界面擴展需要。
先上一張效果圖
1):界面的繼承
XBMC使用的是C++編寫的界面,所有眼睛能看到的界面都是繼承於CGUIWindow(Dialog 繼承於CGUIDialog),XBMC又分為不同的類別,比如音樂、視頻、圖片、天氣等,每個類別分別有一個Base界面繼承自CGUIWindow用來作為該類別的基類,比如視頻的基類為:CGUIWindowVideoBase,假如你要為視頻新增一個界面,那么可以繼承CGUIWindowVideoBase,實現這個類的一些虛承數即可,非常方便。
以我為視頻增加一個縮略圖展示界面的頁面為例,代碼為:
:CGUIWindowVideoBase(WINDOW_VIDEO_THUMBLIST,"MyVideoThumb.xml")
A. WINDOW_VIDEO_THUMBLIST定義在源碼里的:xbmc/guilib/Key.h ,代碼為:
這個常量用來代表這個界面,要使用這個界面可以直接使用,比如打開或者顯示該界面可以:
g_windowManager.ActivateWindow(WINDOW_VIDEO_THUMBLIST);
另外,想要讓XBMC認出這個界面還需要在xbmc/Application.cpp 初始化時添加進來,代碼塊位於:
……
g_windowManager.Add( new CGUIWindowVideoThumbList);
……
}
B.MyVideoThumb.xml這個文件代表界面元素,可以理解成android 的xml界面,但編寫方式和控件的排列方面都不相同,關於界面控件的排布齋在第2點詳細說明。到此為止,一個新的界面就算是完成了,下面說說如何在xml上畫界面。
注意:需要在Makefile文件將你新增的文件寫進去,以便編譯時能夠順利編進去。
2):界面元素
XBMC所支持的控件列表:點擊打開 。
默認界面存放於android/addons/skin.confluence/720p目錄,這里面包含了所有界面的XML,對應的素材包括:聲音、字體、語言文字、圖片、顏色等也一並在android/addons/skin.confluence此目錄,最后生成build.bat文件。
注意:一些經常用的或者通用的布局,可以寫在Includes.xml文件里面,以后有需要用到的可以直接寫在你需要的xml上,比如:
以一個panel的控件的XML為例,代碼如下:
<control type="group">
< control type ="panel" id ="8000" >類型panel,id為8000
< posx >180 </ posx > 位於界面x 軸為180
< posy >20 </ posy > 位於界面y軸為20
< width >1160 </ width > panel 的寬度的1160
< height >590 </ height > panel 的高度為590
< onleft >9000 </ onleft > 遙控按向左鍵時如果焦點還在panel里面,並且己經是最左邊一個元素時,將焦點切換到ID為9000的控件上
< onright >60 </ onright > 遙控按向右鍵時如果焦點還在panel里面,並且己經是最右邊一個元素時,將焦點切換到ID為60的控件上
< onup >1000 </ onup > 遙控按向上鍵時如果焦點還在panel里面,並且己經是最頂一個元素時,將焦點切換到ID為1000的控件上
< ondown >1000 </ ondown > 遙控按向下鍵時如果焦點還在panel里面,並且己經是最底一個元素時,將焦點切換到ID為1000的控件上
< viewtype label ="21371" >list </ viewtype > 顯示類型為列表
< pagecontrol >60 </ pagecontrol > 與下面 scrollbar綁定,作為該panel的滾動控件
< scrolltime tween ="sine" easing ="out" >200 </ scrolltime >拖動延時
< preloaditems >2 </ preloaditems >預加載項目2
元素默認時的控件高度200寬度220,該薦包括一個默認無獲得焦點的image(圖片)和未獲得含焦點的label(文字)
<itemlayout height="200" width="220">
<control type="image"> 類型image
<posx>1</posx> 位於panel里面的位置是x 軸1
<posy>0</posy>位於panel 里面的位置 是y軸0
<width>180</width>image寬度180
<height>160</height> image高度160
<aspectratio>scale</aspectratio>不論圖片大小填充整個圖片的寬高.keep 為保持圖片的大小不拉伸。更多請 點擊 。
<bordertexture border="5">folder-nofocus.png</bordertexture>image邊框紋理圖片
<bordersize>5</bordersize>邊框大小
<texture background="true">$INFO[Listitem.Icon]</texture>image圖片,ListItem.Icon為獲取CFileItemPtr里面的數據,后文會介紹
</control>
<control type="label">類型label
<posx>88</posx>位於panel里面的位置是x 軸88
<posy>160</posy>位於panel 里面的位置 是y軸160
<width>180</width>label寬度為180
<height>25</height>label高度為25
<font>font50caps_title</font> 文體類型,該字體定義於:xml同級目錄的Font.xml里面,也可以自行設置filename與size
<textcolor>white</textcolor>文體顏色
<selectedcolor>selected</selectedcolor>選中時顏色
<align>center</align>位於itemLayout的中間x方向
<aligny>center</aligny>位於itemLayout的中間y方向
<info>ListItem.Label</info>顯示信息同樣獲取自CFileitemPtr,也可自行指定
</control>
</itemlayout>
元素獲得焦點時的控件高度200寬度250,該薦包括一個默認無獲得焦點的image(圖片)和未獲得含焦點的label(文字)
<focusedlayout height="200" width="250">
<control type="image">
<posx>1</posx>
<posy>0</posy>
<width>180</width>
<height>160</height>
<aspectratio>scale</aspectratio>
<bordertexture border="5">folder-focus.png</bordertexture> 獲取焦點時的圖片
<bordersize>5</bordersize>
<texture background="true">$INFO[Listitem.Icon]</texture>
</control>
<control type="label">
<posx>88</posx>
<posy>160</posy>
<width>180</width>
<height>25</height>
<font>font50caps_title</font>
<textcolor>white</textcolor>
<selectedcolor>selected</selectedcolor>
<align>center</align>
<aligny>center</aligny>
<info>ListItem.Label</info>
</control>
</focusedlayout>
</control>
<control type="scrollbar" id="60">滾動條
<posx>1250</posx>
<posy>20</posy>
<width>25</width>
<height>590</height>
<onleft>8000</onleft>
<onright>9000</onright>
<texturesliderbackground border="0,14,0,14">ScrollBarV.png</texturesliderbackground>
<texturesliderbar border="2,16,2,16">ScrollBarV_bar.png</texturesliderbar>
<texturesliderbarfocus border="2,16,2,16">ScrollBarV_bar_focus.png</texturesliderbarfocus>
<textureslidernib>ScrollBarNib.png</textureslidernib>
<textureslidernibfocus>ScrollBarNib.png</textureslidernibfocus>
<onleft>500</onleft>
<onright>2</onright>
<showonepage>false</showonepage>
<orientation>vertical</orientation>方向
</control>
</control>
3):界面需要實現的幾個虛函數
頭文件代碼為:
#include " ThumbLoader.h "
#include " GUIWindowVideoNav.h "
class CGUIWindowVideoThumbList : public CGUIWindowVideoBase
{
public:
CGUIWindowVideoThumbList( void);
virtual ~CGUIWindowVideoThumbList( void);
virtual bool OnAction( const CAction &action);動作回調函數,不怎么用到
virtual bool OnMessage(CGUIMessage& message);消息回調函數,處理界面元素的點擊消息,有點像android 的handler消息機制
virtual bool Update( const CStdString &strDirectory);當界面完成一個更新或者顯示一開始顯示時調用
void LoadItemByDirectory( const CStdString &strDirectory);
void LoadItemByDirectory( const CFileItemList &items);
protected:
virtual void OnInitWindow();初始化
virtual void OnWindowLoaded();加載完畢后
int GetWindowSeletectedItem( int iControl);
CFileItemList* m_vecItems;
CFileItemList* itemList;
bool load_done;
CFileItemList* page_index_list;
CStdString previous_path;
CStdString next_path;
int pageIndex;
};
以上幾個有添加注釋為必須實現函數,XBMC界面控制也基本在這幾個回調函數里面進行。
4): 數據的加載或者填充
普通的控件如Button、Label之類的加載文字,可以直接使用預定義好的全局方法SET_CONTROL_LABEL(controlID,label)來做。
而列表加載需要做一個類型List的數據給CGUIMessage,代碼為:
// if(!load_done){
CFileItemList list;
GetDirectory( " plugin://plugin.video.XuZhiTV ",list);通過獲取目錄得到python插件的數據目錄
itemList->Clear();
for( int i= 0;i<list.Size();i++){循環填充進itemList
CFileItemPtr pItem = list.Get(i);
if(strcmp(pItem->GetLabel().c_str(), " .. ")== 0)
continue;
CFileItemPtr cateItem( new CFileItem(pItem->GetLabel()));
cateItem->SetPath(pItem->GetPath());
itemList->Add(cateItem);
}
通過消息將列表廣播出去,加載列表
CGUIMessage msg(GUI_MSG_LABEL_BIND, GetID(), CONTROL_LOAD_CATEGORY_LIST_ID, 0, 0, itemList);
g_windowManager.SendMessage(msg);
//--------------------end------------------------
//-------------item list---------------------------
CFileItemList firstList;
GetDirectory(itemList->Get(0)->GetPath(),firstList);得到插件目錄的子目錄
//-------------------end-----------------------
/* load_done=true;
*/
LoadItemByDirectory(firstList); 加載子項
//}
return true;
}
LoadItemByDirectory方法代碼:
m_vecItems->Clear();
page_index_list->Clear();
for ( int i= 0;i<items.Size(); ++i)
{
CFileItemPtr pItem = items.Get(i);
if(strcmp(pItem->GetLabel().c_str(), " .. ")== 0)
continue;
CFileItemPtr item( new CFileItem(pItem->GetLabel()));
item->SetThumbnailImage(pItem->GetThumbnailImage());獲取網絡上的圖片給上面panel 的image
item->SetPath(pItem->GetPath());
if(pItem->GetLabel().Find( " | ")> 0){
item->SetIntParam(- 1);
CFileItemPtr ptr( new CFileItem(pItem->GetLabel())); 獲取label給上面panel 的label
ptr->SetPath(pItem->GetPath());
page_index_list->Add(ptr);
continue;
} else{
item->SetIntParam( 0);
}
item->SetIconImage( " DefaultVideoCover.png ");
item->SetLabelPreformated( true);
m_vecItems->Add(item);
}廣播消息加載內容
CGUIMessage refresh(GUI_MSG_LABEL_BIND, GetID(), CONTROL_LOAD_ITEM_LIST_ID, 0, 0, m_vecItems);
bool isRefresh= g_windowManager.SendMessage(refresh);
if(isRefresh){
int m_size=page_index_list[ 0].Size();
CFileItemPtr ptr=page_index_list[ 0].Get( 0);
if(m_size== 0){
SET_CONTROL_HIDDEN(CONTROL_NEXT_ID);
SET_CONTROL_HIDDEN(CONTROL_PREVIOUSE_ID);
SET_CONTROL_LABEL(CONTROL_PAGE_COUNT_ID, "");
} else{
SET_CONTROL_LABEL(CONTROL_PAGE_COUNT_ID,ptr->GetLabel().Right( 6));
SET_CONTROL_VISIBLE(CONTROL_NEXT_ID);
SET_CONTROL_VISIBLE(CONTROL_PREVIOUSE_ID);
}
switch(m_size){
case 0:
previous_path= "";
next_path= "";
break;
case 1:{
CStdString control_text=ptr->GetLabel().Left(ptr->GetLabel().Find( " | "));
if(strcmp(control_text, " down ")== 0){
next_path=ptr->GetPath();
} else{
previous_path=ptr->GetPath();
}
}
break;
case 2:
previous_path=ptr->GetPath();
next_path=page_index_list[ 0].Get( 1)->GetPath();
break;
}
}
}
5):點擊事件的處理
點擊事件可以重寫onclick,也可以由OnMessage函數處理,都可以。處理非常簡單代碼為:
{
if (message.GetMessage() == GUI_MSG_CLICKED)消息類型為點擊時,message不止可以處理點擊,還有很多事件可以處理。
{
int iControl = message.GetSenderId();獲得點擊控件的ID
if(iControl == 2000){ID等於2000時
//處理點擊時響 應的代碼
}
}
return CGUIWindowVideoBase::OnMessage(message);
}
更多關於XBMC功能源碼方面歡迎討論。
