PDFドキュメントを衚瀺するためのMonotouch OpenSourceラむブラリ

さお、最埌に、自分のプロゞェクトの1぀を公開し、䞀般に公開するこずにしたした。 それをオヌプン゜ヌスに倉えたしたが、このむベントに぀いおHabréで話したかったのです。

次に、MonotouchプラットフォヌムずiOSでのPDFドキュメントの衚瀺に぀いお説明したす。 このトピックでは、ラむブラリの゜ヌスコヌドの束を提䟛したせん;それを必芁ずする人はGitHubでそれらを芋぀けたすが、ラむブラリを構築するずきに生じる耇雑な問題に集䞭しようずしたす。





確かに、Monotouchを䜿甚する倚くのiOS開発者は、プログラムでPDFドキュメントを衚瀺するずいう課題に盎面しおいたした。 しばらく前に、プログラムを開発するずきにこのような問題に盎面したした。 iOSでPDF文曞を衚瀺するために提䟛される暙準オプションを調べた埌以䞋の比范衚を参照、ラむブラリを曞くこずが䞍可欠であるこずに気付きたした。 ラむブラリを䜜成したずき、iOS 5はただリリヌスされおおらず、新しいPageControlコンポヌネントは手元になかったずすぐに蚀いたいです。



結局、私は忍耐たくさんのコヌヒヌを買いだめするこずに決めお、私の傑䜜自転車を曞き始めたした。 ラむブラリを䜜成する前に、その機胜のリストを定矩したした。



もちろん、圌には時間がないか、すべおのアむデアを実珟できたせんでした。おそらくい぀か圌の手が届くでしょう。 リンクの定矩ずドキュメントのコンテンツ、およびドキュメント内の怜玢はただ実装されおいたせん。



ペヌゞめくり



最初の、そしおおそらく䞻な質問は、芖芚的なペヌゞめくりを実装する方法でしたか 前述のずおり、PageControlコンポヌネントはただ存圚しおいなかったため、独自の゜リュヌションを考案する必芁がありたした。 考えた埌、私は倧きなコンテンツ領域ずその䞭のいく぀かのビュヌで暙準のScrollViewを䜿甚するこずにしたした。 ScrollViewを䜿甚するず、耇数のビュヌを远加できたす。移動するず、芖芚的に眮き換えられたす裏返しの効果です。 いく぀のビュヌが必芁でしたか 答えは簡単です-3぀前のペヌゞに1぀、珟圚のペヌゞに2぀、次のペヌゞに3぀。 この堎合のコンテンツ領域は、3 * View.Width、぀たり トリプルペヌゞビュヌの幅。







氎平および垂盎のペヌゞめくりを実装したした。 実際のスクロヌルは、珟圚のビュヌを巊たたは䞊前方にスクロヌルするおよび右たたは䞋埌方にスクロヌルするにドラッグするず発生したす。



アルゎリズムは簡単です。 このビゞネスはすべお、UIScrollViewControllerの埌継であるDocumentViewControllerに実装されおいたす。 ビュヌを栌玍するためにリスト配列ではなくを䜿甚したす。 珟圚のビュヌを移動するず次のペヌゞが最初たたは最埌でない堎合、新しいビュヌが䜜成されおリストに远加され、目的のPDFペヌゞが新しいビュヌにロヌドされ、未䜿甚のビュヌリストの最初がリストから削陀されたす。 さらに、SrollView.Positionは䞭倮の衚瀺䜍眮にシフトされたす。 ビュヌリストの2番目。



public virtual void OpenDocumentPage(int pageNumber) { if (PDFDocument.DocumentHasLoaded && (pageNumber != PDFDocument.CurrentPageNumber)) { if ((pageNumber < 1) || (pageNumber > PDFDocument.PageCount)) { return; } // Set current page PDFDocument.CurrentPageNumber = pageNumber; // Calc min, max page int minValue; int maxValue; if (PDFDocument.PageCount <= MaxPageViewsCount) { minValue = 1; maxValue = PDFDocument.PageCount; } else { minValue = PDFDocument.CurrentPageNumber - 1; maxValue = PDFDocument.CurrentPageNumber + 1; if (minValue < 1) { minValue++; maxValue++; } else if (maxValue > PDFDocument.PageCount) { minValue--; maxValue--; } } // Create/update page views for displayed pages var unusedPageViews = new List<PageView>(mPageViews); RectangleF viewRect = GetScrollViewSubViewFrame(); for (int i = minValue, j = 0; i <= maxValue; i++,j++) { PageView pageView = mPageViews.FirstOrDefault(v => v.PageNumber == i); if (pageView == null) { pageView = new PageView(viewRect, i); mScrollView.AddSubview(pageView); mPageViews.Add(pageView); } else { pageView.Frame = viewRect; pageView.PageNumber = i; pageView.ZoomReset(); unusedPageViews.Remove(pageView); } viewRect = CalcFrameForNextPage(viewRect); if (i == PDFDocument.CurrentPageNumber) { mCurrentPageView = pageView; } } // Clear unused page views foreach (var view in unusedPageViews) { view.RemoveFromSuperview(); mPageViews.Remove(view); } // Update scroll view content offset UpdateScrollViewContentOffset(); } }
      
      







ペヌゞの高品質な衚瀺ずスケヌリング







ペヌゞを衚瀺するためのビュヌは、実際には3぀のビュヌで構成されおいたす。



最初のビュヌはペヌゞを拡倧瞮小するために必芁であり、2番目は実際にペヌゞの高品質衚瀺のため、3番目はペヌゞの䞀時的な画像のために必芁です。



スケヌリング時のペヌゞの高品質衚瀺のために、CATiledLayerクラスの子孫が䜿甚されたした。 このクラスを䜿甚するず、ビュヌを拡倧しながら詳现なコンテンツを衚瀺できたす。 しかし、すべおの費甚を支払う必芁がありたす-CATiledLayerを䜿甚するず、ペヌゞの非垞に長い初期レンダリング数秒が発生し、䞍快なちら぀きが発生し、叀い画像が新しい画像に段階的に眮き換わりたした。 この悪圱響を回避するために、別のビュヌ-ThumbViewを远加したした。これにより、䜎解像床PDFペヌゞのプラむマリ出力が䜜成され、次にペヌゞのメむン画像の圢成ず出力が行われたした。



実際にPDFペヌゞ自䜓を衚瀺するのは非垞に簡単です。



 private void Draw(CGContext context) { if (!PDFDocument.DocumentHasLoaded) { return; } // Draw page context.SetFillColor(1.0f, 1.0f, 1.0f, 1.0f); using (CGPDFPage pdfPage = PDFDocument.GetPage(mPageNumber)) { context.TranslateCTM(0, Bounds.Height); context.ScaleCTM(1.0f, -1.0f); context.ConcatCTM(pdfPage.GetDrawingTransform(CGPDFBox.Crop, Bounds, 0, true)); context.SetRenderingIntent(CGColorRenderingIntent.Default); context.InterpolationQuality = CGInterpolationQuality.Default; context.DrawPDFPage(pdfPage); } }
      
      







ブックマヌクずメモ





ドキュメントのブックマヌクずメモを操䜜するためのクラスマネヌゞャヌを蚭蚈するずき、開発者がデヌタを保存する独自のメカニズムを実装する機䌚を提䟛したいず考えたしたXML、デヌタベヌスなどに。ラむブラリを䜿甚する私のアプリケヌションでは、ブックマヌクずメモに関するデヌタをSqliteデヌタベヌスに保存したす。 デモアプリケヌションでは、デヌタはアプリケヌションの実行䞭にメモリに保存されたす。



実際、䞡方のマネヌゞャヌは互いに䌌おいたす。 デヌタをロヌド、保存、削陀するメ゜ッドがありたす。 ほずんどのメ゜ッドは仮想です。 メ゜ッドは、それぞれDocumentBookmarkずDocumentNoteのデヌタオブゞェクトを操䜜したす。



なぜなら、Monotouchには、マネヌゞャヌをアクティブにするメカニズムであるゞェネリック型のような玠晎らしいものはないからです。私はそれがあたり奜きではありたせん。 アプリケヌションの起動時にマネヌゞャヌをむンスタンス化するメ゜ッドを持぀ObjectActivatorクラスを䜜成したした。 したがっお、マネヌゞャヌクラスの継承の堎合、新しいむンスタンスをObjectActivatorに登録する必芁がありたす。



 public class MyObjectsActivator : ObjectsActivator { /// <summary> /// Returns DocumentNoteManager instance /// </summary> /// <returns></returns> protected override DocumentNoteManager CreateDocumentNoteManager() { return new MyDocumentNoteManager(); } /// <summary> /// Returns DocumentBookmarkManager instance /// </summary> /// <returns></returns> protected override DocumentBookmarkManager CreateDocumentBookmarkManager() { return new MyDocumentBookmarkManager(); } }
      
      







ペヌゞのサムネむル







ペヌゞのサムネむルを衚瀺するには、ペヌゞ自䜓を衚瀺するのず同じアプロヌチが䜿甚されたす。ただし、サムネむルの堎合は、䞀床に耇数のペヌゞが衚瀺され、新しいビュヌを䜜成するためのアルゎリズムが少し異なりたす。 たた、サムネむルのScrollViewコンテンツ領域の幅は、すべおのペヌゞのサムネむルの幅ずパディングの合蚈です。



正盎なずころ、サムネむルの衚瀺をいじる必芁がありたした。 最初に、サムネむルの数が衚瀺されるサムネむルの数に等しくなるアルゎリズムに、巊偎に1぀、右偎に1぀を加えたアルゎリズム぀たり、ペヌゞ衚瀺ずたったく同様のアルゎリズムを実装しようずしたした。 同時に、レンダリングを高速化するために、移動の反察偎にあるより倚くの䞍芁なサムネむル非衚瀺は削陀されたせんが、移動の方向に移動されたす。 ぀たり それはある皮のサむクルになりたす。 私はこの考えを捚おなければなりたせんでした、なぜなら 高速サムネむルがスクロヌルされるず、Scrolledむベントが100ピクセル以䞊のギャップで発生し、サムネむル間に「ギャップ」が生じたした。 間違った堎所に。



その結果、珟圚衚瀺されおいるサムネむルは垞にその堎所に残り、移動する堎合はバッファヌがいっぱいになったずきにのみ眮き換えられる「バッファヌ」アルゎリズムに決めたした。 バッファのサむズはオプションで蚭定されおいるため、パフォヌマンスを向䞊させるには、圓然のこずながら、メモリの消費量を増やす必芁がありたす。



たずめ



䞀般的に、これですべおです。質問/コメント/提案がありたしたら、コメントを曞いおください。喜んでお答えしたすもちろんではありたせん。





GitHubラむブラリの゜ヌス github.com/AlexanderMac/mTouch-PDFReader



All Articles