前幾天開始寫仿Win8 Metro界面文章,部分網友以爲不錯,感謝各位的意見。原本今天一直在折騰Android VLC播放器,沒時間寫。不過明天休息,因此今天就抽時間先寫一下。html
言歸正傳,咱們都知道Win8的Metro界面只要手指一劃,頁面就跟着滑動(準確來講是按鈕跟着滑動,背景其實沒動),這個操做目前的Android和iPhone都是這種操做,我的感受都是從iPhone借鑑來,滑動切換很早就有,不過按鈕和壁紙分開滑動,這個仍是iPhone時代開始。ide
(這效果圖是截了幾張圖弄的,因此看上去不流暢)函數
類邏輯關係圖佈局
一、界面邏輯層次post
開始說滑動前,先要解析一下屏幕顯示的原理。咱們都知道屏幕最後呈現出來的畫面,其實都是顯存的數據,這個只有一份。也就是說最後用戶看到的都是隻有一張畫面。若是你只是單純按鈕滑動,而背景不滑動,給人感受是一個二維動畫。動畫
沒錯,邏輯上的確是二維的,咱們在顯示邏輯上能夠劃分多個邏輯層,最後組合成一個顯示畫面。url
例以下面的結構體:spa
我這裏區分了三個邏輯層設計
一、背景層指針
二、按鈕層
三、時間控件層
這三個層次在邏輯上是分開的,最後須要顯示的時候,才須要把他們組合起來,把畫面繪畫到兼容DC上,兼容DC再拷貝到屏幕DC上。這樣才完成一次畫面輸出。這個有點想PhotoShop的圖層,一張圖片,由多個圖層疊加完成。用過PS的人,應該很容易理解。
爲了實現兩個頁面滑動切換,我增長了一個Page類,(界面類之間關係,能夠查看上一篇文章)用來管理每一個頁面的按鈕,下面列出Page類的類聲明。
//只支持2行
#define ROW_NUM 2
//識別操做
#define DEL_BTN 0x10
#define ADD_BTN 0x11
#define SWITCH_BTN 0x12
class CDUIPage:public CDUIBase { public: CDUIPage(void); ~CDUIPage(void); public: //保存界面按鈕的二維容器
vector<vector<CDUIButton *> > m_pVUICtrlContent; //保存界面按鈕位置二維容器
vector<vector<CPoint> > m_pVUICtrlPos; //標記是否按鈕滑動 //BOOL m_slideBtn; //標記是否滑動頁面 //BOOL m_enterMouseMove; //點擊了按鈕
BOOL m_ClickBtn; //按下點擊點
CPoint m_ClickDownPoint; //內存DC,保存滑動時候背景
CDC m_BackDC;//記錄有多少方塊(目前只支持兩行)
int m_BlockNum[2]; //點擊的是大按鈕仍是小按鈕,大按鈕爲True
BOOL m_BigBlock; //點擊第幾行按鈕
int m_BlockLine; //點擊第幾個按鈕
int m_BlockClickNum; //刪除區域
CRect m_rcMainInterfaceDel;
//...............
public:
//初始化一個頁面
void InitPage(CDC * pDC, HWND MainWnd); //畫圖
void Draw(CDC * pDC); //響應窗口OnLButtonDown
BOOL OnLButtonDown(POINT point); //響應窗口OnLButtonUp
void OnLButtonUp(POINT point); //響應窗口OnMouseMove
int OnMouseMove(POINT point, CDC * pDC, CDC * pBackDC); //處理按鈕移動交換
int OnLButtonUpDeal(int Page, POINT point); //添加新的按鈕
void AddItem(CDUIButton * btn, int lineNum); //從新計算按鈕位置
void ReloadBtnPos(); //設置偏移量
void SetOffsetPoint(int point);//插入項
void InsertItem(CDUIButton * btn, int lineNum, int Pos);//按鈕排序//刪除釋放空按鈕
void ReleaseBtn(int Line, int index); //............... };
從上面定義能夠看出,這個Page類,其實主要做用就是管理Button類的,定義了一個二維向量容易,對應界面的二維佈局,由於我那裏界面屏幕分辨率相對比較固定。因此最多隻能放兩排按鈕,因此最上面我定義了多少行如今。不過二維向量理論上沒有限制多少行多少列。也就是說建立的全部CDUIButton對象都會被添加到二維向量裏面,下面是添加的操做:
void CDUIPage::AddItem(CDUIButton * btn, int lineNum) { ASSERT(btn != NULL); m_pVUICtrlContent.at(lineNum).push_back(btn); //從新計算按鈕位置
ReloadBtnPos(); }
lineNum表示是第幾行的按鈕,添加傲二維向量容器後,會根據按鈕大小,計算出這個按鈕的位置。按鈕的位置都是動態排布的,因此沒有按鈕滑動的時候顯示區域是動態變化的。其實這個就是把屏幕劃分爲一個二維格子,有點像棋盤,每一個按鈕就是一個棋子,放到對應的格子上面。只是Metro界面棋子大小不同,須要作些特殊處理,其中一種棋子佔用了兩個格子。其實這種設計思惟在如今的Android界面上也一樣如此,Android的Launcher就是按照一個個格子來放按鈕和widget。至於iPhone,沒看過源碼,不敢肯定。不敢按照它界面排布,多半也是相似的思想。
二、按鈕繪畫
按鈕繪畫的時候,是調用的Page的Draw函數,來繪畫。咱們看看Draw函數內容:
void CDUIPage::Draw(CDC * pDC) { //把原來的背景DC拷貝到控件內部DC
m_BackDC.BitBlt(0,0,ScreenWidth,ScreenHeight, pDC, 0, 0, SRCCOPY); for (int outer=0; outer<ROW_NUM; outer++) { int vectorNum = m_pVUICtrlContent.at(outer).size(); for (int k=0; k<vectorNum; k++) { m_pVUICtrlContent.at(outer).at(k)->Draw(pDC); } } }
Draw的代碼其實很簡單,就是調用了Page裏面每一個DUIButton的Draw函數,也就是說Page自己並無提供繪畫的功能,真正繪畫顯示按鈕,是DUIButton類的功能。
DUIButton類繪畫的功能也很簡單,就是顯示一張按鈕的PNG圖片。Draw(CDC * pDC)裏面的DC指針其實就是指向內存兼容DC的指針。。目前能夠理解爲把全部按鈕繪畫到內存兼容DC上,而這個內容兼容DC其實已經繪畫好了背景(這是我在上一層Container實現的內,這個後面會講)。
三、界面滑動實現
界面滑動,就是兩個Page對象之間的切換。下面是onMouseMove的執行代碼:
int CDUIPage::OnMouseMove(POINT point, CDC * pDC, CDC * pBackDC) { for (int outer=0; outer<ROW_NUM; outer++) { int vectorNum = m_pVUICtrlContent.at(outer).size(); for (int k=0; k<vectorNum; k++) { m_pVUICtrlContent.at(outer).at(k)->OnMouseMove(point, pDC, pBackDC); } } return TRUE; }
同上面onDraw函數同樣,MouseMove也是調用了DUIButton自身的MouseMove函數。具體代碼能夠查看上一篇文章。
所以Page類的做用只是用來管理Button,統一全部界面的操做。爲上層提供統一的處理接口。對於最上層的Dialog來講,
是不須要知道下面的按鈕是如何工做的。
今天就講到這裏,下一次會把Container和上層對接說明。有問題的朋友能夠留意!
新建的討論羣,有興趣能夠加入
VC/Wince羣:87053214
Edited by mythou
原創博文,轉載請標明出處:http://www.cnblogs.com/mythou/p/3161754.html
系列文章連接: