2
3

More than 3 years have passed since last update.

【Android / Kotlin】ズーム対応のPDF表示サンプルアプリ(PdfRenderer + PhotoView)

Last updated at Posted at 2021-05-25

はじめに

今回 Android でPDFを表示するためにはどのように実装する必要があるかを調査、検討しました。

結論、Android でPDF表示をするのはかなり大変。
というかただ表示するだけであればそこまで難しくはないものの、使い勝手をよくするためにいろいろな機能を実装したりするとなると相当大変そうです。(というかそもそも可能か?ということもあります。)

iOS のようには行かないみたいです。
Android 大変や…

こんな意見もあって、参考にさせていただきました。
https://qiita.com/s_of_p/items/1c1a467d246ab7dc45e1

そこで今回は

  • PDFを1枚だけ表示(標準SDKのPdfRendererを利用)
  • ズームイン / ズームアウトに対応(ライブラリPhotoViewを利用)

この2点に対応した簡単なサンプルアプリを作成しました。

20210525_115215.gif

環境

  • Android Studio 4.2.1
  • Build #AI-202.7660.26.42.7351085, built on May 11, 2021
  • Runtime version: 11.0.8+10-b944.6916264 x86_64
  • VM: OpenJDK 64-Bit Server VM by N/A
  • macOS 10.15.7

セットアップ

以下を利用できるようにするため、build.gradleに記述を追加する

  • データバインディング
  • PhotoView

build.gradle(Projectレベル)

build.gradle
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
    ext.kotlin_version = "1.5.0"
    repositories {
        google()
        mavenCentral()
    }
    dependencies {
        classpath "com.android.tools.build:gradle:4.2.1"
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        google()
        mavenCentral()
        maven { url "https://www.jitpack.io" } // ここに追加(PhotoView導入のため
        jcenter() // Warning: this repository is going to shut down soon
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

build.gradle(Moduleレベル)

build.gradle
plugins {
    id 'com.android.application'
    id 'kotlin-android'
}

android {
    compileSdkVersion 30
    buildToolsVersion "30.0.3"

    defaultConfig {
        applicationId "com.android.pdfrenderer_sample"
        minSdkVersion 23
        targetSdkVersion 30
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = '1.8'
    }

    // DataBinding 導入のため 以下3行を追加
    buildFeatures {
        dataBinding = true
    }
}

dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
    implementation 'androidx.core:core-ktx:1.3.2'
    implementation 'androidx.appcompat:appcompat:1.2.0'
    implementation 'com.google.android.material:material:1.3.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
    testImplementation 'junit:junit:4.+'
    androidTestImplementation 'androidx.test.ext:junit:1.1.2'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'

    implementation 'com.github.chrisbanes:PhotoView:2.3.0' // ここに追加(PhotoView導入のため
}

PDFファイルを assets にセット

app/assetsディレクトリを作成してその配下に表示対象のPDFファイルをセットします。

スクリーンショット 2021-05-25 12.57.07.png

実装

レイアウトファイル

activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    >
    <androidx.constraintlayout.widget.ConstraintLayout
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

<!--        ここにPDFを表示させる-->
        <com.github.chrisbanes.photoview.PhotoView
            android:id="@+id/photo_view"
            android:layout_width="0dp"
            android:layout_height="0dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

アクティビティ

MainActivity.kt
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // レイアウト と PhotoView 要素を バインド
        val binding: ActivityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)
        val photoView = binding.photoView

        // assets にある PDFファイル にアクセス
        val file = File(cacheDir.path, "sample_explain.pdf")
        val fileOutputStream = FileOutputStream(file)
        assets.open("sample_explain.pdf").copyTo(fileOutputStream)

        // PdfRenderer を インスタンス化
        val parcelFileDescriptor = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY)
        val pdfRenderer = PdfRenderer(parcelFileDescriptor)

        // PdfRenderer を オープン(今回は最初のページのみ表示するため引数の index:0)
        val page = pdfRenderer.openPage(0)

        // Bitmap を生成して 表示する PhotoView にセット(幅、高さなどは適当に設定してます)
        val bitmap = Bitmap.createBitmap(500, 500, Bitmap.Config.ARGB_8888)
        page.render(bitmap, Rect(0, 0, 500, 500), null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY)
        photoView.setImageBitmap(bitmap)

        // page と PdfRenderer を クローズ
        page.close()
        pdfRenderer.close()
    }
}

最後に

PDFを複数ページ表示させるためにはリサイクラービューを利用したりと工夫が必要そうです。
他にもいろいろと機能を実装するためにはかなり実装を工夫して頑張る必要がありそうでした。

参考にさせていただいた資料(ありがとうございました!!!)

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3