cocos2d-x改底层之获取UIListView的实际内容大小

实际项目中UI界面中经常会用到UIListView,大多会在CocoStudio中直接添加这个控件。但是在使用中发现了一些坑和功能缺乏,然 后就看了一下底层的逻辑,发现稍微改一下底层就可以满足需求,所以下面就针对需求来分析UIListView的底层,同时做一些改动。

 

需求:根据链表中的内容来动态调整listView本身的大小

首先,我们要知道,我们插入和移除链表中的一项,listView本身会如何处理:

 

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void ListView::pushBackDefaultItem()
{
     if (!_model)
     {
         return ;
     }
     /* 克隆一份模板,并添加到项的数组里 */
     Widget* newItem = _model->clone();
     _items->addObject(newItem);
     /* 根据listView的基础设置来调整新加项的布局关系 */
     remedyLayoutParameter(newItem);
     addChild(newItem);
     /* 重点:打开刷新开关 */
     _refreshViewDirty = true ;
}

 

这里最后一句才是重点,只有刷新了才会真正计算新的显示,之前的改动才真正生效,所以放我们添加一项的时候,当前帧其实并没有立即刷新,如果这时候 获取大小,只会和之前的一样,并没有改变,那么我们要知道,开关_refreshViewDirty是在什么时候起作用了呢,如下:

 

?
1
2
3
4
5
6
7
8
9
10
void ListView::sortAllChildren()
{
     ScrollView::sortAllChildren();
     if (_refreshViewDirty)
     {
         /* 刷新 */
         refreshView();
         _refreshViewDirty = false ;
     }
}
?
1
2
3
4
5
6
7
8
9
10
11
void ListView::refreshView()
{
     ccArray* arrayItems = getItems()->data;
     int length = arrayItems->num;
     for ( int i= 0 ; i<length; item= "static_cast<Widget*" >(arrayItems->arr[i]);
         item->setZOrder(i);
         remedyLayoutParameter(item);
     }
     /* 更新内容大小 */
     updateInnerContainerSize();
}</length;>

可以看到,最关键的改变大小的函数updateInnerContainerSize():

定义一个变量用来保存真实大小,原因是listView本身计算大小的结果并不是以内容为准,而是以最初用户设置的大小,那么真实的大小会被遗弃,所以我们要保存住她:

 

?
1
CCSize _actualInnerSize;
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
void ListView::updateInnerContainerSize()
{
     switch (_direction)
     {
         case SCROLLVIEW_DIR_VERTICAL:
         {
             /*...*/
             
             /* 保存真实大小 */
             _actualInnerSize = CCSize(finalWidth, finalHeight);
             setInnerContainerSize(_actualInnerSize);
             break ;
         }
         case SCROLLVIEW_DIR_HORIZONTAL:
         {
             /*...*/
             
             /* 保存真实大小 */
             _actualInnerSize = CCSize(finalWidth, finalHeight);
             setInnerContainerSize(_actualInnerSize);
             break ;
         }
         default :
             break ;
     }
}

 

 

setInnerContainerSize(_actualInnerSize);这个函数是在父类定义的:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
void ScrollView::setInnerContainerSize( const CCSize &size)
{
     /* 获取用户设置的大小(没设置就是默认的) */
     float innerSizeWidth = _size.width;
     float innerSizeHeight = _size.height;
     /* 获取原始大小 */
     CCSize originalInnerSize = _innerContainer->getSize();
     /* 更新后的新的内容大小与设置的大小作比较 */
     if (size.width < _size.width)
     {
         /* 如果新的内容大小比设置的要小,输出提示,并以设置的大小为准,大小不改变 */
         CCLOG( "Inner width <= scrollview width, it will be force sized!" );
     }
     else
     {
         /* 如果新的内容大小比设置的要大,则以新内容大小为准 */
         innerSizeWidth = size.width;
     }
     if (size.height < _size.height)
     {
         CCLOG( "Inner height <= scrollview height, it will be force sized!" );
     }
     else
     {
         innerSizeHeight = size.height;
     }
     _innerContainer->setSize(CCSize(innerSizeWidth+ 5 , innerSizeHeight+ 10 ));
}


在updateInnerContainerSize函数中我们以保存了实际内容大小,需要写一个get函数来获取:

 

 

?
1
2
3
4
5
6
CCSize ListView::getActualInnerSize()
{
     /* 重点:立即(当前帧)执行刷新,更新大小 */
     refreshView();
     return _actualInnerSize;
}

 

最后实现需求:listView->setSize(getActualInnerSize())

 

上面是在CocoStudio中添加的UIListView控件,如果是手动创建的话有三点注意:

 

为了能够滚动,要实现两个条件

①:setTouchEnable(true)

②:一定要将UIListView 放入到UILayer中,只有UILayer才会监听UI系列触摸,CCLayer不可以

所以需要创建一个UILayer* layer;layer->addWidget(list);//一定是addWidget,表示以挂件形式添加,addChild不可以,最后再addChild(layer);

③:向列表中添加控件时,列表会自动排好位置,此时位置是不受手动管理的(而且位置通常不对,中心点在左上角,我们无法改变,做相对偏移等);但有 时候我们为了调整位置,只能添加中间层,如UILayout,而UILayout要注意的是,它相当于一个层,坐标计算和层一样。

 

转载于:https://www.cnblogs.com/dudu580231/p/4930288.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值