android 电视盒下XBMC源码功能的简单分析
2012-10-08 15:43 Terry_龙 阅读(11374) 评论(6) 编辑 收藏 举报
由于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功能源码方面欢迎讨论。