亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

Duilib中帶有權重的靈活控件排列實現(一)

2019-11-10 17:28:31
字體:
來源:轉載
供稿:網友
在開發播放器軟件過程中,因為窗口的大小是可變的,為了讓控制欄部分的控件(播放,上一集,下一集,全屏,字幕等)適應窗口的尺寸的變化而顯示隱藏,產品經理會定義一系列的規則,好讓在任何時候都最核心的功能提供給用戶使用。先列一下產品經理給予的需求:兩邊往中間縮,保證左側LOGO和右側X最優先顯示。頂部隱藏優先級:搜索欄,換膚,意見反饋,播放記錄,最小化,最大化底部隱藏優先級:全屏,畫質增強,無痕,打開文件,播放順序,音量條在處理這個需求過程中,前人也嘗試了一些方法,比較通過全float絕對布局的方式,自己通過管理類來完全訂制。而我個人還是希望通過而優雅的相對布局,并利用Container自身的排布算法來實現。經過幾天的探索,大致實現上這種效果,在此分享一下思路與實現。在分析此需求時,我希望引來類似于第3維的權重(weight)概念,即當父容器所提供的位置不足于將所有子控件擺放顯示完全時,就按照重要性自低到高依次隱藏,將該控件的顯示騰出來提供給更為重要的控件來擺放,簡單推演一下,應該是可行的,按照這樣簡單的規則,可以比較輕松地解決這個需求,并且代碼維護起來相對簡單。只需要一個能夠按照子控件的weight值來排列的父容器,命名為CWeightHorizontalLayoutUI。OK,讓我們來實現這個父容器,首先我介紹一下 CHorizontalLayoutUI::SetPos的方法。其實就是兩次for循環,前一次來試算,將沒有設置寬度的控件記錄下來,將剩余的空間求個平均數,設置給自適應的控件,而設置了寬度的控件則按設置的值排布。
    void CWeightHorizontalLayoutUI::SetPos(RECT rc)    {        CControlUI::SetPos(rc);        rc = m_rcItem;        std::map<CControlUI*, int /*width*/> mapAjust;        // Adjust for inset        rc.left     += m_rcInset.left;        rc.top      += m_rcInset.top;        rc.right    -= m_rcInset.right;        rc.bottom   -= m_rcInset.bottom;        if (m_items.GetSize() == 0) {            PRocessScrollBar(rc, 0, 0);            return;        }        if (!m_bScrollFloat && m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible())             rc.right -= m_pVerticalScrollBar->GetFixedWidth();        if (!m_bScrollFloat && m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsVisible())             rc.bottom -= m_pHorizontalScrollBar->GetFixedHeight();        ResetWeightDisplayControlState(); //  讀取當前子控件的權重        m_mapWeight.clear();        for (int i = 0; i < m_items.GetSize(); i++) {            DuiLib::CControlUI* pControl = static_cast<DuiLib::CControlUI*>(m_items[i]);            if (pControl == nullptr) continue;            CStdString strweight = pControl->GetCustomAttribute(L"weight");            int nweight = _ttoi(strweight.GetData());            m_mapWeight[i] = nweight;        }        m_mapWeightCache = m_mapWeight;        // 查找最小權重控件          auto HideMinWeigth = [&](int index) -> bool {            CControlUI* pControl = static_cast<CControlUI*>(m_items[index]);            if (pControl && pControl->IsVisible()) {                pControl->SetInternVisible(false);                m_arrWeightHideControl.push_back(pControl);                return true;            }            return false;        };        // Determine the width of elements that are sizeable        SIZE szAvailable = { rc.right - rc.left, rc.bottom - rc.top };        if (m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsVisible())            szAvailable.cx += m_pHorizontalScrollBar->GetScrollRange();        int nAdjustables = 0;        int cxFixed = 0;        int nEstimateNum = 0;        int cxExpand = 0;        std::pair<int, int> min_weight; // first:control index, second:weight        std::map<CControlUI*, int /*width*/> m_mapEstimateWidth;  // 試算時控件的預設寬度        std::map<CControlUI*, int /*width*/> m_mapBookWidth;        do {            // 查找出當前權重值最小,并且顯示著的控件            min_weight = std::make_pair(999, 999);            std::for_each(m_mapWeight.begin(), m_mapWeight.end(), [&](std::pair<int, int> item)-> void {                CControlUI* pControl = static_cast<CControlUI*>(m_items[item.first]);                if (item.second <= min_weight.second && pControl->IsVisible())                    min_weight = item;            });            // 已經找到后從map中移除,以避免下次查找的還是這個控件            auto min_it = std::find_if(m_mapWeight.begin(), m_mapWeight.end(), [min_weight](std::pair<int, int> item)-> bool {                return (item.first == min_weight.first && item.second == item.second);            });            if (min_it != m_mapWeight.end()) m_mapWeight.erase(min_it);            // 試算中            nAdjustables = 0;            cxFixed = 0;            nEstimateNum = 0;            for (int it1 = 0; it1 < m_items.GetSize(); it1++) {                CControlUI* pControl = static_cast<CControlUI*>(m_items[it1]);                if (pControl->IsFloat()) continue;                if (!pControl->IsVisible()) continue;                SIZE sz = pControl->EstimateSize(szAvailable);                if (sz.cx == 0) {                                                         nAdjustables++;                }                else {                    if (sz.cx < pControl->GetMinWidth()) sz.cx = pControl->GetMinWidth();                    if (sz.cx > pControl->GetMaxWidth()) sz.cx = pControl->GetMaxWidth();                }                m_mapEstimateWidth[pControl] = sz.cx;                cxFixed += sz.cx + pControl->GetPadding().left + pControl->GetPadding().right;                nEstimateNum++;            }            cxFixed += (nEstimateNum - 1) * m_iChildPadding;            cxExpand = 0;            if (nAdjustables > 0) cxExpand = max(0, (szAvailable.cx - cxFixed) / nAdjustables);// 此處下節解釋            // 如果小于空間不夠,先嘗試從低到高縮減帶有adjust屬性的控件            if (szAvailable.cx - cxFixed < 0) {                std::vector<std::pair<CControlUI*, int>> adj_ctrls;                for (int it1 = 0; it1 < m_items.GetSize(); it1++) {                    CControlUI* pControl = static_cast<CControlUI*>(m_items[it1]);                    if (pControl->IsFloat()) continue;                    //if (!pControl->IsVisible()) continue;                    if (pControl->GetCustomAttribute(L"adjustwidth") == NULL ||                        _tcscmp(pControl->GetCustomAttribute(L"adjustwidth"), L"true")) continue;                    adj_ctrls.push_back(std::make_pair(pControl, m_mapWeightCache[it1]));                }                // 自小到大按權重,先嘗試最小權重                std::sort(adj_ctrls.begin(), adj_ctrls.end(), [&](std::pair<CControlUI*, int> lhs,                    std::pair<CControlUI*, int> rhs) -> bool {                    return lhs.second < rhs.second;                });                             for (auto it = adj_ctrls.begin(); it != adj_ctrls.end(); it++) {                    auto ctrl = it->first;                    if (m_mapEstimateWidth[ctrl] > ctrl->GetMinWidth()) {                        int sub_width = min(abs(szAvailable.cx - cxFixed), m_mapEstimateWidth[ctrl] - ctrl->GetMinWidth());                        m_mapEstimateWidth[ctrl] = m_mapEstimateWidth[ctrl] - sub_width;    // 新的試算寬度                         m_mapBookWidth[ctrl] = m_mapEstimateWidth[ctrl];                        cxFixed -= sub_width;                        if (szAvailable.cx - cxFixed >= 0) break; // 已經滿足排列空間                    }                                    }            }            // 空間不夠,從權重最小的依次隱藏        } while (szAvailable.cx - cxFixed < 0 && HideMinWeigth(min_weight.first));        // Position the elements        SIZE szRemaining = szAvailable;        int iposX = rc.left;        if (m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsVisible()) {            iPosX -= m_pHorizontalScrollBar->GetScrollPos();        }        int iAdjustable = 0;        int cxFixedRemaining = cxFixed;        for (int it2 = 0; it2 < m_items.GetSize(); it2++) {            CControlUI* pControl = static_cast<CControlUI*>(m_items[it2]);            if (!pControl->IsVisible()) continue;            if (pControl->IsFloat()) {                SetFloatPos(it2);                continue;            }            RECT rcPadding = pControl->GetPadding();            szRemaining.cx -= rcPadding.left;            SIZE sz = pControl->EstimateSize(szRemaining);            if (sz.cx == 0) {                iAdjustable++;                sz.cx = cxExpand;                //最后一個自適應尺寸大小無需另行計算                //if( iAdjustable == nAdjustables ) {                //	sz.cx = MAX(0, szRemaining.cx -cxFixedRemaining);                //}                if (sz.cx < pControl->GetMinWidth()) sz.cx = pControl->GetMinWidth();                if (sz.cx > pControl->GetMaxWidth()) sz.cx = pControl->GetMaxWidth();            }            else {                if (sz.cx < pControl->GetMinWidth()) sz.cx = pControl->GetMinWidth();                if (sz.cx > pControl->GetMaxWidth()) sz.cx = pControl->GetMaxWidth();            }            sz.cy = pControl->GetFixedHeight();            if (sz.cy == 0) sz.cy = rc.bottom - rc.top - rcPadding.top - rcPadding.bottom;            if (sz.cy < 0) sz.cy = 0;            if (sz.cy < pControl->GetMinHeight()) sz.cy = pControl->GetMinHeight();            if (sz.cy > pControl->GetMaxHeight()) sz.cy = pControl->GetMaxHeight();            //padding不算控件寬度//2012/09/12            //RECT rcCtrl = { iPosX + rcPadding.left, rc.top + rcPadding.top, iPosX + sz.cx + rcPadding.left + rcPadding.right, rc.top + rcPadding.top + sz.cy};            if (m_mapBookWidth.find(pControl) != m_mapBookWidth.end() &&                m_mapBookWidth[pControl] != sz.cx) {                sz.cx = m_mapBookWidth[pControl];            }            RECT rcCtrl = { iPosX + rcPadding.left, rc.top + rcPadding.top, min(iPosX + sz.cx + rcPadding.left, rc.right) , rc.top + rcPadding.top + sz.cy };            pControl->SetPos(rcCtrl);            iPosX += sz.cx + m_iChildPadding + rcPadding.left + rcPadding.right;            szRemaining.cx -= sz.cx + m_iChildPadding + rcPadding.right;            if (m_bWholeDisplay && rcCtrl.right > rc.left + szAvailable.cx)                m_arrWholeDisplayControl.push_back(pControl);        }        // Process the scrollbar        ProcessScrollBar(rc, 0, 0);    }以上代碼主要是在試算過程中,在剩余的空間寬度不足時隱藏一下最小的權重控件,再次試算一遍需要留心的是當Hide時不能夠直接調用子控件的SetVisible接口,這樣會改變控件的基礎狀態,而應使用SetInternVisible,并且在再次SetPos時,清除這樣的記錄,并將狀態重置,這樣,不影響再次的試算過程。基本以上實現了控制欄的自定義隱藏順序。而我們只需要在xml文件中配置一下各個控件的權重即可。實現效果:
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美色播在线播放| 国产精品视频久久久久| 激情亚洲一区二区三区四区| 在线精品高清中文字幕| 国产精品永久在线| 亚洲成人黄色在线| 国产精品高潮粉嫩av| 国产v综合v亚洲欧美久久| 欧美电影免费观看高清| 国产一区二中文字幕在线看| 这里只有视频精品| 91久久精品国产91久久性色| yellow中文字幕久久| 欧美电影免费观看电视剧大全| 92看片淫黄大片欧美看国产片| 欧美激情a∨在线视频播放| 久久69精品久久久久久久电影好| 欧美日韩一区二区在线播放| 久久国产精彩视频| 中文字幕亚洲国产| 少妇激情综合网| 91精品久久久久久久久久久久久久| 欧美日韩激情美女| 亚洲国产天堂网精品网站| 亚洲乱码国产乱码精品精天堂| 亚洲第一av网| 欧美高清视频在线观看| 午夜精品一区二区三区av| 欧美中文字幕视频在线观看| 久久69精品久久久久久久电影好| 2019av中文字幕| 亚洲一区二区三区在线视频| 亚洲最新中文字幕| 久久偷看各类女兵18女厕嘘嘘| 91av在线网站| 国产成人在线一区二区| 欧美激情久久久| 中文字幕日韩欧美在线| 中日韩美女免费视频网址在线观看| 欧美激情精品在线| 黑人巨大精品欧美一区二区三区| 国产免费观看久久黄| 欧美视频中文字幕在线| 久久久久在线观看| 国产在线观看一区二区三区| 国产精品中文久久久久久久| 欧美超级免费视 在线| 亚洲国产精品字幕| 国产成人a亚洲精品| 久久国产精品视频| 久久久久在线观看| 国产精品亚洲视频在线观看| 亚洲电影免费观看高清| 亚洲成色www8888| 国产一区二区成人| 欧美床上激情在线观看| 国产精品久久久精品| 色爱av美腿丝袜综合粉嫩av| 欧美大胆a视频| 欧美另类xxx| 日韩一区二区福利| 日韩欧美国产中文字幕| 欧美日韩999| 日韩免费在线播放| 亚洲91精品在线观看| 国产一区二区在线免费| 亚洲欧美一区二区三区情侣bbw| 成人乱色短篇合集| 欧美激情在线视频二区| 色综合久久精品亚洲国产| 亚洲午夜av久久乱码| 97超级碰碰人国产在线观看| 国产精品普通话| 中文字幕亚洲欧美日韩高清| 日韩欧美在线观看| 欧美极品欧美精品欧美视频| 国产精品久久久久久婷婷天堂| 亚洲美女视频网| 欧美亚洲另类在线| 国产免费一区二区三区在线能观看| 国内精品400部情侣激情| 日韩精品黄色网| 日韩成人激情视频| 伦理中文字幕亚洲| 97国产精品视频人人做人人爱| 日韩av快播网址| 国产精品福利观看| 欧美日韩一区二区免费在线观看| 欧美性xxxx极品hd满灌| 亚洲福利视频网| 狠狠躁夜夜躁人人躁婷婷91| 日韩精品视频在线播放| 日韩av在线精品| 国产精品久久久精品| 欧美黑人xxxⅹ高潮交| 日韩av在线免费| 国产日韩欧美影视| 日韩在线播放视频| 精品国产精品三级精品av网址| 亚洲18私人小影院| 成人精品一区二区三区| 国产欧美日韩精品丝袜高跟鞋| 午夜精品一区二区三区视频免费看| 午夜精品久久久久久久白皮肤| 亚洲嫩模很污视频| 国产视频精品免费播放| 亚洲一区亚洲二区亚洲三区| 久久免费精品视频| 高清欧美性猛交xxxx黑人猛交| 久久久久久久久电影| 福利视频一区二区| 国产精品专区一| 亚洲毛片在线观看| 国产精品久久99久久| 国产日本欧美一区| 国产亚洲欧美视频| 国产99视频精品免视看7| 91丝袜美腿美女视频网站| 精品国产网站地址| 欧美黑人xxxx| 韩国日本不卡在线| 国产深夜精品福利| 色一情一乱一区二区| 久久手机精品视频| 成人妇女淫片aaaa视频| 国产精品嫩草视频| 日韩女优人人人人射在线视频| 国产视频一区在线| 国产精品v片在线观看不卡| 午夜精品一区二区三区在线视| 久久中国妇女中文字幕| 国产日韩欧美影视| 欧美激情亚洲视频| 久久久精品一区二区| 欧美日韩一区二区精品| 欧美精品在线免费观看| 国产亚洲精品美女久久久久| 久久人人爽人人爽爽久久| 中文字幕一区二区三区电影| 国产精自产拍久久久久久蜜| 国产美女被下药99| 欧美电影《睫毛膏》| 日本午夜人人精品| 亚洲精品国产品国语在线| 国产精品亚洲综合天堂夜夜| 亚洲另类欧美自拍| 亚洲一区二区三区四区视频| 欧美日韩在线视频一区二区| 欧美激情亚洲精品| 国产精品一区二区三区毛片淫片| 亚洲国产天堂久久综合网| 国产一区二区精品丝袜| 日韩中文字幕国产精品| 欧美成人精品不卡视频在线观看| 国产盗摄xxxx视频xxx69| 成人写真视频福利网| 亚洲精品欧美极品| 91精品国产综合久久香蕉最新版| 欧美激情视频网站| 日韩高清av在线| 欧美裸体男粗大视频在线观看| 欧美国产精品日韩| 中文字幕日韩在线观看| 欧美成人免费观看|