仿Win8 Metro風(fēng)格如何實現(xiàn)兩個按鈕拖動交換位置,包括同一個頁面按鈕交換或者兩個頁面之間的按鈕交換。另外就是如何拖動刪除界面上的快捷方式。按鈕交換和拖動刪除,這兩個功能基本上是現(xiàn)在智能手機的標(biāo)準(zhǔn)功能,不管是IOS或者Android都有類似功能。我實現(xiàn)的功能,主要是參考Android的功能實現(xiàn)。
下面這個就是動態(tài)交換按鈕效果圖:
還是先把邏輯關(guān)系圖放出來:
1、按鈕拖動
怎么樣才能實現(xiàn)拖動一個按鈕到另外一個按鈕位置上,實現(xiàn)交換?這個首先一個需要做的就是拖動按鈕的操作。按鈕拖動我放到封裝的DUIButton里面實現(xiàn)。下面我們看看DUIButton里面如何把按鈕拖動出來。
int CDUIButton::OnMouseMove(POINT point, CDC * pDC, CDC * backDC) { //printf("mythou------->enter the Page::omMouseMove"); //判斷拖動的條件,按下按鈕并且移動的距離大于30像素的時候,認(rèn)為是拖動按鈕 if( abs(point.x - m_iEndSlide) > 30 || abs(m_clickY - point.y) > 30 || m_mouseMove)//拖動快捷鍵 { if(m_ClickState) { m_mouseMove = TRUE; CRect rect = CRect(0, 0, ScreenWidth, ScreenHeight); //恢復(fù)保存的背景,主要是提高繪畫效率 CDC destDC; destDC.CreateCompatibleDC(backDC); CBitmap CompatibleBmp; CompatibleBmp.CreateCompatibleBitmap(backDC,rect.Width(),rect.Height()); CBitmap *pOlddestBmp = destDC.SelectObject(&CompatibleBmp); destDC.FillSolidRect(&rect,RGB(0,0,0)); CDC srcDC; srcDC.CreateCompatibleDC(backDC); HBITMAP hOldBmp; destDC.BitBlt(0, 0, rect.Width(),rect.Height(), backDC, 0, 0, SRCCOPY); //根據(jù)用戶手指移動的位置,動態(tài)刷新按鈕,形成按鈕跟誰手指移動的效果 hOldBmp = (HBITMAP)srcDC.SelectObject(m_btnHBitmap); m_pngCtrl.BiltPNG(&destDC,&srcDC,(point.x-(m_btnRc.Width()/2) ), (point.y-(m_btnRc.Height()/2)), m_btnRc.Width(),m_btnRc.Height(), m_AlphaSel); srcDC.SelectObject(hOldBmp); //把按鈕圖片,繪畫到屏幕 pDC->BitBlt(0,0,rect.Width(),rect.Height(),&destDC,0,0,SRCCOPY); srcDC.DeleteDC(); destDC.SelectObject(pOlddestBmp); CompatibleBmp.DeleteObject(); destDC.DeleteDC(); return 1; } } return 0; }
從這里可以發(fā)現(xiàn),其實拖動一個按鈕,就是把該按鈕的圖片,跟隨手指的移動而動態(tài)貼圖。需要注意的是如何才能保證拖動的流暢性。這個需要把你的背景圖做成緩存,保留下來,拖動過程中,都是使用緩存中原始的背景圖。這樣每次拖動,只需要繪畫一個按鈕的圖片,才能流暢得拖動按鈕。
另外你手指點擊按鈕還需要做一些條件判斷,需要符合條件的情況下,才能拖動按鈕。我這里把手指觸摸按鈕分為3種行為:
點擊按鈕,打開某個程序
觸摸按鈕,滑動切換頁面
把按鈕拖動出來,執(zhí)行交換、刪除、添加操作
這幾個也是目前智能機系統(tǒng)一般都支持的手勢操作,上面我們按鈕的拖動,就是屬于第三種情況。
2、按鈕交換
把按鈕拖動出來,然后拖動到需要交換的按鈕的位置,釋放按鈕,執(zhí)行交換操作。這個就是交換的流程,這里根據(jù)釋放的位置來識別到底跟哪一個按鈕進(jìn)行交換。
//大按鈕移動到大按鈕位置 Edited by mythou if (UpBlockBig) { //printf("mythou-------->enter change the big block"); CDUIButton * tempDUIBtn; tempDUIBtn = m_pVUICtrlContent.at(m_BlockLine).at(m_BlockClickNum); //保存IDS CString FirstBtnIDS = tempDUIBtn->GetBtnIDS(); m_pVUICtrlContent.at(m_BlockLine).at(m_BlockClickNum) = m_pVUICtrlContent.at(Line).at(vectorBtnIndex); //保存IDS CString SecondBtnIDS = m_pVUICtrlContent.at(Line).at(vectorBtnIndex)->GetBtnIDS(); m_pVUICtrlContent.at(Line).at(vectorBtnIndex) = tempDUIBtn; //動畫效果 ChangeBtnPosAni(m_pVUICtrlContent.at(m_BlockLine).at(m_BlockClickNum), m_pVUICtrlContent.at(Line).at(vectorBtnIndex)); //修改配置文件 int PosIndex1 = GetBtnPos(m_BlockLine,m_BlockClickNum); int PosIndex2 = GetBtnPos(Line,vectorBtnIndex); m_pSaveInterFace->SwitchSameButton(Page,m_BlockLine,PosIndex1,FirstBtnIDS, Page,Line,PosIndex2,SecondBtnIDS); }
這是一個簡單的交換邏輯,因為我們的按鈕都是存放在Page類里面的二維Vector向量里面,按鈕交換位置也就是交換Vector里面的值。因為Vector里面存放只是按鈕對象的指針應(yīng)用。因此,Vector交換兩個指針也不會存在負(fù)責(zé)的數(shù)據(jù)交互。當(dāng)然如果要做出比較好的交換效果,我們免不了使用動畫,交換過程中。我們加入一個動畫效果,我這里做的是一個淡入淡出的效果,主要控制按鈕圖片的Alpha值,形成一個較好的交換效果。最后還需要把交換的位置信息記錄到文件里面,方便下次啟動程序的時候,保存交換后的效果。需要注意的是交換按鈕刷新和動畫效果之間的操作。要做到流程,考慮使用一個線程運行動畫。
3、拖動刪除按鈕
這個功能其實就是參照Android的刪除快捷方式做的。當(dāng)按鈕被拉動出來后,界面上方會出現(xiàn)一個有垃圾桶圖標(biāo)的區(qū)域,把按鈕拖動到該區(qū)域釋放,就可以把相對的快捷方式刪除。下面我們看看邏輯上如何實現(xiàn)。
//在刪除區(qū)域釋放,刪除按鈕 if (m_rcMainInterfaceDel.PtInRect(point)) { //printf("\n mythou------> Enter OnLButtonUpDeal() Delete the Btn ************** \n"); //刪除選中按鈕 CString DelBtnIDS = m_pVUICtrlContent.at(m_BlockLine).at(m_BlockClickNum)->GetBtnIDS(); m_pVUICtrlContent.at(m_BlockLine).at(m_BlockClickNum)->ResetAllClickFlag(); m_pVUICtrlContent.at(m_BlockLine).erase(m_pVUICtrlContent.at(m_BlockLine).begin()+m_BlockClickNum); //填充空按鈕 CDUIButton *pBtn = new CDUIButton(); pBtn->SetNullBtn(); m_pVUICtrlContent.at(m_BlockLine).insert((m_pVUICtrlContent.at(m_BlockLine).begin()+m_BlockClickNum),pBtn); //如果是大按鈕,再填充一次 if (m_BigBlock) { CDUIButton *pBtn = new CDUIButton(); pBtn->SetNullBtn(); m_pVUICtrlPos.at(m_BlockLine).push_back(CPoint(0,0)); m_pVUICtrlContent.at(m_BlockLine).insert((m_pVUICtrlContent.at(m_BlockLine).begin()+m_BlockClickNum),pBtn); } //修改配置文件 int PosIndex1 = GetBtnPos(m_BlockLine,m_BlockClickNum); m_pSaveInterFace->DeleteButton(Page,m_BlockLine,PosIndex1,DelBtnIDS,m_BigBlock); //DeleteButton(Page,m_BlockLine,PosIndex1,DelBtnIDS,m_BigBlock); m_BigBlock = FALSE; ReloadBtnPos(); return DEL_BTN; }
刪除操作在邏輯上也很簡單,就是刪除我們記錄的Vector里面的相對應(yīng)的按鈕指針。不過刪除后,我們需要做一些額外的操作。第一需要填充一個空按鈕指針到原來的位置。這個操作主要是用來記錄界面上哪些位置是可以存放按鈕和交換按鈕?瞻粹o是一個空類,只有一個標(biāo)記用來記錄位置。刪除后還需要針對按鈕的類型做不同的添加操作,大按鈕和小按鈕。。最后還需要在配置文件做記錄,記錄哪個按鈕刪除了。如果需要一個好的效果,可以類似交換按鈕一樣,加入一個動畫效果。
4、添加快捷方式欄
這是額外做的一個功能,主要是把常用的功能加入到一個導(dǎo)航欄上面,可以在任何界面使用相關(guān)常用功能。
void CDUIPage::Send2TaskBar(CDUIButton *pBtn) { printf("\n mythou-------->Enter Send2TaskBar ********************************\n"); DUIButtonData *pDuiData = new DUIButtonData(); //拷貝數(shù)據(jù) wcscpy(pDuiData->name, pBtn->m_btnName.GetBuffer(pBtn->m_btnName.GetLength())); pBtn->m_btnName.ReleaseBuffer(); wcscpy(pDuiData->cmd, pBtn->m_BtnClickCMD.GetBuffer(pBtn->m_BtnClickCMD.GetLength())); pBtn->m_BtnClickCMD.ReleaseBuffer(); wcscpy(pDuiData->animate, pBtn->m_AnimateType.GetBuffer(pBtn->m_AnimateType.GetLength())); pBtn->m_AnimateType.ReleaseBuffer(); wcscpy(pDuiData->ids, pBtn->m_BtnNameIDS.GetBuffer(pBtn->m_BtnNameIDS.GetLength())); pBtn->m_BtnNameIDS.ReleaseBuffer(); CString btnPicName = GetExeName(pBtn->m_btnPic); wcscpy(pDuiData->picName, btnPicName.GetBuffer(btnPicName.GetLength())); btnPicName.ReleaseBuffer(); COPYDATASTRUCT cpdata; cpdata.dwData=PROCESSID cpdata.cbData = sizeof(DUIButtonData); cpdata.lpData = (PVOID)pDuiData; HWND mainWnd = ::FindWindow(NULL,_T("APKTaskBar")); if (!mainWnd) { return; } printf("\n mythou------->Send the OnCopyData Send2TaskBar ********************************"); ::SendMessage(mainWnd, WM_COPYDATA, (WPARAM)m_MainWndH, (LPARAM)&cpdata); delete pDuiData; }
因為我的快捷欄是另外一個獨立程序,所以這里把需要添加的按鈕拉動到界面底部,然后把按鈕的相關(guān)數(shù)據(jù)轉(zhuǎn)換為相關(guān)數(shù)據(jù)包,發(fā)送到快捷欄程序里面。這里也需要加入相關(guān)的動畫效果,才能達(dá)到較好的界面交互效果。剩下的就是另外一個程序處理發(fā)送過來的數(shù)據(jù)包。解析然后顯示出來就好了。
今天主要是講解界面上常用的交換按鈕、刪除按鈕、添加快捷欄等操作。其中交換按鈕這里只是把同頁面的交換做了解說,除了同頁面交換外,也需要做到不同頁面之間交換,這個原理是一樣,只是不同頁面之間交換需要做到邏輯頁面的切換。這個也是我做了Page類作為頁面管理類的原因。不同類之間交換按鈕,只要切換Page類就好了。。。
轉(zhuǎn)載請標(biāo)明出處:http://www.cnblogs.com/mythou/p/3172707.html