Как iBooks отображает представление индекса так быстро при просмотре PDF? Или: как нарисовать UIImages на UIScrollView напрямую без UIImageView? - PullRequest
3 голосов
/ 17 декабря 2011

У меня есть пробный PDF на 140 страниц (полная спецификация Adobe PDF, http://wwwimages.adobe.com/www.adobe.com/content/dam/Adobe/en/devnet/pdf/pdfs/adobe_supplement_iso32000.pdf), и я открываю его в iBooks. Затем переключаюсь в режим просмотра в виде индекса (миниатюры). Если я прокручиваю до конца достаточно быстро, я вижу, что Я могу прокручивать быстрее, чем iBooks отображает страницы, но на iPad 2 довольно быстро догоняет. Из этого я узнаю две вещи:

  • Сначала iBooks показывает 140 пустых квадратов правильного размера, а затем заполняет предварительный просмотр.
  • iBooks действительно отображает все предварительные просмотры и сохраняет их в памяти (если я прокручиваю, я не могу обнаружить повторный рендеринг)
  • Я также протестировал другую спецификацию Adobe, которая имеет более 700 страниц: точно такое же поведение! Захватывающий!

Вопрос в том, как они это делают? Я написал код, который получает каждую страницу PDF в виде изображения, добавляет его в UIImageView и добавляет его в представление прокрутки.

Я использую ту же технику и макет, что и iBooks. Он рендерит так же быстро, как iBooks, но потребление памяти безумно, особенно когда прокрутка приложения полностью застревает через некоторое время. Кто-нибудь может указать мне правильное направление? Я уже удалил рендеринг PDF для тестирования, и он действительно быстрый, поэтому я могу связать его с созданием миниатюр.

EDIT: Если из приведенного ниже кода генерация PDF удалена и вместо нее возвращается пустой UIImageView, производительность все равно остается крайне низкой. Поэтому я предполагаю, что UIImageView вызывает проблему. Как я могу нарисовать большие пальцы PDF на моем UIScrollView без требования 140 UIImageViews?

Для тех фирм в Monotouch, вот код, который я использую для отрисовки больших пальцев, возможно, он демонстрирует очевидную слабость:

/// <summary>
        /// Gets the low res page preview of a PDF page. Does a quick image render of the page.
        /// </summary>
        /// <param name="iPage">the number of the page to render</param>
        /// <param name="oTergetRect">the target rect to fit the PDF page into</param>
        /// <returns>
        /// The low res page image view.
        /// </returns>
        public static UIImageView GetLowResPagePreview (CGPDFPage oPdfPage, RectangleF oTargetRect)
        {
            RectangleF oOriginalPdfPageRect = oPdfPage.GetBoxRect (CGPDFBox.Media);
            RectangleF oPdfPageRect = PdfViewerHelpers.RotateRectangle( oPdfPage.GetBoxRect (CGPDFBox.Media), oPdfPage.RotationAngle);
            // If preview is requested for the PDF index view, render a smaller version.
            if (!oTargetRect.IsEmpty)
            {
                // Resize the PDF page so that it fits the target rectangle.
                oPdfPageRect = new RectangleF (new PointF (0, 0), GetFittingBox (oTargetRect.Size, oPdfPageRect.Size));
            }

            // Create a low res image representation of the PDF page to display before the TiledPDFView
            // renders its content.
            int iWidth = Convert.ToInt32 ( oPdfPageRect.Size.Width );
            int iHeight = Convert.ToInt32 ( oPdfPageRect.Size.Height );
            CGColorSpace oColorSpace = CGColorSpace.CreateDeviceRGB();
            CGBitmapContext oContext = new CGBitmapContext(null, iWidth, iHeight, 8, iWidth * 4, oColorSpace, CGImageAlphaInfo.PremultipliedLast);

            // First fill the background with white.
            oContext.SetFillColor (1.0f, 1.0f, 1.0f, 1.0f);
            oContext.FillRect (oOriginalPdfPageRect);
            // Scale the context so that the PDF page is rendered 
            // at the correct size for the zoom level.
            oContext.ConcatCTM ( oPdfPage.GetDrawingTransform ( CGPDFBox.Media, oPdfPageRect, 0, true ) );
            oContext.DrawPDFPage (oPdfPage);
            CGImage oImage = oContext.ToImage();
            UIImage oBackgroundImage = UIImage.FromImage( oImage );
            oContext.Dispose();
            oImage.Dispose ();
            oColorSpace.Dispose ();

            UIImageView oBackgroundImageView = new UIImageView (oBackgroundImage);
            oBackgroundImageView.Frame = new RectangleF (new PointF (0, 0), oPdfPageRect.Size);
            oBackgroundImageView.ContentMode = UIViewContentMode.ScaleToFill;
            oBackgroundImageView.UserInteractionEnabled = false;
            oBackgroundImageView.AutoresizingMask = UIViewAutoresizing.None;
            return oBackgroundImageView;
        }

        internal static RectangleF RotateRectangle ( RectangleF oRect, int iRotationAngle )
        {
            if ( iRotationAngle == 90 || iRotationAngle == 270 )
            {
                return new RectangleF (oRect.X, oRect.Y, oRect.Height, oRect.Width);
            }
            return oRect;
        }

Ответы [ 2 ]

1 голос
/ 17 декабря 2011

Вы не должны использовать 140 UIImageViews !!! используйте только достаточно, чтобы заполнить область, а затем переработайте те, которые больше не отображаются.

Как Apple реализовала UITableView ?? Как вы думаете, они хранят все ячейки таблицы в памяти ??

Посмотрите пример кода PhotoScroller и соответствующее видео WWDC 2010. Я думаю, что это называется «Разработка приложений с scrollViews»

Видео с аналогичным названием WWDC 2011 является продолжением того же трюка повторного просмотра.

Надеюсь, это поможет.

1 голос
/ 17 декабря 2011

Вы проверили размер каждого UIImageView?Возможно, каждая из ваших миниатюр на самом деле имеет размер полной страницы.

Возможно, iBooks не помещает каждую миниатюру в UIImageView?Может быть, приложение использует что-то из CoreAnimation или даже OpenGL ES?

...