Changing Collection view flow layout - ios

I'm having this issue with switching flow layouts, in the view debugger it changes to the flow layout that I want, however in the simulator and on my phone it's a jumbled mess. I've been looking everywhere for an answer or what the problem is and I can't find a solution. ![left side is what im trying to accomplished and how the view debugger looks, right is the simulator][1]
here is the code for the collectionview and the flow layouts -
(void)setupCollectionView
{
CGRect mainscreen = [[UIScreen mainScreen]bounds];
self.originalLayout = [[UICollectionViewFlowLayout alloc]init];
self.otherLayout = [[UICollectionViewFlowLayout alloc]init];
self.collectionView = [[UICollectionView alloc]initWithFrame:mainscreen collectionViewLayout:self.originalLayout];
self.collectionView.delegate = self;
self.collectionView.dataSource = self;
[self.collectionView registerClass:[MyCollectionViewCell class] forCellWithReuseIdentifier:#"Cell"];
[self.collectionView setPagingEnabled:YES];
[self.originalLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
[self.originalLayout setMinimumInteritemSpacing:0.0f];
[self.originalLayout setMinimumLineSpacing:0.0f];
self.originalLayout.itemSize = CGSizeMake(self.collectionView.frame.size.width, self.collectionView.frame.size.height);
[self.otherLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
[self.otherLayout setMinimumInteritemSpacing:10.0f];
[self.otherLayout setMinimumLineSpacing:10.0f];
self.otherLayout.itemSize = CGSizeMake(self.view.frame.size.width/2, self.view.frame.size.height/2);
[self.view addSubview:self.collectionView];
}
-(void)changeLayout
{
if (self.topBar.hidden == NO) {
self.topBar.hidden = YES;
self.bottomBar.hidden = YES;
}
if (self.swapCollectionViewLayout == NO) {
self.swapCollectionViewLayout = YES;
[self.collectionView setPagingEnabled:NO];
[self.collectionView setCollectionViewLayout:self.otherLayout animated:YES];
[self.collectionView reloadData];
}
else
{
[self.collectionView setCollectionViewLayout:self.originalLayout animated:YES];
self.collectionView.pagingEnabled = YES;
self.swapCollectionViewLayout = NO;
[self.collectionView reloadData];
}
Here is a link to a photo of the issue
https://www.facebook.com/photo.php?fbid=909831825747700&l=340de9351b

Related

how to suspend reloadData of tableview being called?

reloadData is NSLog out after viewDidLayoutSubviews,
I want the tableview call reloadData after GetDataSource , no reloadData on first loading. I even try set _tableView.dataSource = nil; and set it to self in GetDatasource();
But reloadData keeps being called before GetDatasource();
GetDatasource(); is in viewDidload();
viewWillAppar: <ATOMCutstomNavigationController: 0x1476abfc0>
viewDidload
viewWillAppear
viewWillAppear: <ATOMMyFollowViewController: 0x14751b4c0>
viewWillLayoutSubviews
viewDidLayoutSubviews
reloadData
viewWillLayoutSubviews
viewDidLayoutSubviews
viewDidAppear
GetDataSource()
Anyone has any hint?
How can I suspend reloadData or what mistake I have made ?
code In viewDidload:
_myAttentionView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT - NAV_HEIGHT - TAB_HEIGHT)];
self.view = _myAttentionView;
_tableView = [[RefreshTableView alloc] initWithFrame:_myAttentionView.bounds];
[_tableView registerClass:[kfcFollowCell class] forCellReuseIdentifier:CellIdentifier];
_tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
_tableView.estimatedRowHeight = SCREEN_HEIGHT - NAV_HEIGHT - TAB_HEIGHT;
_tableView.delegate = self;
_tableView.psDelegate = self;
_tableView.dataSource = nil;
[_myAttentionView addSubview:_tableView];
_tapMyAttentionGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapMyAttentionGesture:)];
[_tableView addGestureRecognizer:_tapMyAttentionGesture];
_canRefreshFooter = YES;
_dataSource = [NSMutableArray array];
[self firstGetDataSource];
- (void)getDataSource {
Model *sss = [ATOMShowAttention new];
[sss Get:param withBlock:^(NSMutableArray *resultArray, NSError *error) {
if (resultArray.count) {
[_dataSource removeAllObjects];
}
for (ATOMCommonImage *commonImage in resultArray) {
kfcFollowVM * viewModel = [kfcFollowVM new];
[viewModel setViewModelData:commonImage];
[_dataSource addObject:viewModel];
}
if (!_hasSetSource) {
_tableView.dataSource = self;
_hasSetSource = YES;
}
[_tableView reloadData];
[_tableView.header endRefreshing];
}];
}
in view did load
_myAttentionView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT - NAV_HEIGHT - TAB_HEIGHT)];
self.view = _myAttentionView;
_tableView = [[RefreshTableView alloc] initWithFrame:_myAttentionView.bounds];
_dataSource = [NSMutableArray array];//do it HERE..........
[self firstGetDataSource];//do it HERE...........
[_tableView registerClass:[kfcFollowCell class] forCellReuseIdentifier:CellIdentifier];
_tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
_tableView.estimatedRowHeight = SCREEN_HEIGHT - NAV_HEIGHT - TAB_HEIGHT;
_tableView.delegate = self;
_tableView.psDelegate = self;
_tableView.dataSource = nil;
[_myAttentionView addSubview:_tableView];
_tapMyAttentionGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapMyAttentionGesture:)];
[_tableView addGestureRecognizer:_tapMyAttentionGesture];
_canRefreshFooter = YES;

Adding UICollectionViewLayout programmatically issue

I'm trying to implements this library without using storyBoard (first step for implementing this library) , because I'm creating my UIcollectionView programmatically.
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
//self.view.backgroundColor = [UIColor whiteColor];
[self.view addSubview:self.collectionView];
[_collectionView registerNib:[UINib nibWithNibName:#"myCell" bundle:nil] forCellWithReuseIdentifier:#"cell3"];
[_collectionView setBackgroundColor:[UIColor colorWithRed:0.945 green:0.945 blue:0.945 alpha:1] ];
[_collectionView setTransform:CGAffineTransformMakeScale(-1, 1)];
RFQuiltLayout* layout = (id)[_collectionView collectionViewLayout];
layout.direction = UICollectionViewScrollDirectionVertical;
layout.blockPixels = CGSizeMake(100, 100);
}
- (UICollectionView *)collectionView {
if (!_collectionView) {
CGRect collectionViewFrame = self.view.bounds;
collectionViewFrame.size.height -= (self.navigationController.viewControllers.count > 1 ? 0 : (CGRectGetHeight(self.tabBarController.tabBar.bounds))) + 0;
// FMMosaicLayout *mosaicLayout = [[FMMosaicLayout alloc] init];
//// _collectionView = [[UICollectionView alloc] initWithFrame:collectionViewFrame collectionViewLayout:mosaicLayout];
// RFQuiltLayout* layout = (id)[_collectionView collectionViewLayout];
// layout.direction = UICollectionViewScrollDirectionVertical;
// layout.blockPixels = CGSizeMake(100, 100);
_collectionView = [[UICollectionView alloc] initWithFrame:collectionViewFrame collectionViewLayout:[[RFQuiltLayout alloc] init]];
_collectionView.delegate = self;
_collectionView.dataSource = self;
}
return _collectionView;
}
But this didn't worked and nothing is shown in my view (no error and empty view that's all) Also using debugger I've notified that the UICollectionView Method are never called
First of all, your collectionView method is not called because you are using _collectionView instead self.collectionView in your viewDidLoad method. You need to write self for every property to call their setter and getter methods.
Second, if you want to add custom layout without Storyboard of XIB, then you need to set it programmatically:
RFQuiltLayout* layout = [[RFQuiltLayout alloc] init];
layout.direction = UICollectionViewScrollDirectionVertical;
layout.blockPixels = CGSizeMake(100, 100);
self.collectionView.collectionViewLayout = layout;

tableHeaderView UISearchBar not showing

I have added a UISearchBar programatically to my UITableView, it was showing perfectly fine untill I decided to add an offset to my UITableView to hide the UISearchBar when the view is loaded. I would like help displaying it again.
This is what my code looks like.
- (void)viewDidLoad
{
[super viewDidLoad];
self.tableView.contentOffset = CGPointMake(0.0f, 44.0f);
mySearchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 320.0f, 44.0f)];
mySearchBar.autocorrectionType = UITextAutocorrectionTypeNo;
mySearchBar.autocapitalizationType = UITextAutocapitalizationTypeNone;
mySearchBar.keyboardType = UIKeyboardTypeAlphabet;
mySearchBar.delegate = self;
self.tableView.tableHeaderView = mySearchBar;
// Create the search display controller
UISearchDisplayController *searchController = [[UISearchDisplayController alloc] initWithSearchBar:mySearchBar contentsController:self];
searchController.searchResultsDataSource = self;
searchController.searchResultsDelegate = self;
I am not really sure where to go to from here.
This code will work in both iOS6 and iOS7.
Note that in iOS7 you will loose transparency of NavigationBar
if ([self respondsToSelector:#selector(edgesForExtendedLayout)]) {
self.edgesForExtendedLayout = UIRectEdgeNone;
}
[self.tableView setContentOffset:CGPointMake(0, mySearchBar.frame.size.height)];
If you want to save default transparency in iOS7 use this code:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
if ([self respondsToSelector:#selector(edgesForExtendedLayout)]) {
[self.tableView setContentOffset:CGPointMake(0, -20)];
}
else {
[self.tableView setContentOffset:CGPointMake(0, mySearchBar.frame.size.height)];
}
}

iOS 7 UITableView inside a popover

I have a UITableView which has some custom styling. This table view appears in two places in the app, one of which is inside a UIPopoverController. However when the tableview is inside the popover it takes on the default tableview styling as stated in the UI Transition Guide under "Popover".
The problem I have is that there appears to be nowhere to change this behaviour. Regardless of where I try and modify properties of the tableview the view inside the popover doesn't change.
Anyone dealt with this issue before or have any ideas?
Here is the init method of LibraryProductView where I create the table view:
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.sectionOrdering = [NSArray arrayWithObjects:
[NSNumber numberWithInt:LIBRARY_PRODUCT_SECTION_DESCRIPTION],
[NSNumber numberWithInt:LIBRARY_PRODUCT_SECTION_DOCUMENTS],
[NSNumber numberWithInt:LIBRARY_PRODUCT_SECTION_ACTIVE_INGREDIENTS],
[NSNumber numberWithInt:LIBRARY_PRODUCT_SECTION_RELATED_PRODUCTS],
[NSNumber numberWithInt:LIBRARY_PRODUCT_SECTION_RELATED_DOCUMENTS], nil];
self.backgroundColor = [UIColor whiteColor];
self.tableView = [[UITableView alloc] initWithFrame:CGRectInset(self.bounds, 10, 0) style:UITableViewStyleGrouped];
self.tableView.backgroundColor = [UIColor whiteColor];
self.tableView.dataSource = self;
self.tableView.delegate = self;
self.tableView.separatorColor = [UIColor clearColor];
self.tableView.showsVerticalScrollIndicator = NO;
[self addSubview:self.tableView];
}
return self;
}
Here is where the containing view (LibraryProductView) is added to the popover:
- (IBAction)didTouchInformationButton:(id)sender
{
if (_infoPopover != nil && _infoPopover.isPopoverVisible)
{
[_infoPopover dismissPopoverAnimated:YES];
return;
}
CGSize preferredSize = CGSizeMake(600.0f, 500.0f);
LibraryProductViewController* productController = [[[LibraryProductViewController alloc] initWithPreferredSize:preferredSize] autorelease];
productController.filterByMyCompany = NO;
productController.product = _activityInput.product;
UINavigationController* nav = [[[UINavigationController alloc] initWithRootViewController:productController] autorelease];
nav.title = _activityInput.product.name;
RELEASE(_infoPopover);
_infoPopover = [[UIPopoverController alloc] initWithContentViewController:nav];
_infoPopover.popoverContentSize = CGSizeMake(preferredSize.width, preferredSize.height + 46);
[_infoPopover presentPopoverFromRect:_infoButton.frame inView:_infoButton permittedArrowDirections:UIPopoverArrowDirectionLeft animated:YES];
}
The LibraryProductView is created within viewDidLoad method of LibraryProductViewController.
- (void)viewDidLoad
{
[super viewDidLoad];
self.libraryProductView = [[LibraryProductView alloc] initWithFrame:(usingPreferredSize ? CGRectMake(0.0, 0.0, preferredSize.width, preferredSize.height) : self.view.bounds)];
self.libraryProductView.dataSource = self;
self.libraryProductView.delegate = self;
[self.view addSubview:self.libraryProductView];
}
To set properties for the TableView you might do so in
- (NSInteger) numberOfSectionsInTableView:(UITableView *)tableView
{
[tableView setBackgroundColor:[UIColor redcolor]];
[tableView setSeparatorColor: [UIColor blueColor]];
return 1;
}
This, of course, assumes you have set UITableViewDataSource in your .h file

Assertion Failure in UICollectionViewData validateLayoutInRect on ios7

Assertion Failure in UICollectionViewData validateLayoutInRect on iOS7.
I am trying to delete all UICollectionView items, one by one, using a for loop; I posted my code below. I delete the UICollectionView items using deleteItemsAtIndexPaths. It's working perfectly on iOS6, but crashes in iOS7 with this exception:
Assertion Failure in UICollectionViewData validateLayoutInRect
I delete the object from collectionArray then self.collectionView, one by one, using indexPath. When I delete the 4th object its raises Assertion failure on iOS7. Here I am using performBatchUpdates.
Please help me get the proper result in iOS7. Share proper code.
Thanks in advance.
try {
for (int i=count-1; i>=0; i--) {
[self.collectionView performBatchUpdates:^(void){
[collectionArray removeObjectAtIndex:i]; // First delete the item from you model
[self.collectionView deleteItemsAtIndexPaths:#[[NSIndexPath indexPathForRow:i inSection:0]]];
} completion:nil];
[self.collectionView reloadData];
}
}
#catch (NSException *exception) {
}
#finally {
}
I actually got this crash one time not because I was returning zero for a number of sections or items in a section but because I was reusing a flow layout like this for more than 1 collection view:
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
[flowLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
Collection1 = [[UICollectionView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 320.0f, 50.0f) collectionViewLayout:flowLayout];
[Collection1 setDataSource:self];
[Collection1 setDelegate:self];
[self.view addSubview:Collection1];
Collection2 = [[UICollectionView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 320.0f, self.view.frame.size.height) collectionViewLayout:flowLayout];
Collection2.backgroundColor = [UIColor whiteColor];
Instead if I create a new flow layout for each UICollectionView I avoid this crash. Hopefully that might help someone
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
[flowLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
Collection1 = [[UICollectionView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 320.0f, 50.0f) collectionViewLayout:flowLayout];
[Collection1 setDataSource:self];
[Collection1 setDelegate:self];
[self.view Collection1];
UICollectionViewFlowLayout *flowLayoutVert = [[UICollectionViewFlowLayout alloc] init];
[flowLayoutVert setScrollDirection:UICollectionViewScrollDirectionVertical];
Collection2 = [[UICollectionView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 320.0f, self.view.frame.size.height) collectionViewLayout:flowLayoutVert];
in iOS 10 you must disable the prefetchingEnabled:
// Swift
if #available(iOS 10, *) {
collectionView.prefetchingEnabled = false
}
//Obj C
if ([self.collectionView respondsToSelector:#selector(setPrefetchingEnabled:)]) {
self.collectionView.prefetchingEnabled = false;
}
It looks like you probably want to do this:
[self.CollectionView performBatchUpdates:^(void) {
for (int i = count - 1; i >= 0; i--) {
[collectionArray removeObjectAtIndex:i]; // First delete the item from you model
[self.CollectionView deleteItemsAtIndexPaths:#[[NSIndexPath indexPathForRow:i inSection:0]]];
}
} completion:nil];
So that all the updates are performed together. Otherwise you will end up trying to perform several lots of batch updates on top of each other.
You should implement invalidateLayout in your layoutClass and remove all kinds of UICollectionViewLayoutAttributes items in your config.
- (void)invalidateLayout{
[super invalidateLayout];
[self.itemsAttributes removeAllObjects];
}
try to call [yourCollectionView.collectionViewLayout invalidateLayout];
You should implement invalidateLayout in your layout class and remove all kinds of UICollectionViewLayoutAttributes items in your config.
- (void)invalidateLayout{
[super invalidateLayout];
[self.itemsAttributes removeAllObjects];
}
For a better way to implement invalidateLayoutWithContext, see more about UICollectionViewLayoutInvalidationContext.
From Apple Developer documentation:
When implementing a custom layout, you can override this method and use
it to process information provided by a custom invalidation context.
You are not required to provide a custom invalidation context but might
do so if you are able to provide additional properties that can help
optimize layout updates. If you override this method, you must call
super at some point in your implementation.
In my case following delegate was missing:
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
[collectionView.collectionViewLayout invalidateLayout];
return 1;
}

Resources