yapstudios / YapDatabase

YapDB is a collection/key/value store with a plugin architecture. It's built atop sqlite, for Swift & objective-c developers.
Other
3.35k stars 365 forks source link

Improve wiki section on flexible ranges #133

Open dvkch opened 9 years ago

dvkch commented 9 years ago

Hi,

I have a table view showing chat messages, and replicating the view features of apps like iMessage. I use a flexible section pinned to the bottom, initial length of 20, minLength of 10, maxLength of 300. This filled my tableview with the last 20 messages. My question is: once the user makes it to the top of the tableview how can I update the range somehow to show more?

Since you have information in the wiki about flexible ranges, write how it could apply to iMessage-like apps, I think it would be nice to add the answer inside the wiki page.

Thanks for considering,

Stan

robbiehanson commented 9 years ago

Great idea! I've actually been wanting to make a sample Xcode project to demonstrate this feature. I think both a wiki & sample project would go a long way.

Since I'm slammed with my "day job" right now, I'll just throw out some info for you in case you've been wondering how to go about doing something like this:

When the user scrolls all the way to the top of the tableView:

YapDatabaseViewRangePosition rangePosition = [mappings rangePositionForGroup:conversationId];
if (rangePosition.offsetFromBeginning > 0)
{
    // Load another 50 messages (or however many are left)
    [self increaseRangeLengthBy:MIN(50, rangePosition.offsetFromBeginning)];
}

And then your increaseRange method may look something like this:

- (void)increaseRangeLengthBy:(NSUInteger)count
{
    DDLogTrace(@"increaseRangeLengthBy: %ld", (long)count);

    CGPoint contentOffset = tableView.contentOffset;
    CGFloat contentOffsetDiff = 0;

    // Calculate the contentOffset diff:
    // - the timestamp in cell at index 0 (will be moved to index 'count') may get removed

    if ([mappings numberOfItemsInGroup:conversationId] > 0)
    {
        ChatMessage *message = [self messageAtIndex:0];
        CGFloat cellHeight = [self cellHeightForMessage:message atTableRow:0];

        contentOffsetDiff -= cellHeight;
        [cellHeightCache removeObjectForKey:message.uuid];
    }

    // Update the rangeOptions & mappings

    YapDatabaseViewRangeOptions *rangeOptions = [mappings rangeOptionsForGroup:conversationId];
    rangeOptions = [rangeOptions copyWithNewLength:(rangeOptions.length + count)];

    [mappings setRangeOptions:rangeOptions forGroup:conversationId];

    // Calculate the contentOffset diff:
    // - cells that were added to the tableView

    for (NSUInteger i = 0; i < count; i++)
    {
        ChatMessage *message = [self messageAtIndex:i];
        CGFloat cellHeight = [self cellHeightForMessage:message atTableRow:i];

        contentOffsetDiff += cellHeight;
    }

    // Calculate the contentOffset diff:
    // - the timestamp in cell that was at index 0 (now at index 'count') may have been removed

    if ([mappings numberOfItemsInGroup:conversationId] > count)
    {
        ChatMessage *message = [self messageAtIndex:count];
        CGFloat cellHeight = [self cellHeightForMessage:message atTableRow:count];

        contentOffsetDiff += cellHeight;
    }

    // Update the tableView and update the contentOffset to match what was previously displayed

    contentOffset.y += contentOffsetDiff;

    [tableView reloadData];
    tableView.contentOffset = contentOffset;
    [tableView flashScrollIndicators];
}

Hope this helps.