21 February 2017

Last week: Dynamic cell's height

I’m currently working on an iOS app which has an UICollectionView with different cells, and one of those has inside an UIWebView. Such, renders HTML returned from an API and, by design specs., the container cell must grow to accommodate the final web page loaded (similar to what Medium's app does when you tap on an article).

My question was: how can I achieve such dynamic growth? By one side, is how we gather the final HTML document’s height, where this simple JavaScript snippet returns exactly that:

var actualHeight = WebView.EvaluateJavascript("document.body.scrollHeight");

(You’ll need to execute it just before the DOM is loaded, where UIWebView.LoadFinished is pretty handy.)

By the other one, how do I tell back the UICollectionView that specific cells need more vertical space? Looking through Google I found out a few articles and StackOverflow questions which touch this and, don’t know where, found what I finally implemented: the atrezzo cell technique (the “atrezzo” thing is mine).

 

Títeres

 

The idea is as follows: why don’t we create an atrezzo cell -one which never gets actually added to the collection view- just for computing its size depending on its content? That way, asynchronously we’ll get the final height (through above JavaScript) and ask the collection view to reload just that item. Something like this -in your UICollectionViewSource:

[Export("collectionView:layout:sizeForItemAtIndexPath:")]
public virtual CGSize SizeForItemAtIndexPath(UICollectionView collectionView, 
                                             UICollectionViewLayout layout, 
                                             NSIndexPath indexPath)
{
    [...]

    if (_webViewHeight == 0)
    {
        if (_atrezzoCell == null)
        {
            _atrezzoCell = NSBundle.MainBundle.LoadNib(nameof(WebViewCell), 
                this, null)
                .GetItem(0);

            _atrezzoCell.HeightMeasured += (sender, e) =>
            {
                _webViewHeight = e.Height;

                ReloadItemAction(indexPath);
            };
        }

        var item = GetItemAt(indexPath);

        _atrezzoCell.Refresh(item);
        _atrezzoCell.SetNeedsLayout();
        _atrezzoCell.LayoutIfNeeded();

        size = _atrezzoCell.ContentView.SystemLayoutSizeFittingSize(
            UIView.UILayoutFittingCompressedSize);

        _previousItemHeight = size.Height;

        size.Width = collectionView.Frame.Width;
    }
    else
        size = new CGSize(collectionView.Frame.Width, 
            _previousItemHeight + _webViewHeight);

    [...]

    return size;
}

I implemented this back in December and last week had a similar task but without involving UIWebView. Our workmate Oriol made a simple yet powerful approach without needed those atrezzos so, finally, this time I backed on his solution. I hope this servers as a poke to him to write how he sorted that out which, for sure, will be useful for others as well.


Source Url: http://marcoscobena.com/#/last-week-dynamic-cells-height

Related

0 ( 0 reviews)

Post a Comment