1
votes

I'm having a problem with UICollectionView with paging enabled. Each cell will cover whole screen, so only 1 cell is visible at a time In the main view I have UICollectionView, and when user swipes to other cell, the navigation title will change accroding to the new cell, this works perfectly when users swipe properly, meaning that when swipe, UICollectionView push whole new cell to the screen However, when users swipe just a little bit to reveal the next cell, then move back to current showing cell, the navigation title is changed, but the content is still current one Does anyone have any idea how to solve this issue? I attached image here for illustration

Thank you very much

Here's my code:

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
    SingleLabViewCollectionScrollCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:collectionCellID forIndexPath:indexPath];
    if (cell == nil){
        NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"SingleLabViewCollectionScrollCell" owner:self options:nil];
        cell = [nib objectAtIndex:0];
    }

    // hide
    [cell.viewMain2 setHidden:YES];
    [cell.viewMain3 setHidden:YES];
    [cell.viewBubble2 setHidden:YES];
    [cell.viewBubble3 setHidden:YES];

    // set text view
    [cell.lblLabText setFont:FONT_AVANT_BOOK(cell.lblLabText.font.pointSize)];
    [cell.textview setScrollEnabled:YES];
    [cell.textview setUserInteractionEnabled:YES];

    NSDictionary *thisDict = [dictLabContentPlist valueForKey:self.titleName];
    if(thisDict != nil){
        NSDictionary *thisDictContent = [thisDict objectForKey:@"Text"];
        NSString *content = [thisDictContent valueForKey:@"Content"];
        NSAttributedString *ctAttri = [self attributedMessageFromMessage:content];
        UITapGestureRecognizer *gesture = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(messageTapped:)];
        [cell.textview addGestureRecognizer:gesture];
        cell.textview.attributedText = ctAttri;
        cell.lblLabText.text = [thisDictContent valueForKey:@"Title"];
    }

    // expand textview according to text
    [cell.textview sizeToFit];
    [cell.textview layoutIfNeeded];
    cell.textview.backgroundColor = [UIColor clearColor];

    CGRect rect = cell.viewDescription.frame;
    rect.size.height = cell.textview.contentSize.height + 40;
    cell.viewDescription.frame = rect;
    [cell.viewMain.layer setCornerRadius:5];
    [cell.viewMain2.layer setCornerRadius:5];
    [cell.viewMain3.layer setCornerRadius:5];
    [cell.viewDescription.layer setCornerRadius:5];

    // set scrollview contentsize
    rect.size.height += 400;
    cell.cellScrollView.contentSize = rect.size;
    [cell.cellScrollView setScrollEnabled:YES];
    [cell.cellScrollView scrollsToTop];

    // set bubble view
    [cell.btnSeeMore addTarget:self action:@selector(expand:) forControlEvents:UIControlEventTouchUpInside];

    // get data for this testID
    for(int i = 0; i < self.arrayTestIDs.count; i++){
        if([self.arrayTestIDs[i] isEqualToString:currentID]){
            currentIndex = i;
            break;
        }
    }

    // load 1st time
    if(firstTimeOpenThisView){
        cell.lblTestName.text = self.arrayTestNames[currentIndex];
        self.titleName = self.arrayTestNames[currentIndex];
        currentID = self.arrayTestIDs[currentIndex];
    }else{
        currentIndex ++;
        // set title name
        cell.lblTestName.text = self.arrayTestNames[indexPath.row];
        self.titleName = self.arrayTestNames[indexPath.row];
        currentID = self.arrayTestIDs[indexPath.row];
    }



    NSMutableDictionary *postData = [[NSMutableDictionary alloc] init];
    [postData setValue:singleton.ACCESS_TOKEN forKey:@"token"];
    [postData setValue:currentID forKey:@"testId"];

    // this is new block that check db when click next
    NSArray *fetchObjects = [singleton loadDataFromTable:@"TestData"];
    // first load data from DB
    isDataExist = false;
    for(NSManagedObject *item in fetchObjects){
        if ([[item valueForKey:@"testID"] isEqualToString:[NSString stringWithFormat:@"%@",currentID]]) {

            dataResponseDict = [item valueForKey:@"data"];
            NSDictionary *commonDict = [dataResponseDict objectForKey:@"Common"];
            cell.lblLeftValue.text = [commonDict valueForKey:@"min"];
            cell.lblLeftLevel.text = [commonDict valueForKey:@"statusBegin"];
            cell.lblUnit.text = [commonDict valueForKey:@"avg"];
            cell.lblRightLevel.text = [commonDict valueForKey:@"statusEnd"];
            cell.lblRightValue.text = [commonDict valueForKey:@"max"];

            dataResponseArray = [dataResponseDict objectForKey:@"LabReport"];

            //kenvu
            NSDictionary *testDict = [dataResponseArray[0] objectForKey:@"Test"];
            NSString *resultStr = [testDict valueForKey:@"result"];
            if([resultStr isKindOfClass:[NSNull class]])
                numberOfRows = 1;
            else
                numberOfRows = 2;

            [self loadDataIntoCell:cell indexPath:indexPath];
            isDataExist=true;

        }
    }

    if(!isDataExist){ // even data exist, still needs to download from server for latest labs data
        clvMain.hidden = YES;
        [self showHud];
        [ws downloadDataWithMethod:@"viewlab" requestMethod:@"POST" data:postData completionBlock:^(NSDictionary *resultDict){

            NSDictionary *tmpDict = [resultDict valueForKey:WS_RESULT_DATA];
            dataResponseDict = [resultDict valueForKey:WS_RESULT_DATA];
            if(dataResponseDict != NULL && ![dataResponseDict isKindOfClass:[NSNull class]] && dataResponseDict.count > 0){
                // remove existing data for this category id
                for(NSManagedObject *item in fetchObjects){
                    if ([[item valueForKey:@"testID"] isEqualToString:[NSString stringWithFormat:@"%@",currentID]]) {
                        [singleton deleteObjectFromDB:item];
                    }
                }
                // save data to db
                NSMutableDictionary *dataToSave = [[NSMutableDictionary alloc]init];
                [dataToSave setObject:[NSString stringWithFormat:@"%@",currentID] forKey:@"testID"];
                [dataToSave setObject:tmpDict forKey:@"data"];
                [singleton saveNewData:dataToSave forTable:@"TestData"];

                // only reload data if no data in DB
                if(!isDataExist){
                    NSDictionary *commonDict = [dataResponseDict objectForKey:@"Common"];
                    cell.lblLeftValue.text = [commonDict valueForKey:@"min"];
                    cell.lblLeftLevel.text = [commonDict valueForKey:@"statusBegin"];
                    cell.lblUnit.text = [commonDict valueForKey:@"avg"];
                    cell.lblRightLevel.text = [commonDict valueForKey:@"statusEnd"];
                    cell.lblRightValue.text = [commonDict valueForKey:@"max"];

                    dataResponseArray = [dataResponseDict objectForKey:@"LabReport"];
                    //kenvu
                    NSDictionary *testDict = [dataResponseArray[0] objectForKey:@"Test"];
                    NSString *resultStr = [testDict valueForKey:@"result"];
                    if([resultStr isKindOfClass:[NSNull class]])
                        numberOfRows = 1;
                    else
                        numberOfRows = 2;

                    [self loadDataIntoCell:cell indexPath:indexPath];
                }

            }else{ // if data == nil, still show static info
                numberOfRows = 1;
                cell.lblLeftValue.text = cell.lblLeftLevel.text = cell.lblUnit.text = cell.lblRightLevel.text = cell.lblRightValue.text = @"";
                [self loadDataIntoCell:cell indexPath:indexPath];
            }
            [self hideHud];
            clvMain.hidden = NO;
        }];
    }


    firstTimeOpenThisView = false;
    return cell;
}

-(void)loadDataIntoCell:(SingleLabViewCollectionScrollCell *)cell indexPath:(NSIndexPath*)indexPath{
    if(indexPath.row == self.arrayTestIDs.count - 1){
        btnNext.hidden = YES;
    }else{
        btnNext.hidden = NO;
    }
    if(indexPath.row == 0){
        btnPrevious.hidden = YES;
    }else{
        btnPrevious.hidden = NO;
    }

    // set navigation title
    titleView.lblTestName.text = self.titleName;
    [titleView.lblTestName setFont:FONT_AVANT_BOOK(cell.lblTestName.font.pointSize)];

    .....
}

enter image description here

3
Show us the code that changes the navigation title when the cell has been swiped. - Robert J. Clegg
I just change the navigation title in cellForItemAtIndexPath - kenvu
Without seeing the code... I'd hazard a guess that as soon as the delegate is about to show the new cell it changes the title in that method. What you can do is put an if statement to check how far the cell is on the screen. If past a point of no return.. set the title. Else don't change the title. - Robert J. Clegg
Would u plz show me how to do that? Because as soon as users start dragging, UICollectionView already call cellForItemAtIndexPath. - kenvu
Post your cellForItemAtIndexPath code in your question. Lets see exactly what it is doing then I can see exactly what needs to be done based off your current code. - Robert J. Clegg

3 Answers

2
votes

I found the solution for this. By using scrollViewDidEndDecelerating, I just add a delay of 0.1 second before getting visibleCells of UICollectionView, and it always return correct visible cell

2
votes

UICollectionView inherits from UIScrollView, which means you can access the contentOffset property of the collection view at any time. If you divide the contentOffset by the width of the collection view cells, you'll derive the index of the cell being shown, so you can figure out which cell is currently visible.

You could also exploit UIScrollViewDelegate's scrollViewDidScroll method - override this, then use the contentOffset to figure out how far the visible cell has moved and trigger the change of the navigation bar text. So you could wait until the current cell has scrolled more that 50% of its width to the next cell before changing - that way, if the user touched up and let the cell "snap" back, the nav bar title wouldn't be altered.

1
votes

Okay, so having a look through Apple's developers documentation shows that there really aren't any delegate methods that will tell you when a cell is visible on screen. My first comment about checking this in cellForItemAtIndexPath isn't technically accurate either. That method should not know where a cell is on screen. Just how to display it.

So my suggestion is try this:

Remove the method call to loadDataIntoCell from cellForItemAtIndexPath.

Next since UICollectionView inherits from UIScrollView, you could use those delegate methods to figure out what to do when scrolling. Here is a rough example:

The method [collectionView visibleCells] will give you all visibleCells in an array. You could use that to change your title:

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
    for (UICollectionViewCell *cell in [collectionView visibleCells]) {
        NSIndexPath *indexPath = [collectionView indexPathForCell:cell];
        NSLog(@"%@",indexPath);
       //Set the navigation title here 
    }
}

You will need to just manage the array and make sure the object in it is the correct one. But this should get you going in the right direction.