Search code examples
iosuitableviewparse-platformpfquery

Change Parse PFQueryTableViewController Cells' Style


I currently use PFQueryTableViewController, and my UITableView looks like a standard TableView I would prefer it look like one rounded rectangle per item in the view. Per answer below, my code is currently:

Cell.m

- (void)layoutSubviews {

    [super layoutSubviews];
    self.imageView.frame = CGRectMake(1,1,69,69);


}
+ (CGFloat)heightForCellWithName:(NSString *)name contentString:(NSString *)content
{
    CGSize contentSize = [content boundingRectWithSize:CGSizeMake([UIScreen mainScreen].bounds.size.width - 20.0, CGFLOAT_MAX)
                                               options:NSStringDrawingUsesLineFragmentOrigin // wordwrap?
                                            attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:13.0f]}
                                               context:nil].size;

        return 10 + 50 + 10 + contentSize.height + 10 + 20 + 10 + 30;
}

PFQueryTableViewController

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
     PFObject *entry = [self.objects objectAtIndex:indexPath.row];
    NSString *commentString = entry[@"Request"];
    NSString *nameString = @"";
    NSLog(@"%@", commentString);
    return [Cell heightForCellWithName:nameString contentString:commentString] + 50;
}

Doing so returns this:

enter image description here

Update

Though the main issues are solved, I noticed that if contentLabel.text is too large, it starts covering up the likeButton and commentButtons.

enter image description here


Solution

  • Your going to have to set the height of the cell dynamically according to the content of the text... I have done this with my project as well and its quite simple... Create a custom UITableviewcell that has a class method +(CGFloat)heightForCellWith:(NSString *)content and return call it when returning the height of the currently visible cell... Heres some sample code

    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
        NSString *commentString = [self.objects[indexPath.row] objectForKey:kPHGlobalChatTextKey];
        PFUser *commentAuthor = (PFUser *)[object objectForKey:kPHGlobalChatUserKey];
        NSString *nameString = @"";
        if (commentAuthor) {
            nameString = [commentAuthor objectForKey:kPHUserDisplayNameKey];
        }
        return [PHChatCell heightForCellWithName:nameString contentString:commentString] + 50;
    }
    

    Basically I am setting the height of the cell according to the text passed in... Heres how the method is implemented:

    + (CGFloat)heightForCellWithName:(NSString *)name contentString:(NSString *)content
    {
        CGSize contentSize = [content boundingRectWithSize:CGSizeMake([UIScreen mainScreen].bounds.size.width - 20.0, CGFLOAT_MAX)
                                                   options:NSStringDrawingUsesLineFragmentOrigin // wordwrap?
                                                attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:13.0f]}
                                                   context:nil].size;
    
    /*
     * header spacing
     * profile picture
     * spacing
     * content
     * spacing
     * like/comment label
     * spacing
     * like/comment button
     */
    
        return 10 + 50 + 10 + contentSize.height + 10 + 20 + 10 + 30;
    }
    

    As you can see, I don't even use the user's name to determine the height of the cell, just the content of the string passed into the method...

    Heres a pic of the result...

    Image

    And yes... when creating the label... you need [label numberOfLines:0] to be set.

    EDIT

    Check out the cell I use for the screenshot... It should clear things up for you and give you a better understand of whats going on... How the labels are laid out and how everything is set...

    Cell url

    There is a method that is not included within the Cell class that calls PHUtility. just comment that out and your good to go... It basically handles how the date should be formatted with respect to the current date.

    Edit

    Where the content labels height is set, change the value to this...

    CGSize contentSize = [content boundingRectWithSize:CGSizeMake([UIScreen mainScreen].bounds.size.width - 40.0, FLT_MAX)
                                               options:NSStringDrawingUsesLineFragmentOrigin
                                            attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:13.0f]}
                                               context:nil].size;
    

    Notice the -40... There are two places you need to change this in, layoutsubviews and the heightForCell class method

    Set the NSFontAttributeName to whatever you like, just make sure your return the same CGSize variable in the heightForCell class method and in layoutsubviews.

    Since the cell view's x value origin is at 10 and the content label is within the cell view where the content labels x origin value is also 10, within the main screen the actual x value is 20, so the width needs to be the width of the main screen -40.

    Also, heres the method I use to format the date a little better...

    #pragma mark - Date formatters
    +(NSDateFormatter *)timeFormatter
    {
        static dispatch_once_t onceMark;
        static NSDateFormatter *formatter = nil;
    
        dispatch_once(&onceMark, ^{
            formatter = [[NSDateFormatter alloc] init];
            [formatter setDateFormat:@"h:mm a"];
        });
    
        return formatter;
    }
    
    +(NSDateFormatter *)formatter
    {
        static dispatch_once_t onceMark;
        static NSDateFormatter *formatter = nil;
    
        dispatch_once(&onceMark, ^{
            formatter = [[NSDateFormatter alloc] init];
            [formatter setDateFormat:@"MMMM d 'at' h:mm a"];
        });
    
        return formatter;
    }
    + (NSString *)relativeDateStringForDate:(NSDate *)date
    {
    
    #ifdef __IPHONE_8_0
        NSCalendarUnit units = NSCalendarUnitDay | NSCalendarUnitWeekOfYear | NSCalendarUnitMonth | NSCalendarUnitYear;
    #else
        NSCalendarUnit units = NSDayCalendarUnit | NSWeekOfYearCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit;
    #endif
    
        // if `date` is before "now" (i.e. in the past) then the components will be positive
        NSDateComponents *components = [[NSCalendar currentCalendar] components:units
                                                                       fromDate:date
                                                                         toDate:[NSDate date]
                                                                        options:0];
    
    
    
        if (components.year > 0) {
            return [[PHUtility formatter] stringFromDate:date];
        } else if (components.month > 0) {
            return [[PHUtility formatter] stringFromDate:date];
        } else if (components.weekOfYear > 0) {
            return [[PHUtility formatter] stringFromDate:date];
        } else if (components.day > 0) {
            return (components.day == 1) ?
            [[PHUtility formatter] stringFromDate:date] :
            [NSString stringWithFormat:@"Yesterday at %@", [[PHUtility timeFormatter] stringFromDate:date]];
        }
    
        if (components.year == 0 && components.month == 0 && components.weekOfYear == 0 && components.day == 0){
            return [NSString stringWithFormat:@"Today at %@", [[PHUtility timeFormatter] stringFromDate:date]];
        }
    
        return nil;
    }
    

    Edit

    To help with your button selection issue, your going to have to RE-SET the UIButtons background color everytime the user has set a prayer...

    Heres how I have implemented the method for the sake of your problem:

    - (void)setLikeStatus:(BOOL)liked {
    
        [self.likeButton setSelected:liked];
    
        if (liked) {
            [self.likeImage setImage:[UIImage imageNamed:@"ButtonLikeSelected.png"]];
            [self.likeButton setBackgroundColor:[UIColor blueColor]];
            return;
        }
    
        [self.likeImage setImage:[UIImage imageNamed:@"ButtonLike.png"]];
        [self.likeButton setBackgroundColor:buttonColor];
    }