2016-05-27 23 views
5

私はPdfRendererを使用しようとしていますが、ズームとスクロールを利用できるようにする必要がありますが、Android PdfRendererではズームとスクロールをサポートしていません。PdfRendererズームとスクロールのサポートを実装する方法は?

しかし、私はズームとスクロールのサポートPdfRendererがimageviewを使用してコンテンツを表示するビットマップを使用して実装できると思います。

Google PdfRenderer サンプルでズームとスクロールのサポートを実装する方法は?

PS:私は、Googleが提供している、このPdfRendererサンプル、https://github.com/googlesamples/android-PdfRendererBasic

答えて

3

私は@ yan-yankelevichのアイデアを使用し、Javaでコードを書いています。適切なズームとそれに対応するビットマップサイズの値を見つけることには多くの問題がありました。 PdfRendererはAPI 21+でのみ動作することを忘れないでください。

PDFビットマップfragment_pdf_renderer.xmlとフラグメント:

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:background="@color/white" 
    android:orientation="vertical" 
    tools:context=".PdfRendererFragment"> 

    <ScrollView 
     android:layout_width="match_parent" 
     android:layout_height="0dp" 
     android:layout_weight="1"> 

     <HorizontalScrollView 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content"> 

      <ImageView 
       android:id="@+id/image" 
       android:layout_width="wrap_content" 
       android:layout_height="wrap_content" 
       android:background="@android:color/white" 
       android:contentDescription="@null" /> 
     </HorizontalScrollView> 
    </ScrollView> 

    <LinearLayout 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:background="@color/from_divider_gray" 
     android:gravity="center_vertical" 
     android:orientation="horizontal"> 

     <Button 
      android:id="@+id/previous" 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content" 
      android:layout_weight="1" 
      android:text="@string/previous_page" 
      android:textSize="13sp" /> 

     <Button 
      android:id="@+id/next" 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content" 
      android:layout_weight="1" 
      android:text="@string/next_page" 
      android:textSize="13sp" /> 

     <ImageButton 
      android:id="@+id/zoomout" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:layout_margin="0dp" 
      android:padding="8dp" 
      android:src="@drawable/ic_zoom_out_black_36dp" /> 

     <ImageButton 
      android:id="@+id/zoomin" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:layout_margin="0dp" 
      android:padding="8dp" 
      android:src="@drawable/ic_zoom_in_black_36dp" /> 
    </LinearLayout> 

</LinearLayout> 

enter image description here

PdfRendererFragment

/** 
* This fragment has a big {@ImageView} that shows PDF pages, and 2 
* {@link android.widget.Button}s to move between pages. We use a 
* {@link android.graphics.pdf.PdfRenderer} to render PDF pages as 
* {@link android.graphics.Bitmap}s. 
*/ 
@RequiresApi(Build.VERSION_CODES.LOLLIPOP) 
public class PdfRendererFragment extends Fragment implements View.OnClickListener { 

    /** 
    * Key string for saving the state of current page index. 
    */ 
    private static final String STATE_CURRENT_PAGE_INDEX = "current_page_index"; 

    /** 
    * The filename of the PDF. 
    */ 
    public String FILENAME; 
    public String PURCHASE_ID; 
    public int TICKETS_NUMBER; 

    /** 
    * File descriptor of the PDF. 
    */ 
    private ParcelFileDescriptor mFileDescriptor; 

    /** 
    * {@link android.graphics.pdf.PdfRenderer} to render the PDF. 
    */ 
    private PdfRenderer mPdfRenderer; 

    /** 
    * Page that is currently shown on the screen. 
    */ 
    private PdfRenderer.Page mCurrentPage; 

    /** 
    * {@link android.widget.ImageView} that shows a PDF page as a {@link android.graphics.Bitmap} 
    */ 
    private ImageView mImageView; 

    /** 
    * {@link android.widget.Button} to move to the previous page. 
    */ 
    private Button mButtonPrevious; 
    private ImageView mButtonZoomin; 
    private ImageView mButtonZoomout; 
    private Button mButtonNext; 
    private float currentZoomLevel = 12; 

    /** 
    * PDF page index 
    */ 
    private int mPageIndex; 

    public PdfRendererFragment() { 
    } 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
          Bundle savedInstanceState) { 
     return inflater.inflate(R.layout.fragment_pdf_renderer, container, false); 
    } 

    @Override 
    public void onViewCreated(View view, Bundle savedInstanceState) { 
     super.onViewCreated(view, savedInstanceState); 
     // Retain view references. 
     mImageView = (ImageView) view.findViewById(R.id.image); 
     mButtonPrevious = (Button) view.findViewById(R.id.previous); 
     mButtonNext = (Button) view.findViewById(R.id.next); 
     mButtonZoomin = view.findViewById(R.id.zoomin); 
     mButtonZoomout = view.findViewById(R.id.zoomout); 

     // Bind events. 
     mButtonPrevious.setOnClickListener(this); 
     mButtonNext.setOnClickListener(this); 
     mButtonZoomin.setOnClickListener(this); 
     mButtonZoomout.setOnClickListener(this); 

     mPageIndex = 0; 
     // If there is a savedInstanceState (screen orientations, etc.), we restore the page index. 
     if (null != savedInstanceState) { 
      mPageIndex = savedInstanceState.getInt(STATE_CURRENT_PAGE_INDEX, 0); 
     } 
    } 

    @Override 
    public void onActivityCreated(@Nullable Bundle savedInstanceState) { 
     super.onActivityCreated(savedInstanceState); 
     FILENAME = getActivity().getIntent().getExtras().getString("pdfFilename"); 
     TICKETS_NUMBER = getActivity().getIntent().getExtras().getInt("tickets_number"); 
     PURCHASE_ID = getActivity().getIntent().getExtras().getString("purchaseGuid"); 
    } 

    @Override 
    public void onStart() { 
     super.onStart(); 
     try { 
      openRenderer(getActivity()); 
      showPage(mPageIndex); 
     } catch (IOException e) { 
      e.printStackTrace(); 
      Toast.makeText(getActivity(), getString(R.string.ticket_file_not_found, FILENAME), Toast.LENGTH_SHORT).show(); 
      App app = (App) getActivity().getApplicationContext(); 
      TicketUtil.downloadTicket(app, PURCHASE_ID); 
      getActivity().finish(); 
     } 
    } 

    @Override 
    public void onStop() { 
     try { 
      closeRenderer(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
     super.onStop(); 
    } 

    @Override 
    public void onSaveInstanceState(Bundle outState) { 
     super.onSaveInstanceState(outState); 
     if (null != mCurrentPage) { 
      outState.putInt(STATE_CURRENT_PAGE_INDEX, mCurrentPage.getIndex()); 
     } 
    } 

    /** 
    * Sets up a {@link android.graphics.pdf.PdfRenderer} and related resources. 
    */ 
    private void openRenderer(Context context) throws IOException { 
     // In this sample, we read a PDF from the assets directory. 
     File file = TicketUtil.getTicketFile(context, PURCHASE_ID); 
     if (!file.exists()) { 
      // Since PdfRenderer cannot handle the compressed asset file directly, we copy it into 
      // the cache directory. 
      InputStream asset = context.getAssets().open(FILENAME); 
      FileOutputStream output = new FileOutputStream(file); 
      final byte[] buffer = new byte[1024]; 
      int size; 
      while ((size = asset.read(buffer)) != -1) { 
       output.write(buffer, 0, size); 
      } 
      asset.close(); 
      output.close(); 
     } 
     mFileDescriptor = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY); 
     // This is the PdfRenderer we use to render the PDF. 
     if (mFileDescriptor != null) { 
      mPdfRenderer = new PdfRenderer(mFileDescriptor); 
     } 
    } 

    /** 
    * Closes the {@link android.graphics.pdf.PdfRenderer} and related resources. 
    * 
    * @throws java.io.IOException When the PDF file cannot be closed. 
    */ 
    private void closeRenderer() throws IOException { 
     if (null != mCurrentPage) { 
      mCurrentPage.close(); 
      mCurrentPage = null; 
     } 
     if (null != mPdfRenderer) { 
      mPdfRenderer.close(); 
     } 
     if (null != mFileDescriptor) { 
      mFileDescriptor.close(); 
     } 
    } 

    /** 
    * Zoom level for zoom matrix depends on screen density (dpiAdjustedZoomLevel), but width and height of bitmap depends only on pixel size and don't depend on DPI 
    * Shows the specified page of PDF to the screen. 
    * 
    * @param index The page index. 
    */ 
    private void showPage(int index) { 
     if (mPdfRenderer.getPageCount() <= index) { 
      return; 
     } 
     // Make sure to close the current page before opening another one. 
     if (null != mCurrentPage) { 
      mCurrentPage.close(); 
     } 
     // Use `openPage` to open a specific page in PDF. 
     mCurrentPage = mPdfRenderer.openPage(index); 
     // Important: the destination bitmap must be ARGB (not RGB). 
     int newWidth = (int) (getResources().getDisplayMetrics().widthPixels * mCurrentPage.getWidth()/72 * currentZoomLevel/40); 
     int newHeight = (int) (getResources().getDisplayMetrics().heightPixels * mCurrentPage.getHeight()/72 * currentZoomLevel/64); 
     Bitmap bitmap = Bitmap.createBitmap(
       newWidth, 
       newHeight, 
       Bitmap.Config.ARGB_8888); 
     Matrix matrix = new Matrix(); 

     float dpiAdjustedZoomLevel = currentZoomLevel * DisplayMetrics.DENSITY_MEDIUM/getResources().getDisplayMetrics().densityDpi; 
     matrix.setScale(dpiAdjustedZoomLevel, dpiAdjustedZoomLevel); 
//  Toast.makeText(getActivity(), "width " + String.valueOf(newWidth) + " widthPixels " + getResources().getDisplayMetrics().widthPixels, Toast.LENGTH_LONG).show(); 
//  matrix.postTranslate(-rect.left/mCurrentPage.getWidth(), -rect.top/mCurrentPage.getHeight()); 

     // Here, we render the page onto the Bitmap. 
     // To render a portion of the page, use the second and third parameter. Pass nulls to get 
     // the default result. 
     // Pass either RENDER_MODE_FOR_DISPLAY or RENDER_MODE_FOR_PRINT for the last parameter. 
     mCurrentPage.render(bitmap, null, matrix, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY); 
     // We are ready to show the Bitmap to user. 
     mImageView.setImageBitmap(bitmap); 
     updateUi(); 
    } 

    /** 
    * Updates the state of 2 control buttons in response to the current page index. 
    */ 
    private void updateUi() { 
     int index = mCurrentPage.getIndex(); 
     int pageCount = mPdfRenderer.getPageCount(); 
     if (pageCount == 1) { 
      mButtonPrevious.setVisibility(View.GONE); 
      mButtonNext.setVisibility(View.GONE); 
     } else { 
      mButtonPrevious.setEnabled(0 != index); 
      mButtonNext.setEnabled(index + 1 < pageCount); 
     } 
     if (currentZoomLevel == 2) { 
      mButtonZoomout.setActivated(false); 
     } else { 
      mButtonZoomout.setActivated(true); 
     } 
    } 

    /** 
    * Gets the number of pages in the PDF. This method is marked as public for testing. 
    * 
    * @return The number of pages. 
    */ 
    public int getPageCount() { 
     return mPdfRenderer.getPageCount(); 
    } 

    @Override 
    public void onClick(View view) { 
     switch (view.getId()) { 
      case R.id.previous: { 
       // Move to the previous page 
       currentZoomLevel = 12; 
       showPage(mCurrentPage.getIndex() - 1); 
       break; 
      } 
      case R.id.next: { 
       // Move to the next page 
       currentZoomLevel = 12; 
       showPage(mCurrentPage.getIndex() + 1); 
       break; 
      } 
      case R.id.zoomout: { 
       // Move to the next page 
       --currentZoomLevel; 
       showPage(mCurrentPage.getIndex()); 
       break; 
      } 
      case R.id.zoomin: { 
       // Move to the next page 
       ++currentZoomLevel; 
       showPage(mCurrentPage.getIndex()); 
       break; 
      } 
     } 
    } 
} 

は、ズームレベルは、画面の密度が、幅に依存することに注意を持参し、ビットマップの高さ(ピクセル単位)は、ズームレベルにのみ依存します。また、デフォルトのズームで(pdfフルスクリーンで表示され、値が12だった私にとっては)、PDFビットマップはビューに必要以上に必要以上にならないように、サイズを微調整する必要があります。

int newWidth = (int) (getResources().getDisplayMetrics().widthPixels * mCurrentPage.getWidth()/72 * currentZoomLevel/40); 
int newHeight = (int) (getResources().getDisplayMetrics().heightPixels * mCurrentPage.getHeight()/72 * currentZoomLevel/64); 
Bitmap bitmap = Bitmap.createBitmap(
       newWidth, 
       newHeight, 
       Bitmap.Config.ARGB_8888); 
  1. 私はズーム12が私の画面に適合し、40と64は、ビットマップの適切なサイズを作る的係数いることがわかりました。
  2. mCurrentPage.getWidth()は、ポストスクリプトポイントの幅を返します。ここで、各ptは1/72インチです。
  3. 72(DPI)がデフォルトのPDF解像度です。

PS。あなたはこのソリューションを皮切りScrollview vertical and horizontal in android

4

私はこのような状況に直面したときに使用したソリューション使用しています:

  • ロードImageViewの中pdfRendererページを

  • 私のImageViewをScrollView(tadamスクロール管理)に入れ、このScrollViewをFrameLayoutに入れます

  • ズームインとズームアウトを管理する2つのボタン(スクロールビューの外側)を追加します(各ボタンはImageViewでスケールアニメーションをトリガーします)。私はフェードインを追加した素敵な効果を得るために(まだScrollView外)ページの変更を管理するために2つのボタンを追加し

  • をあなたはまた、ジェスチャー検出器とそれを管理することができますがそう

  • を行うとき、私はスクロール動作で苦労していました/フェードアウト私のボタンのアニメーション(アニメーションが再生されていない場合)、フェードインがOnTouchEventsでトリガ、およびフェードインアニメーションは、私は、助けたあなたはより詳細な情報が必要な場合は、私をAKSが、あなたが知っておくべき希望

の上にあるときにフェードアウトは、トリガ今どこから始めるか

コードサンプル: コード: C#(でもJavaに変換するのは簡単ですが)

private Button _zoomInButton; 
private Button _zoomOutButton; 
private ImageView _pdfViewContainer; 
private float _currentZoomLevel; 
private float _zoomFactor; 
private float _maxZoomLevel; 
private float _minZoomLevel; 

private void Init(View view) // the content of this method must go in your OnViewCreated method, here the view being the frameLayout you will find in xml 
{ 
    _zoomInButton = view.FindViewById<Button>(Resource.Id.PdfZoomInButton); 
    _zoomOutButton = view.FindViewById<Button>(Resource.Id.PdfZoomOutButton); 
    _pdfViewContainer = view.FindViewById<ImageView>(Resource.Id.PdfViewContainer); 

    _zoomInButton.Click += delegate { ZoomIn(); }; //for you (in Java) this must looks like setOnClickListener(this); and in the onClick metghod you just have to add a case for R.id.PdfZoomInButton containing a call to ZoomIn(); 
    _zoomOutButton.Click += delegate { ZoomOut(); }; 

    _minZoomLevel = 0.9f; 
    _maxZoomLevel = 1.2f; 
    _zoomFactor = 0.1f; 
} 

private void ZoomIn() 
{ 
    if (_currentZoomLevel + _zoomFactor < _maxZoomLevel) 
    { 
     ScaleAnimation scale = new ScaleAnimation(_currentZoomLevel, _currentZoomLevel + _zoomFactor, _currentZoomLevel, _currentZoomLevel + _zoomFactor, Dimension.RelativeToSelf, 0.5f, Dimension.RelativeToSelf, 0.5f); 
     scale.Duration = 50; 
     scale.FillAfter = true; 
     _pdfViewContainer.StartAnimation(scale); 
     _currentZoomLevel += _zoomFactor; 
    } 
} 

private void ZoomOut() 
{ 
    if (_currentZoomLevel - _zoomFactor > _minZoomLevel) 
    { 
     ScaleAnimation scale = new ScaleAnimation(_currentZoomLevel, _currentZoomLevel - _zoomFactor, _currentZoomLevel, _currentZoomLevel - _zoomFactor, Dimension.RelativeToSelf, 0.5f, Dimension.RelativeToSelf, 0.5f); 
     scale.Duration = 50; 
     scale.FillAfter = true; 
     _pdfViewContainer.StartAnimation(scale); 
     _currentZoomLevel -= _zoomFactor; 
    } 
} 

これにより

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:id="@+id/PdfContainer"> 
    <ScrollView xmlns:tools="http://schemas.android.com/tools" 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:scrollbarAlwaysDrawVerticalTrack="true" 
     android:id="@+id/PdfScrollView"> 
     <ImageView 
      android:layout_width="match_parent" 
      android:layout_height="match_parent" 
      android:scaleType="fitCenter" 
      android:adjustViewBounds="true" 
      android:scrollbars="vertical" 
      android:src="@drawable/mediaIconPDF" 
      android:id="@+id/PdfViewContainer" /> 
    </ScrollView> 
    <LinearLayout 
     android:id="@+id/PdfRightLayout" 
     android:layout_gravity="right" 
     android:orientation="vertical" 
     android:gravity="center" 
     android:layout_width="50dp" 
     android:layout_height="match_parent" 
     android:weightSum="1"> 
     <Button 
      android:id="@+id/PdfZoomInButton" 
      android:layout_width="match_parent" 
      android:layout_height="50dp" 
      android:text="+" /> 
     <space 
      android:layout_width="match_parent" 
      android:layout_height="0dp" 
      android:layout_weight="0.2" /> 
     <Button 
      android:id="@+id/PdfZoomOutButton" 
      android:layout_width="match_parent" 
      android:layout_height="50dp" 
      android:text="-" /> 
    </LinearLayout> 
    <LinearLayout 
     android:id="@+id/PdfBottomLayout" 
     android:layout_gravity="bottom" 
     android:orientation="horizontal" 
     android:layout_width="match_parent" 
     android:layout_height="50dp" 
     android:background="@color/vogofTransparentGrey" 
     android:weightSum="1"> 
     <Button 
      android:id="@+id/PdfPreviousPage" 
      android:layout_width="0dp" 
      android:layout_weight="0.15" 
      android:layout_height="match_parent" 
      android:text="Prev" /> 
     <TextView 
      android:id="@+id/PdfCurrentPageLabel" 
      android:layout_width="0dp" 
      android:layout_weight="0.7" 
      android:gravity="center" 
      android:layout_height="match_parent" 
      /> 
     <Button 
      android:id="@+id/PdfNextPage" 
      android:layout_width="0dp" 
      android:layout_weight="0.15" 
      android:layout_height="match_parent" 
      android:text="Next" /> 
    </LinearLayout> 
</FrameLayout> 

XML、いくつかの時間は、それを理解するには少しの努力は、あなたは、所望の結果を得ることができる必要があります。素敵な一日を!

+0

ター答えはnks。サンプルコードを投稿できますか? –

+0

完了しましたが、XamarinC#のようにコピーして貼り付けるだけでは機能しません(ただし、翻訳が簡単です) –

+0

いいえ、それは役に立ちませんでした:-(私はこれで悩んでいます!! –

0

同時垂直方向と水平方向のスクロールが必要な場合:https://stackoverflow.com/a/46002017/5049286私は初期のズーム係数及びその他の固定係数を避けるための良い方法を発見し、この方法だけを変更:

private void showPage(int index) { 

    if (mPdfRenderer.getPageCount() <= index) { 
     return; 
    } 
    if (null != mCurrentPage) { 
     mCurrentPage.close(); 
    } 
    mCurrentPage = mPdfRenderer.openPage(index); 

    int newWidth = (int) (mVerticalScrollView.getWidth() * 
    currentZoomLevel); 
    int newHeight = (int) (newWidth * 
    ((float)mCurrentPage.getHeight()/(float)mCurrentPage.getWidth())); 

    Bitmap bitmap = Bitmap.createBitmap(
     newWidth, 
     newHeight, 
     Bitmap.Config.ARGB_8888); 

    mCurrentPage.render(bitmap, null, null, 
    PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY); 
    mImageView.setImageBitmap(bitmap); 

    updateUi(); 

}

このソリューションcurrentZoomLevelはscrollviewにXXX(あなたが限界を決める)とズーム1.0Fフィットでレンダリングされた画像に1.0Fから始まり、比率が維持されていると

...

関連する問題