duilib中的V和H布局中滚动条问题

转自博客:http://blog.csdn.net/damingg/article/details/41149037

首先看一段xml代码

[html] view
plain
copy

  1.  <?xml version="1.0" encoding="utf-8"?>  
  2. <Window size="300,200" caption="0,0,300,20">  
  3.     <HorizontalLayout name="aaaa" bkcolor="#FFEEEEEE" >  
  4.   
  5.         <VerticalLayout name="xxxxxx" float="true" pos="50,20,250,195" hscrollbar="true" vscrollbar="true" sepheight="4" >  
  6.           
  7.             <Label name="child1" text="text1" float="false" pos="0,0,300,200" bordercolor="#FFEE00EE" bkcolor="#FF0000EE" textcolor="#FF010101"/>  
  8.             <Label name="child2" text="text2" float="false" pos="0,0,200,200" bordercolor="#FFEE00EE" bkcolor="#FF0000EE" textcolor="#FF01FF01"/>  
  9.   
  10.         </VerticalLayout>  
  11.   
  12.     </HorizontalLayout>  
  13. </Window>  

这是一个窗口,它包含一个竖的布局,显示出来初始状态是这样的:

在布局中,2个子控件所需要的长和宽,比布局本身的大小要大,所以需要2个滚动条来拉动显示。

我们可以看到横竖两个滚动条。

不过,我们拉动滚动条,却不能完全展示子控件。如下图:

虽然横向滚动条拉到了最右边,但Label控件child1的右边没有展示出来。

检查代码,发现CVerticalLayoutUI的SetPos方法如下:

[cpp] view
plain
copy

  1. void CVerticalLayoutUI::SetPos(RECT rc)  
  2. {  
  3.     ...省略若干代码  
  4.   
  5.     // Process the scrollbar  
  6.     ProcessScrollBar(rc, 0, cyNeeded);  
  7. }  

在最后面,调用了基类CContainerUI的ProcessScrollBar方法,来设置滚动条信息,ProcessScrollBar函数的第二个参数是设置横向滚动条信息,第三个参数是竖向滚动条。此时设置横向的参数为0,竖向的是cyNeeded。显然,这里忽略了横向的,所以在竖向布局VerticalLayout中,横向滚动条不能正常显示。

在CVerticalLayoutUI::SetPos中,所有涉及到cyNeeded的代码如下:

[cpp] view
plain
copy

  1. int cyNeeded = 0;  
  2.         int cyExpand = 0;  
  3.         if( nAdjustables > 0 ) cyExpand = MAX(0, (szAvailable.cy - cyFixed) / nAdjustables);  
  4.         // Position the elements  
  5.         SIZE szRemaining = szAvailable;  
  6.         int iPosY = rc.top;  
  7.         if( m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible() ) {  
  8.             iPosY -= m_pVerticalScrollBar->GetScrollPos();  
  9.         }  
  10.         int iPosX = rc.left;  
  11.         if( m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsVisible() ) {  
  12.             iPosX -= m_pHorizontalScrollBar->GetScrollPos();  
  13.         }  
  14.         int iAdjustable = 0;  
  15.         int cyFixedRemaining = cyFixed;  
  16.         for( int it2 = 0; it2 < m_items.GetSize(); it2++ ) {  
  17.             CControlUI* pControl = static_cast<CControlUI*>(m_items[it2]);  
  18.             if( !pControl->IsVisible() ) continue;  
  19.             if( pControl->IsFloat() ) {  
  20.                 SetFloatPos(it2);  
  21.                 continue;  
  22.             }  
  23.   
  24.             RECT rcPadding = pControl->GetPadding();  
  25.             szRemaining.cy -= rcPadding.top;  
  26.             SIZE sz = pControl->EstimateSize(szRemaining);  
  27.             if( sz.cy == 0 ) {  
  28.                 iAdjustable++;  
  29.                 sz.cy = cyExpand;  
  30.                 // Distribute remaining to last element (usually round-off left-overs)  
  31.                 if( iAdjustable == nAdjustables ) {  
  32.                     sz.cy = MAX(0, szRemaining.cy - rcPadding.bottom - cyFixedRemaining);  
  33.                 }   
  34.                 if( sz.cy < pControl->GetMinHeight() ) sz.cy = pControl->GetMinHeight();  
  35.                 if( sz.cy > pControl->GetMaxHeight() ) sz.cy = pControl->GetMaxHeight();  
  36.             }  
  37.             else {  
  38.                 if( sz.cy < pControl->GetMinHeight() ) sz.cy = pControl->GetMinHeight();  
  39.                 if( sz.cy > pControl->GetMaxHeight() ) sz.cy = pControl->GetMaxHeight();  
  40.                 cyFixedRemaining -= sz.cy;  
  41.             }  
  42.   
  43.             sz.cx = pControl->GetFixedWidth();  
  44.             if( sz.cx == 0 ) sz.cx = szAvailable.cx - rcPadding.left - rcPadding.right;  
  45.             if( sz.cx < 0 ) sz.cx = 0;  
  46.             if( sz.cx < pControl->GetMinWidth() ) sz.cx = pControl->GetMinWidth();  
  47.             if( sz.cx > pControl->GetMaxWidth() ) sz.cx = pControl->GetMaxWidth();  
  48.   
  49.             RECT rcCtrl = { iPosX + rcPadding.left, iPosY + rcPadding.top, iPosX + rcPadding.left + sz.cx, iPosY + sz.cy + rcPadding.top + rcPadding.bottom };  
  50.             pControl->SetPos(rcCtrl);  
  51.   
  52.             iPosY += sz.cy + m_iChildPadding + rcPadding.top + rcPadding.bottom;  
  53.             cyNeeded += sz.cy + rcPadding.top + rcPadding.bottom;  
  54.             szRemaining.cy -= sz.cy + m_iChildPadding + rcPadding.bottom;  
  55.         }  
  56.         cyNeeded += (nEstimateNum - 1) * m_iChildPadding;  

在for循环里,会统计所有非float子控件的高度

在  cyNeeded += sz.cy + rcPadding.top + rcPadding.bottom;  里,sz.cy是1个子控件的高度,而rcPadding = pControl->GetPadding(); 是控件的padding属性,也就是外边距。

最后yNeeded += (nEstimateNum - 1) * m_iChildPadding;  m_iChildPadding是布局的childpadding属性,也就是子控件之间的额外距离。

我们可以仿照cyNeeded的计算方式,来算出cxNeeded。因为是竖向布局,所以 cyNeeded += sz.cy 这里是累加,但是横向值,应该取最宽的控件的值,

所以for循环中的代码应该是这样:

int tmp = sz.cx + rcPadding.left + rcPadding.right;
cxNeeded = (tmp > cxNeeded) ? tmp: cxNeeded;

最后cxNeeded += (nEstimateNum - 1) * m_iChildPadding;

    此时通过对代码的了解,可以得知:布局在计算容量面积时,只计算非float类型的子控件,忽略了float类型的子控件。

算出了布局的宽度后,就应用起来

修改原来的代码为:ProcessScrollBar(rc, cxNeeded, cyNeeded);

改完后,发现问题依然。于是,检查了下ProcessScrollBar的代码,如下

[cpp] view
plain
copy

  1. void CContainerUI::ProcessScrollBar(RECT rc, int cxRequired, int cyRequired)  
  2. {  
  3.     if( m_pHorizontalScrollBar != NULL && m_pHorizontalScrollBar->IsVisible() ) {  
  4.         RECT rcScrollBarPos = { rc.left, rc.bottom, rc.right, rc.bottom + m_pHorizontalScrollBar->GetFixedHeight()};  
  5.         m_pHorizontalScrollBar->SetPos(rcScrollBarPos);  
  6.     }  
  7.   
  8.     if( m_pVerticalScrollBar == NULL ) return;  
  9.   
  10.     if( cyRequired > rc.bottom - rc.top && !m_pVerticalScrollBar->IsVisible() ) {  
  11.         m_pVerticalScrollBar->SetVisible(true);  
  12.         m_pVerticalScrollBar->SetScrollRange(cyRequired - (rc.bottom - rc.top));  
  13.         m_pVerticalScrollBar->SetScrollPos(0);  
  14.         m_bScrollProcess = true;  
  15.         SetPos(m_rcItem);  
  16.         m_bScrollProcess = false;  
  17.         return;  
  18.     }  
  19.     // No scrollbar required  
  20.     if( !m_pVerticalScrollBar->IsVisible() ) return;  
  21.   
  22.     // Scroll not needed anymore?  
  23.     int cyScroll = cyRequired - (rc.bottom - rc.top);  
  24.     if( cyScroll <= 0 && !m_bScrollProcess) {  
  25.         m_pVerticalScrollBar->SetVisible(false);  
  26.         m_pVerticalScrollBar->SetScrollPos(0);  
  27.         m_pVerticalScrollBar->SetScrollRange(0);  
  28.         SetPos(m_rcItem);  
  29.     }  
  30.     else  
  31.     {  
  32.         RECT rcScrollBarPos = { rc.right, rc.top, rc.right + m_pVerticalScrollBar->GetFixedWidth(), rc.bottom };  
  33.         m_pVerticalScrollBar->SetPos(rcScrollBarPos);  
  34.   
  35.         if( m_pVerticalScrollBar->GetScrollRange() != cyScroll ) {  
  36.             int iScrollPos = m_pVerticalScrollBar->GetScrollPos();  
  37.             m_pVerticalScrollBar->SetScrollRange(::abs(cyScroll));  
  38.             if( m_pVerticalScrollBar->GetScrollRange() == 0 ) {  
  39.                 m_pVerticalScrollBar->SetVisible(false);  
  40.                 m_pVerticalScrollBar->SetScrollPos(0);  
  41.             }  
  42.             if( iScrollPos > m_pVerticalScrollBar->GetScrollPos() ) {  
  43.                 SetPos(m_rcItem);  
  44.             }  
  45.         }  
  46.     }  
  47. }  

很明显,cxRequired根本没有用到。

对于横向滚动条,只使用了这3行代码:

[cpp] view
plain
copy

  1. if( m_pHorizontalScrollBar != NULL && m_pHorizontalScrollBar->IsVisible() ) {  
  2.     RECT rcScrollBarPos = { rc.left, rc.bottom, rc.right, rc.bottom + m_pHorizontalScrollBar->GetFixedHeight()};  
  3.     m_pHorizontalScrollBar->SetPos(rcScrollBarPos);  
  4. }  

于是,我们需要仿照设置竖向滚动条的方式,来设置横向滚动条:

[cpp] view
plain
copy

  1. void CContainerUI::ProcessScrollBar(RECT rc, int cxRequired, int cyRequired)  
  2. {  
  3.     while(m_pHorizontalScrollBar)  
  4.     {  
  5.         if (cxRequired > rc.right - rc.left && !m_pHorizontalScrollBar->IsVisible())  
  6.         {  
  7.             m_pHorizontalScrollBar->SetVisible(true);  
  8.             m_pHorizontalScrollBar->SetScrollRange(cxRequired - (rc.right - rc.left));  
  9.             m_pHorizontalScrollBar->SetScrollPos(0);  
  10.             m_bScrollProcess = true;  
  11.             SetPos(m_rcItem);  
  12.             m_bScrollProcess = false;  
  13.             break;  
  14.         }  
  15.   
  16.         if( !m_pHorizontalScrollBar->IsVisible() ) break;  
  17.   
  18.         int cxScroll = cxRequired - (rc.right - rc.left);  
  19.         if (cxScroll <= 0 && !m_bScrollProcess)  
  20.         {  
  21.             m_pHorizontalScrollBar->SetVisible(false);  
  22.             m_pHorizontalScrollBar->SetScrollPos(0);  
  23.             m_pHorizontalScrollBar->SetScrollRange(0);  
  24.             SetPos(m_rcItem);  
  25.         }  
  26.         else  
  27.         {  
  28.             RECT rcScrollBarPos = { rc.left, rc.bottom, rc.right, rc.bottom + m_pHorizontalScrollBar->GetFixedHeight() };  
  29.             m_pHorizontalScrollBar->SetPos(rcScrollBarPos);  
  30.   
  31.             if( m_pHorizontalScrollBar->GetScrollRange() != cxScroll ) {  
  32.                 int iScrollPos = m_pHorizontalScrollBar->GetScrollPos();  
  33.                 m_pHorizontalScrollBar->SetScrollRange(::abs(cxScroll));  
  34.                 if( m_pHorizontalScrollBar->GetScrollRange() == 0 ) {  
  35.                     m_pHorizontalScrollBar->SetVisible(false);  
  36.                     m_pHorizontalScrollBar->SetScrollPos(0);  
  37.                 }  
  38.                 if( iScrollPos > m_pHorizontalScrollBar->GetScrollPos() ) {  
  39.                     SetPos(m_rcItem);  
  40.                 }  
  41.             }  
  42.         }  
  43.         break;  
  44.     }  
  45.   
  46.     while(m_pVerticalScrollBar)  
  47.     {  
  48.         if( cyRequired > rc.bottom - rc.top && !m_pVerticalScrollBar->IsVisible() ) {  
  49.             m_pVerticalScrollBar->SetVisible(true);  
  50.             m_pVerticalScrollBar->SetScrollRange(cyRequired - (rc.bottom - rc.top));  
  51.             m_pVerticalScrollBar->SetScrollPos(0);  
  52.             m_bScrollProcess = true;  
  53.             SetPos(m_rcItem);  
  54.             m_bScrollProcess = false;  
  55.             break;  
  56.         }  
  57.         // No scrollbar required  
  58.         if( !m_pVerticalScrollBar->IsVisible() ) break;  
  59.   
  60.         // Scroll not needed anymore?  
  61.         int cyScroll = cyRequired - (rc.bottom - rc.top);  
  62.         if( cyScroll <= 0 && !m_bScrollProcess) {  
  63.             m_pVerticalScrollBar->SetVisible(false);  
  64.             m_pVerticalScrollBar->SetScrollPos(0);  
  65.             m_pVerticalScrollBar->SetScrollRange(0);  
  66.             SetPos(m_rcItem);  
  67.         }  
  68.         else  
  69.         {  
  70.             RECT rcScrollBarPos = { rc.right, rc.top, rc.right + m_pVerticalScrollBar->GetFixedWidth(), rc.bottom };  
  71.             m_pVerticalScrollBar->SetPos(rcScrollBarPos);  
  72.   
  73.             if( m_pVerticalScrollBar->GetScrollRange() != cyScroll ) {  
  74.                 int iScrollPos = m_pVerticalScrollBar->GetScrollPos();  
  75.                 m_pVerticalScrollBar->SetScrollRange(::abs(cyScroll));  
  76.                 if( m_pVerticalScrollBar->GetScrollRange() == 0 ) {  
  77.                     m_pVerticalScrollBar->SetVisible(false);  
  78.                     m_pVerticalScrollBar->SetScrollPos(0);  
  79.                 }  
  80.                 if( iScrollPos > m_pVerticalScrollBar->GetScrollPos() ) {  
  81.                     SetPos(m_rcItem);  
  82.                 }  
  83.             }  
  84.         }  
  85.         break;  
  86.     }  
  87. }  

看看效果

可以看到控件child1的右边框。

HorizontalLayout也有同样的问题,可类似修改。

时间: 2024-09-20 19:33:59

duilib中的V和H布局中滚动条问题的相关文章

scrollview-如何只让一个 textview 滚动而不是在整个布局中?

问题描述 如何只让一个 textview 滚动而不是在整个布局中? 我在 xml 布局中创建了几个布局,在这些布局中有一个 textview,包含一个大的文本.我想问的是如何只设置textview 垂直滚动,而不是整个布局. xml 布局: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/inner_content" androi

PS网页设计教程V——如何在Photoshop中创建一个商业网站布局

作为编码者,美工基础是偏弱的.我们可以参考一些成熟的网页PS教程,提高自身的设计能力.套用一句话,"熟读唐诗三百首,不会作诗也会吟". 本系列的教程来源于网上的PS教程,都是国外的,全英文的.本人尝试翻译这些优秀的教程.因为翻译能力有限,翻译的细节上还有待推敲,希望广大网友不吝赐教. 约定: 1.本文的软件是Photoshop CS5版本 2.原教程的截图是英文的,本人在重新制作的基础上,重新截了中文版的图 3.原文中有些操作没有给出参数.本人在反复测试的情况下测定了一些参数,以红色的

layout-android布局中的swipe动画

问题描述 android布局中的swipe动画 我了解到动画效果可以运用到布局中,能实现onclicklistener, ontouchlistener事件. 但是不了解当向左边或右边滑动布局时,哪个事件会发生. previousButton.setOnClickListener(new OnClickListener() { @Override publicvoid onClick(View v) { viewFlipper.setInAnimation(MainActivity.this,R

camera-捕捉图像,然后使用 activity 在另一个布局中显示

问题描述 捕捉图像,然后使用 activity 在另一个布局中显示 我想通过在 FirstActivity 中点击按钮Capture捕捉图像,然后使用SecondActivity在activity_second(layout)中显示出来.如何实现? 代码部分: FirstActivity public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.la

android-如何在一个自定义的布局中显示图像?

问题描述 如何在一个自定义的布局中显示图像? 我可以使用下面的代码在一个系统布局中显示一个图像,但是我希望在我自定义的布局中显示一个图像,如何实现? public void onClick(View v) { // TODO Auto-generated method stub int id = v.getId(); Intent intent = new Intent(); intent.setAction(Intent.ACTION_VIEW); intent.setDataAndType(

【H.264/AVC视频编解码技术详解】八、 熵编码算法(2):H.264中的熵编码基本方法、指数哥伦布编码

<H.264/AVC视频编解码技术详解>视频教程已经在"CSDN学院"上线,视频中详述了H.264的背景.标准协议和实现,并通过一个实战工程的形式对H.264的标准进行解析和实现,欢迎观看! "纸上得来终觉浅,绝知此事要躬行",只有自己按照标准文档以代码的形式操作一遍,才能对视频压缩编码标准的思想和方法有足够深刻的理解和体会! 链接地址:H.264/AVC视频编解码技术详解 GitHub代码地址:点击这里 本节视频免费 1. H.264中的熵编码基本方法

深入解析Android中的setContentView加载布局原理

前言 对于Android的开发者来说,setContentView大家再熟悉不过了,在我们的Activity中首先就是要用它加载我们的布局,但是应该有一部分人是不知道加载布局的原理,也包括我,今天就从源码的角度分析setContentView加载布局原理. 准备工作 由于我们使用的Android API部分源码是隐藏的,当我们在AndroidStudio中是不能找到源码的,我们可以去官网下载相应源码去查看,当然在GitHub下载相应版本的API替换我们sdk下platforms相应api的and

Android 布局中的android:onClick的使用方法总结

Android 布局中的android:onClick的使用方法总结 Android布局中的 android:onClick="..."属性设置点击时从上下文中调用指定的方法.该属性值和要调用的方法名称完全一致.一般在Activity定义符合如下参数和返回值的函数并将方法名字符串指定为该属性值即可: public void onClickButton(View view) android:onClick="onClickButton" 功能类似于Button的监听器

Android布局中涉及的一些属性

Android:gravity属性     线性布局常见的就是利用LinearLayout进行布局,其中有个比较重要的属性就是android:gravity,在官方文档中是这么描述这个属性的:指定一个元素怎么放置它的内容,包括在X和Y轴,在它自己的边框中. 下面我们将在一个简单的TextView中应用android:gravity属性.假设我们想要TextView内的内容在右侧显示,那么我们就可以编写对应的XML布局 <LinearLayout xmlns:android="http://