6

I have a UICollectionView with 5 sections, some sections have data and some sections (in my code it is section 2) doesn't have (it depend on sever)
Therefore, I want to display a label ("No item") in the selection that doesn't data.

However, I can find any idea to do that, I hope anyone can give me some suggestion or instruction to achieve it.
I would really appreciate any help

Here is my code for intergrade sections

-(UICollectionReusableView *) collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath{

        FriendsFanLevelHeaderView *headerView = (FriendsFanLevelHeaderView *)[self.collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"FanLevelHeader" forIndexPath:indexPath];

            switch (indexPath.section) {
                case 0:
                    [headerView.lblFanLevelTitle setText:@"Gold"];
                    break;
                case 1:
                    [headerView.lblFanLevelTitle setText:@"Silver"];
                    break;
                case 2:
                    [headerView.lblFanLevelTitle setText:@"Bronze"];
                    break;
                case 3:
                    [headerView.lblFanLevelTitle setText:@"Green"];
                    break;
                case 4:
                    [headerView.lblFanLevelTitle setText:@"Other"];
                    break;
                default:
                    break;
            }

            return headerView;
 }


- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
    switch (section) {
        case 0:
            return 3;
        case 1:
            return 0; // it doesn't have any item
        case 2:
            return 2;
        case 3:
            return 3;
        case 4:
            return 5;
        default:
            return 0;
    }
}

- (FriendsCollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
        FriendsCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"FriendsCollectionViewCell" forIndexPath:indexPath];

        [cell.lblFriendBand setText:@"Band: White Mash  "];
        [cell.lblFriendGenre setText:@"Freestyle house,  House,  Freestyle music,"];
        [cell.lblFriendECScore setText:@"EC score: 79"];

        return cell;
}

enter image description here

============================================

HERE IS WHAT I WANT

enter image description here

Linh
  • 57,942
  • 23
  • 262
  • 279

6 Answers6

4

Let's assume that you have your data (items) for each section in a NSArray.

So you have the goldSectionItems array, silverSectionItems array, bronzeSectionItems array, greenSectionItems array and otherSectionItems array.

What you want to do is:

  1. when you have some items in the section you want to display them
  2. when you have no items in the section you want to display "No item"

In case 1, you want to indicate to the collection view the number of items you have in your section, using your array that contains your items.

In case 2, you want to indicate to the collection view that you have 1 item, which will be the "No item" cell.

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
    switch (section) {
        case 0:
            return MAX(1, goldSectionItems.count);
        case 1:
            // return at least 1 when you have no items from the server.
            // When you do not have any items in
            // you NSArray then you return 1, otherwise you return
            // the number of items in your array
            return MAX(1, silverSectionItems.count);
        case 2:
            return MAX(1, bronzeSectionItems.count);
        case 3:
            return MAX(1, greenSectionItems.count);
        case 4:
            return MAX(1, otherSectionItems.count);
        default:
            return 0;
    }
}

Note: MAX will return the maximum value between its two operands. For example if your silverSectionItems array is empty then the count property will return 0, so the MAX(1, 0) will return 1. If your silverSectionItems is not empty count will return N (where N>1) so the MAX(1, N) will return N.

Then in your -collectionView:cellForItemAtIndexPath: you want to check in which case you are:

If you are in case 1 you want a cell that displays normal content.

If you are in case 2 you want a cell that displays "No item".

- (FriendsCollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
    FriendsCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"FriendsCollectionViewCell" forIndexPath:indexPath];
    // get the array that contains the items for your indexPath
    NSArray *items = [self itemArrayForIndexPath:indexPath];

    // case 2
    // if the section does not have any items then set up the
    // cell to display "No item" 
    if (items.count == 0) {
        [cell.lblFriendBand setText:@"No item"];
        [cell.lblFriendGenre setText:@""];
        [cell.lblFriendECScore setText:@""];
    }
    // case 1
    // setup the cell with your items
    else {
        // get you item here and set up the cell with your content
        // Item *item = items[indexPath.item];
        [cell.lblFriendBand setText:@"Band: White Mash  "];
        [cell.lblFriendGenre setText:@"Freestyle house,  House,  Freestyle music,"];
        [cell.lblFriendECScore setText:@"EC score: 79"];
    }

    return cell;
}

// return array for the corresponding indexPath
- (NSArray *)itemArrayForIndexPath:(NSIndexPath *)indexPath {
    switch (indexPath.section) {
        case 0:
            return goldSectionItems;
        case 1:
            return silverSectionItems;
        case 2:
            return bronzeSectionItems;
        case 3:
            return greenSectionItems;
        case 4:
            return otherSectionItems;
        default:
            return nil;
    }
}

-(UICollectionReusableView *) collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath{

    FriendsFanLevelHeaderView *headerView = (FriendsFanLevelHeaderView *)[self.collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"FanLevelHeader" forIndexPath:indexPath];

        switch (indexPath.section) {
            case 0:
                [headerView.lblFanLevelTitle setText:@"Gold"];
                break;
            case 1:
                [headerView.lblFanLevelTitle setText:@"Silver"];
                break;
            case 2:
                [headerView.lblFanLevelTitle setText:@"Bronze"];
                break;
            case 3:
                [headerView.lblFanLevelTitle setText:@"Green"];
                break;
            case 4:
                [headerView.lblFanLevelTitle setText:@"Other"];
                break;
            default:
                break;
        }

        return headerView;
}

Feel to ask anything you do not understand.

averello
  • 114
  • 1
  • 5
  • thank you for giving me a nice idea, it solved my problem. However I think if I am using sections footer for display label "No item" as Kuba recommend , my code will more clearly – Linh Jan 19 '16 at 03:02
2

You need to use UICollectionElementKindSectionFooter the same way you use section header. I build simple CollectionView example to show what i have in mind:

enter image description here

So basically what I do is create universal footer and hide it when there is a content to fill the cells:

The basic example is:

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForFooterInSection:(NSInteger)section {
    NSArray *sectionContent = self.collectionViewData[section][COLLECTIONVIEW_CONTENT_KEY];
    return ([sectionContent count] > 0) ? CGSizeMake(0, 0) : CGSizeMake(collectionView.frame.size.width, FOOTER_HEIGHT);
  }

Where my self.collectionViewData is an NSArray of NSDictionary.

But to avoid breaking constraints i highly recomment to create separate xib for footer and apply both for your collectionView.

-(UICollectionReusableView *) collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath{

NSArray *sectionContent = self.collectionViewData[indexPath.section][COLLECTIONVIEW_CONTENT_KEY];

if([kind isEqualToString:UICollectionElementKindSectionHeader]) {
    UICollectionReusableView *headerView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"header" forIndexPath:indexPath];
    return headerView;
} else {
    NSString *footerIdentifier = ([sectionContent count] > 0) ? @"blankFooter" : @"footer";
    UICollectionReusableView *footerView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:footerIdentifier forIndexPath:indexPath];
    return footerView;
}
}

You can download example project here to have a look: https://bitbucket.org/Kettu/so_34526276

Bitbucket to this repository

Jakub
  • 13,712
  • 17
  • 82
  • 139
  • It is a good solution and I solved my problem. But please update the code to your example project, your example project now doesn't show anything – Linh Jan 19 '16 at 02:56
  • Sorry I forgot to push changes, I updated the repository. – Jakub Jan 20 '16 at 22:14
1

I have did this in one my project but i use collectionView in each section of collection view for scroll horizontal to each section like below . might you get some idea

if (row==0)
{
    lblCoupons = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, collectionVCategory.frame.size.width, 50)];
  //  lblCoupons.tag = 99;
    [lblCoupons setText:@"No Coupons Found!"];
    [lblCoupons setTextAlignment:NSTextAlignmentCenter];
    [lblCoupons setFont:[UIFont systemFontOfSize:15]];
    [collctnView.backgroundView layoutSubviews];
    collctnView.backgroundView = lblCoupons;
}
else
{
    [lblCoupons removeFromSuperview];
    //[collectionVCategory.backgroundView removeAllSubviewsOfTag:99];
    collctnView.backgroundView = nil;
}
Jaydeep Patel
  • 1,699
  • 17
  • 30
  • 1
    Now, I don't use tableview in each section of CollectionView. If I can not found any solution , I will consider the way to add TableView to each sections of CollectionView. Thank you for nice suggestion – Linh Dec 30 '15 at 09:23
  • In my case, I think when I add TableView for each section of UICollectionView, my layout is more complex :(. Too more code for display a simple component – Linh Dec 30 '15 at 09:25
  • actually in my case each section have multiple(0 to 100 or more) item to display and i have to have to scroll each section so i used tableview there – Jaydeep Patel Dec 30 '15 at 09:30
  • sorry it was collection view in each section – Jaydeep Patel Dec 30 '15 at 09:33
1

If u r getting data in such a format that the every index of the array itself contains one complete array. Like recipeImages contains 3 objects which are itself are arrays.

NSArray *mainDishImages = [NSArray arrayWithObjects:@"egg_benedict.jpg", @"full_breakfast.jpg", @"ham_and_cheese_panini.jpg", @"ham_and_egg_sandwich.jpg", nil];

NSArray *drinkDessertImages = [NSArray arrayWithObjects:@"green_tea.jpg", @"starbucks_coffee.jpg", @"white_chocolate_donut.jpg", nil];

NSArray *sideDishes = [NSArray arrayWithObjects:@"green_tea.jpg", @"starbucks_coffee.jpg", @"white_chocolate_donut.jpg", nil];

recipeImages = [NSArray arrayWithObjects:mainDishImages, drinkDessertImages, sideDishes ,nil];

you can give number of sections in collection view as:

- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return [recipeImages count];
}

and number of rows in each section as

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
return [[recipeImages objectAtIndex:section] count];
}

If your data is in such a format you can check the if there are any data in the specified section by getting the array at specific section.

-(UICollectionReusableView *) collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath{

NSArray *temp_arr_gold = [recipeImages objectAtIndex:0];
NSArray *temp_arr_silver = [recipeImages objectAtIndex:1];
NSArray *temp_arr_bronze = [recipeImages objectAtIndex:2];
NSArray *temp_arr_green = [recipeImages objectAtIndex:3];
NSArray *temp_arr_other = [recipeImages objectAtIndex:4];
FriendsFanLevelHeaderView *headerView = (FriendsFanLevelHeaderView *)[self.collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"FanLevelHeader" forIndexPath:indexPath];

switch (indexPath.section) {
    case 0:
        if (temp_arr_gold.count !=0)
        {
            [headerView.lblFanLevelTitle setText:@"Gold"];
        }
        else
        {
            [headerView.lblFanLevelTitle setText:@"No item"];
        }
        break;
    case 1:
        if (temp_arr_silver.count !=0)
        {
            [headerView.lblFanLevelTitle setText:@"Silver"];
        }
        else
        {
            [headerView.lblFanLevelTitle setText:@"No item"];
        }
        break;
    case 2:
        if (temp_arr_bronze.count !=0)
        {
            [headerView.lblFanLevelTitle setText:@"Bronze"];
        }
        else
        {
            [headerView.lblFanLevelTitle setText:@"No item"];
        }
        break;
    case 3:
        if (temp_arr_green.count !=0)
        {
            [headerView.lblFanLevelTitle setText:@"Green"];
        }
        else
        {
            [headerView.lblFanLevelTitle setText:@"No item"];
        }
        break;
    case 4:
        if (temp_arr_other.count !=0)
        {
            [headerView.lblFanLevelTitle setText:@"Other"];
        }
        else
        {
            [headerView.lblFanLevelTitle setText:@"No item"];
        }
        break;
    default:
        break;
}

return headerView;

}

Hope it helps.. Happy Coding.

luckyShubhra
  • 2,731
  • 1
  • 12
  • 19
  • sorry, may be you miss somthing. with your code, you will change the section title. not showing the "No item" beetween 2 section – Linh Dec 30 '15 at 10:43
  • Where have defined that label("Friend not found").. ?? Have you created IBOutlet for the same..?? – luckyShubhra Dec 30 '15 at 12:28
1

One way could be creation of another cell "No Item" in collectionView

Then in collectionView:numberOfItemsInSection: always return minimum 1 for making room for "No Item" cell.

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {

    // TODO: check dataSource array for "NO FRIENDS"
    // TODO: If true 
    // NoFriendsCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"NoFriendsCollectionViewCell" forIndexPath:indexPath];
    // cell.label.text = "No Item";
    // return cell;
    // else

    FriendsCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"FriendsCollectionViewCell" forIndexPath:indexPath];

    [cell.lblFriendBand setText:@"Band: White Mash  "];
    [cell.lblFriendGenre setText:@"Freestyle house,  House,  Freestyle music,"];
    [cell.lblFriendECScore setText:@"EC score: 79"];

    return cell;
}
Warif Akhand Rishi
  • 23,920
  • 8
  • 80
  • 107
1

if you want to show the "no item" label, then you need to return 1 in the numberOfItemsInSection, and then when the collectionview ask for the cell, depends on the actual counts of your item, you could return either the "no item" label or the actual first item in your collection when the indexpath's row number is 1.

Allen
  • 6,505
  • 16
  • 19
  • thank you for giving me a nice idea, it solved my problem. However I think if I am using sections footer for display label "No item" as Kuba recommend , my code will more clearly – Linh Jan 19 '16 at 03:02