滚动视图仅显示最后添加的子视图
Posted
技术标签:
【中文标题】滚动视图仅显示最后添加的子视图【英文标题】:scrollview is showing only the last added subview 【发布时间】:2013-04-22 23:03:19 【问题描述】:我的UIScrollView
子视图出现了奇怪的行为,我的想法是以编程方式创建UIView
的一个实例,其中包含一个自定义的 nib 文件,在我的例子中是一个表单,用模型类中的数据填充该表单,然后将其添加为我的UIScrollView
的子视图。 问题是当我处理多个子视图时,UIScrollView
只保留最新的子视图,所以如果我创建了三个子视图,滚动视图将只显示第三个(最新的)子视图。虽然页面控件设置为子视图的核心数量(三个)。
项目太长,所以我将尝试用相关代码简要解释我的问题:
- (void)viewDidLoad
NSArray *sorted = [appArray sortedArrayUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];//this array contains the data from model, I debugged that to make sure I got the exact data, no more no less :)
//Loop all NSManaged objects, for example let's say I have 3 model objects, don't worry about how I get data etc, because I debugged all and maked sure all data objects number are exact, etc.
for (App_Table *_appTable in sorted)
//This looped 3 times as expected, I debugged that also and maked sure on each iteration I got the data I expected to have
//App_Table is a subclass of NSManagedObject, it's my model class and get its data from coredata file
[self addMoreView];//Call this method will create a new subview and add it as subview to the UIScrollView, it will also update the page control, update the content size property, etc.
AppTableView *_appTableView = (AppTableView *) [[self.scrollView subviews] lastObject];//Remember addMoreView method create a new instance of AppTableView and add it as subview for the UIScrollView property, then I get that subview to fill it with data here
_appTableView.txtADDRESS.text = _appTable.address;//Fill in the form, no need to write all the form fields code because it's the same way.
// Scroll To First Page...
self.pageControl.currentPage = 0;
[self.scrollView scrollRectToVisible:CGRectMake(0, 0, viewWidth, viewHeight) animated:YES];
self.scrollView.contentSize = CGSizeMake(viewWidth*noOfItems, viewHeight);//Set the content size to the sum of subviews width, I also debugged that to check it's correct
self.scrollView.delegate = self;
[super viewDidLoad];
好的,所以当我有三个子视图时,滚动视图将加载三个子视图的宽度,根据上面的行计算:
self.scrollView.contentSize = CGSizeMake(viewWidth*noOfItems, viewHeight);//Set the content size to the sum of subviews width, I also debugged that to check it's correct
我可以滚动到 3 次移动(这是子视图的数量),UIPageControl
也设置为三个点,但只有一个子视图可见,我只能看到最新的一个看,另外两个子视图消失了,滚动视图为它们计算了内容大小,但它们不可见。有什么想法吗 ?谢谢。
编辑:
值得注意的是,我第一次编辑视图时,一切正常,当我处理3个子视图时,它们都是可见的,但是当我转到另一个视图并回到这个视图时,只有最后一个子视图可见。
另外,我正在开发一个带有拆分视图的 iPad 项目。
编辑:
这是为UIScrollView
绘制新子视图的方法的代码
-(IBAction) addMoreView
NSArray *arr = [[NSBundle mainBundle] loadNibNamed:@"AppTableView" owner:self options:nil];
AppTableView *aView = [arr objectAtIndex:0];
[aView setFrame:CGRectMake(startX, 0, aView.bounds.size.width, aView.bounds.size.height)];
[self.scrollView addSubview:aView];
self.scrollView.contentSize = CGSizeMake(self.scrollView.contentSize.width+aView.frame.size.width
, self.scrollView.contentSize.height);
startX = startX + aView.frame.size.width;//Update the X position, first 0, then 600, 1200, and so on.
[self.scrollView scrollRectToVisible:aView.frame animated:YES];
NSLog(@"%f",self.scrollView.contentSize.width);
NSLog(@"%f",self.scrollView.contentSize.height);
假设我有 3 个子视图,上面的方法将被调用 3 次,因为它被放入 for
循环中。所以这是NSLogs
对于上述方法的结果:
NSLog(@"%f",self.scrollView.contentSize.width);
NSLog(@"%f",self.scrollView.contentSize.height);
First iteration:
600.000000
0.000000
Second iteration:
1200.000000
0.000000
Third iteration:
1800.000000
0.000000
编辑:
rob mayoff 建议的命令让我明白为什么会发生这种情况:
| | | | <AppTableView: 0x1eef4700; frame = (0 18; 600 430); autoresize = LM+RM+TM+BM; tag = 990; layer = <CALayer: 0x1eef4790>>
| | | | <AppTableView: 0x1ee3f380; frame = (0 18; 600 430); autoresize = LM+RM+TM+BM; tag = 991; layer = <CALayer: 0x1ee3f410>>
| | | | <AppTableView: 0x1ee56910; frame = (0 18; 600 430); autoresize = LM+RM+TM+BM; tag = 992; layer = <CALayer: 0x1ee3f410>>
所有三个子视图都绘制在同一个框架中,因此它们在彼此之上,但是当我在运行时使用断点进行调试时,x
正在发生变化,第一次是 0,然后是 600,然后是 1200,这让我觉得它是正确绘图。如何解决这个问题,尤其是 x 值正在正确递增,那么问题是什么?为什么它们仍然在相同的 x 坐标上绘制?
【问题讨论】:
当您说“转到另一个视图并返回此视图”时,此视图是否正在重建?我猜它不是;-viewDidLoad
仅在第一次之前被调用,问题出在代码中的其他地方。
是的,它正在重建,因为当我退出这个视图时,数据会存储到模型中,然后当我返回时,会检索数据并重建子视图。你的意思-viewDidLoad is only called before the first time
我用断点检查过,viewDidLoad
在到达视图时总是被调用。
好的,那么如果您在对-viewDidLoad
的不同调用中得到不同的结果,那么这两个调用之间有什么变化?
嗨,在每次通话中,我检查了contentSize
、frame
、数据等。一切都很好,为什么滚动视图总是保持for
循环中的最后一次迭代,虽然它绘制了必要的空间来容纳所有子视图,但只显示其中一个?
您的for
循环在哪里结束?您可能需要向我们展示-addMoreView
的代码。
【参考方案1】:
首先,您应该将[super viewDidLoad]
调用放在- (void)viewDidLoad
方法的顶部,而不是底部。
鉴于您实际看到的内容和期望看到的内容还不够清楚,因此将您的问题的最低工作示例作为可下载项目提供给我们将有助于我们为您提供帮助。如果您只是尝试在不与托管对象交互但使用一些静态提供的数据的单独视图控制器中重现它,其他人将能够自己重现并调试它。或者你也可以在这个过程中自己弄清楚。
【讨论】:
【参考方案2】:我回来的有点晚了,但我终于找到了解决问题的方法,所以认为分享它以节省其他人的时间是件好事。
就我而言,滚动视图是 nib 文件中的自定义视图。因此,通过激活它的 Autosizing 遮罩左侧和顶部,修复了该错误。
【讨论】:
【参考方案3】:-addMoreView
中的这段代码就是问题所在:
AppTableView *aView = [arr objectAtIndex:0];
[aView setFrame:CGRectMake(startX, 0, aView.bounds.size.width, aView.bounds.size.height)];
[self.scrollView addSubview:aView];
如果startX
永远不会改变,那么您将在同一位置添加所有这些视图。
【讨论】:
啊,打错了,抱歉,我再次更新了我的帖子,实际上我使用了一个静态变量,它在加载时重新初始化为 0,然后它会增加子视图的宽度以开始绘制每次都在新的X
位置上。
我建议您在 -addMoreView
中添加一些调试以打印滚动视图中的每个子视图:for(UIView *v in self.scrollView.subviews)NSLog(@"%@", v);
并确保您有尽可能多的子视图,并且它们的框架是正确的,等等.
嗨,Seamus,我也已经调试过了,所有子视图的宽度、高度和 Y 位置值都相同,只有 X 位置从一个子视图更改为另一个。【参考方案4】:
您肯定没有为 3 个项目正确设置内容大小:
self.scrollView.contentSize.width+aView.frame.size.width
应该是
self.scrollView.contentSize.width+ ( aView.frame.size.width * NUMBER_OF_SUBVIEWS)
我想当你在滚动视图上水平滚动时,内容大小只允许一个子视图有足够的空间对吗?
【讨论】:
嗨,Thanx,我用其他试探性的板凳尝试了你的建议。不幸的是,没有人能解决我的问题。【参考方案5】:使用了一个静态变量,该变量在加载时重新初始化为 0,然后它会增加子视图的宽度以开始在新的 X 位置上绘图。
【讨论】:
【参考方案6】:尝试在addMoreView方法中将aView的autoresizingMask
设置为UIViewAutoresizingNone
。
【讨论】:
UIViewAutoresizingNone
是autoresizingMask
属性的默认值。
从您的日志中,AppTableView autoresizingMask 是 LM+RM+TM+BM。【参考方案7】:
我created a project 在姐妹帖子中使用了您的代码,并且工作正常。我在自动调整大小的掩码上添加了几个测试,如下所示。我建议您将其与您正在做的事情进行比较。当子视图或滚动视图上的掩码未设置为绑定到顶部/左侧时,会发生奇怪的事情。
我修改后的代码:
NSArray *colors = @[ [UIColor redColor], [UIColor greenColor], [UIColor blueColor] ];
UIViewAutoresizing mask;
mask = [self.scrollView autoresizingMask];
//assert(!self.scrollView.autoresizesSubviews); // has no affect here
if((mask & (UIViewAutoresizingFlexibleRightMargin|UIViewAutoresizingFlexibleBottomMargin)) != mask) NSLog(@"scrollView MASK WRONG");
for (int i=0; i<3; ++i)
NSArray *arr = [[NSBundle mainBundle] loadNibNamed:@"AppTableView" owner:self options:nil];
NSLog(@"scrollView frame: %@", NSStringFromCGRect(self.scrollView.frame));
if((mask & (UIViewAutoresizingFlexibleRightMargin|UIViewAutoresizingFlexibleBottomMargin)) != mask) NSLog(@"aView MASK WRONG");
AppTableView *aView = [arr objectAtIndex:0];
assert([aView isKindOfClass:[AppTableView class]]);
NSLog(@"orig aView frame: %@", NSStringFromCGRect(aView.frame));
UIViewAutoresizing mask = [aView autoresizingMask];
if((mask & (UIViewAutoresizingFlexibleRightMargin|UIViewAutoresizingFlexibleBottomMargin)) != mask) NSLog(@"aView MASK WRONG");
aView.frame = CGRectMake(startX, 0, aView.bounds.size.width, aView.bounds.size.height);
NSLog(@"changed aView frame: %@", NSStringFromCGRect(aView.frame));
aView.backgroundColor = colors[i];
[self.scrollView addSubview:aView];
self.scrollView.contentSize = CGSizeMake(self.scrollView.contentSize.width+aView.frame.size.width
,self.scrollView.contentSize.height);
startX = startX + aView.frame.size.width;
//AppTableView *_appTableView = (AppTableView *) [[self.scrollView subviews] lastObject];
//_appTableView.txtADDRESS.text = _appTable.address;//Fill in the form, no need to write all the form fields code because it's the same way.
NSLog(@"scrollView frame: %@", NSStringFromCGRect(self.scrollView.frame));
NSLog(@"scrollView contentOffset: %@", NSStringFromCGPoint(self.scrollView.contentOffset));
【讨论】:
以上是关于滚动视图仅显示最后添加的子视图的主要内容,如果未能解决你的问题,请参考以下文章