- objective-c - iOS 5 : Can you override UIAppearance customisations in specific classes?
- iphone - 如何将 CGFontRef 转换为 UIFont?
- ios - 以编程方式关闭标记的信息窗口 google maps iOS
- ios - Xcode 5 - 尝试验证存档时出现 "No application records were found"
我正在开发一个具有 UICollectionView
的应用程序 - Collection View 的工作是显示来自网络服务的数据。
我正在尝试实现的应用程序的一个功能是使用户能够将此 UICollectionView
的布局从 GridView 更改为表格 View 。
我花了很多时间来完善它,并设法让它发挥作用。但是,存在一些问题。两种布局之间的过渡看起来不太好,有时它会在切换 View 之间中断,我的应用程序会留下一个处于意外状态的 View 。只有当用户连续快速地在网格和表格 View 之间切换(按 changeLayoutButton
)时才会发生这种情况。
所以,显然存在一些问题,我觉得代码有点脆弱。我还需要解决上述问题。
我将从如何实现此 View 开始。
实现
因为我需要两个不同的单元格(grideCell
和 tableViewCell
)来显示不同的东西 - 我决定子类化 UICollectionViewFlowLayout
会更好因为它完成了我需要的一切——我需要做的就是更改单元格大小。
考虑到这一点,我创建了两个子类 UICollectionViewFlowLayout
这是这两个类的样子:
BBTradeFeedTableViewLayout.m
#import "BBTradeFeedTableViewLayout.h"
@implementation BBTradeFeedTableViewLayout
-(id)init
{
self = [super init];
if (self){
self.itemSize = CGSizeMake(320, 80);
self.minimumLineSpacing = 0.1f;
}
return self;
}
@end
BBTradeFeedGridViewLayout.m
#import "BBTradeFeedGridViewLayout.h"
@implementation BBTradeFeedGridViewLayout
-(id)init
{
self = [super init];
if (self){
self.itemSize = CGSizeMake(159, 200);
self.minimumInteritemSpacing = 2;
self.minimumLineSpacing = 3;
}
return self;
}
@end
如您所见,非常简单 - 只需更改单元格大小。
然后在我的 viewControllerA
类中,我像这样实现了 UICollectionView
:创建属性:
@property (strong, nonatomic) BBTradeFeedTableViewLayout *tableViewLayout;
@property (strong, nonatomic) BBTradeFeedGridViewLayout *grideLayout;
在 viewDidLoad
/* Register the cells that need to be loaded for the layouts used */
[self.tradeFeedCollectionView registerNib:[UINib nibWithNibName:@"BBItemTableViewCell" bundle:nil] forCellWithReuseIdentifier:@"TableItemCell"];
[self.tradeFeedCollectionView registerNib:[UINib nibWithNibName:@"BBItemGridViewCell" bundle:nil] forCellWithReuseIdentifier:@"GridItemCell"];
用户点击按钮在布局之间切换:
-(void)changeViewLayoutButtonPressed
我使用 BOOL 来确定哪个布局当前处于事件状态,并基于此我使用以下代码进行切换:
[self.collectionView performBatchUpdates:^{
[self.collectionView.collectionViewLayout invalidateLayout];
[self.collectionView setCollectionViewLayout:self.grideLayout animated:YES];
} completion:^(BOOL finished) {
}];
在cellForItemAtIndexPath
我确定我应该使用哪些单元格(网格或 tableView)并加载数据 - 该代码如下所示:
if (self.gridLayoutActive == NO){
self.switchToTableLayout = NO;
BBItemTableViewCell *tableItemCell = [collectionView dequeueReusableCellWithReuseIdentifier:tableCellIdentifier forIndexPath:indexPath];
if ([self.searchArray count] > 0){
self.switchToTableLayout = NO;
tableItemCell.gridView = NO;
tableItemCell.backgroundColor = [UIColor whiteColor];
tableItemCell.item = self.searchArray[indexPath.row];
}
return tableItemCell;
}else
{
BBItemTableViewCell *gridItemCell= [collectionView dequeueReusableCellWithReuseIdentifier:gridCellIdentifier forIndexPath:indexPath];
if ([self.searchArray count] > 0){
self.switchToTableLayout = YES;
gridItemCell.gridView = YES;
gridItemCell.backgroundColor = [UIColor whiteColor];
gridItemCell.item = self.searchArray[indexPath.row];
}
return gridItemCell;
}
最后在两个单元格类中 - 我只是根据需要使用数据来设置图像/文本。
同样在网格单元格中——图像更大,我删除了我不想要的文本——这是使用两个单元格的主要原因。
我对如何使此 View 在 UI 中看起来更流畅且错误更少感兴趣。我想要的外观就像 eBays iOS 应用程序一样——它们在三种不同的 View 之间切换。我只需要在两个不同的 View 之间切换。
最佳答案
@jrturton 的回答很有帮助,但是除非我遗漏了某些东西,否则它确实会使非常简单的事情变得过于复杂。我将从我们同意的要点开始......
首先,我同意在布局转换开始时禁用用户交互并在结束时(在完成 block 中)使用 [[UIApplication sharedApplication] begin/endIgnoringInteractionEvents]
重新启用的方法- 这比尝试取消正在进行的过渡动画并立即从当前状态开始反向过渡要好得多。
此外,我非常同意为每个布局使用相同单元格类的建议。在 viewDidLoad
中注册一个单元格类,并简化您的 collectionView:cellForItemAtIndexPath:
方法以仅出列一个单元格并设置其数据:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
BBItemCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellID forIndexPath:indexPath];
if ([self.searchArray count] > 0) {
cell.backgroundColor = [UIColor whiteColor];
cell.item = self.searchArray[indexPath.row];
}
return cell;
}
(请注意,单元格本身(除了特殊情况外)不应该知道与当前正在使用的布局、布局是否正在过渡或当前过渡进度有关的任何事情)
然后当您调用 setCollectionViewLayout:animated:completion:
时, Collection View 不需要重新加载任何新的单元格,它只是设置一个动画 block 来更改每个单元格的布局属性(您不需要不需要从 performBatchUpdates:
block 中调用此方法,也不需要手动使布局无效)。
但是正如所指出的,您会注意到单元格的 subview 会立即跳转到它们新布局的框架。解决方案是在更新布局属性时简单地强制立即布局单元格 subview :
- (void)applyLayoutAttributes:(UICollectionViewLayoutAttributes *)layoutAttributes
{
[super applyLayoutAttributes:layoutAttributes];
[self layoutIfNeeded];
}
(无需为过渡创建特殊的布局属性)
为什么会这样?当 Collection View 更改布局时,applyLayoutAttributes:
会为每个单元格调用,因为 Collection View 正在为该转换设置动画 block 。但是单元格 subview 的布局并没有立即完成——它被推迟到稍后的运行循环——导致实际的 subview 布局更改没有被合并到动画 block 中,所以 subview 立即跳转到它们的最终位置。调用 layoutIfNeeded
意味着我们告诉单元格我们希望 subview 布局立即发生,所以布局是在动画 block 内完成的, subview 的帧是动画的连同细胞本身。
的确,使用标准的 setCollectionViewLayout:...
API 确实会限制对动画时间的控制。如果你想应用自定义缓动动画曲线,那么解决方案如 TLLayoutTransitioning
演示一种利用交互式 UICollectionViewTransitionLayout
对象来控制动画时间的简便方法。但是,只要只需要 subview 的线性动画,我认为大多数人都会对默认动画感到满意,尤其是考虑到实现它的单行简单性。
郑重声明,我本人并不热衷于缺乏对动画的控制,因此实现了类似于 TLLayoutTransitioning
的东西。如果这也适用于你,那么请忽略我对@jrturton 的严厉批评,否则他的回答会很好,并查看使用计时器实现的TLLayoutTransitioning
或UICollectionViewTransitionLayout
:)
关于ios - 完善 UICollectionView 布局转换中的 subview 大小调整,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23564453/
我在自定义表格单元格中长按时添加 subview ,但是当我滚动表格时, subview 消失。 p> 我应该怎么做,以便当我向后滚动时,该 subview 仍然显示/出现在该单元格上,或者换句话说,
如何遍历 UIView 的所有 subview ,以及它们的 subview 和它们的 subview ? 最佳答案 使用递归: // UIView+HierarchyLogging.h @inter
如果我有 contentView 和 2 个 subview 。我想根据subviewB居中subviewA subviewA 和 subviewB 有相同的父 View 。 这就是我现在正在做的,将
我想向 self.view 添加一个覆盖整个区域的 subview (如调光 View )。但在它下面,有一些 View 我不希望受到添加的 subview 的影响(我不希望这些 View 具有变暗的
我正在尝试向 UITabBar 添加 subview ,它应该位于其他 UITabBar subview 之后。 我在 UITabBarController 的子类中添加了这样的 subview :
图像描述了我必须将这种 subview 添加到我现有的单元格中,并且在多次单击“添加”图标时还要添加相同的 subview 。 我在添加 subview 时遇到困难。如果有人能为我提供处理此结构的正确
我添加了一个 subview ,如下所示: func showPlayerView2() { self.view.frame = CGRect(x: 0, y: 0, width: view.
我的问题是关于 UIView/CALayer: Transform triggers layoutSubviews in superview 据报道,来自苹果的 TSI 回复: Generally,
我试图为我的主视图创建一个辅助 View 。这个 subview 需要很小的高度,它需要适合另一个带有标签的大 UIView。 问题是当我使用 UIView addSubview 时,第三个 UIVi
我正在尝试淡出整个 View ,但只有一个特定的 subview , 这将强调 subview更清晰的外观。假设 self.view 有 5 textfields和 2 UIView如subviews
我确信我在这里错过了一些愚蠢的东西,但我有 mainView、subviewA 和 subviewB。我试图将 subviewB 添加到 subviewA 并将其锚定在 subviewA 内部,但是它
我有一个包含 3 个 subview 的 View ,分别称为 view A、view B、view C。 当我删除 subview 时,意味着我需要自动设置边距以进行调整。 当我删除 view A
我有两个加载的 subview 。一个是位于 View Controller 内部的选项卡栏,它很早就加载,第二个是按下选项卡栏项目时出现的 View 。 但是,当添加此 subview 时,它会加载
在 iOS 应用中,我在主视图中添加了一个 subview : [self.view addSubview:firstUIImageSubview]; 但是在 subview 类 firstUIIma
我正在制作一个球程序,您可以通过长按手势将球 UIView subview 添加到 super View 。点击 View 会将其从父 View 中移除。 添加所有 View 效果很好,重新添加 Vi
我使用以下代码在单击按钮时将日期选择器 View 添加到我的应用程序主视图。 - (IBAction)CalenderButton_Click:(id)sender { // code to add
我正在努力向 View 添加 subview 。进度变量在其 View Controller 的 viewDidLoad() 中设置。 progressView frame size 设置正确,只是添
这是我的代码 var button = [UIButton?](count:3, repeatedValue: UIButton()) for i in 0...2{
我有一个 UIViewController,里面有几个不同的 UIView subview 。当用户调用某个 Action 时,我手动更改每个的大小、比例和位置。我想更新其中一个 UILabel( s
我的屏幕有一个主视图模型。它由 2 个 subview 模型组成。 其中一个负责注册部分。其中一个处理登录部分。其中一个负责处理菜单部分(如果经过身份验证,可以显示哪些菜单项,以及“欢迎“用户名”类型
我是一名优秀的程序员,十分优秀!