PDF display options on Android with PdfFragment

Nutrient provides two kinds of fragments for displaying PDF documents:

  • PdfFragment is meant for users who want to fully customize and control the PDF display. It shows only the document and does not feature additional views like the thumbnail bar, search, outline, etc.

  • PdfUiFragment works like the ready-to-use PDF viewer activities and provides all the features the PdfActivity provides. You can use this if using a PdfActivity is not possible because you have to use a specific activity subclass already. However, if at all possible, we still recommend using PdfActivity over using PdfUiFragment.

Setting up the manifest

No matter which kind of fragment you end up using, the first step before adding either in your activity is to ensure that your application is prepared for displaying and editing PDFs.

Make sure you have the android:largeHeap="true" property in your <application> tag in AndroidManifest.xml. Rendering PDF files can be memory intensive, and this property will ensure your app has enough heap allocated to avoid hitting out-of-memory errors:

<application android:largeHeap="true">
    ...
</application>

Configuring the fragment

Just like the PdfActivity, both PdfFragment and PdfUiFragment allow passing in a configuration object that defines various options.

PdfFragment

For the PdfFragment, create the PdfConfiguration and pass the desired settings, e.g. scroll orientation, scroll mode, and rendering settings:

val configuration = PdfConfiguration.Builder()
    .scrollDirection(PageScrollDirection.HORIZONTAL)
    .build()
final PdfConfiguration configuration = new PdfConfiguration.Builder()
    .scrollDirection(PageScrollDirection.HORIZONTAL)
    .build();

PdfUiFragment

For the PdfUiFragment use a PdfActivityConfiguration instead of PdfConfiguration. Otherwise, the configuration works the same.

Adding fragment to your activity

PdfFragment

Add PdfFragment to your activity just like you would any other Android fragment. Create the fragment using PdfFragment.newInstance() and attach it to your activity. This is usually done within the onCreate() method of your activity. Since fragments are retained over configuration changes, make sure you don’t recreate the fragment if it already exists:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_custom_fragment)

    // First, try to restore a previously created fragment. If no fragment exists, create a new one.
    val fragment = supportFragmentManager.findFragmentById(R.id.fragmentContainer) as PdfFragment
        ?: createFragment(documentUri, configuration)
}

private fun createFragment(documentUri: Uri, configuration: PdfConfiguration): PdfFragment {
    val fragment = PdfFragment.newInstance(documentUri, configuration)
    supportFragmentManager.beginTransaction()
        .replace(R.id.fragmentContainer, fragment)
        .commit()
    return fragment
}
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_custom_fragment);

    // First, try to restore a previously created fragment.
    PdfFragment fragment = (PdfFragment) getSupportFragmentManager()
        .findFragmentById(R.id.fragmentContainer);

    // If no fragment exists, create a new one.
    if (fragment == null) {
        fragment = PdfFragment.newInstance(documentUri, configuration);
        getSupportFragmentManager()
            .beginTransaction()
            .replace(R.id.fragmentContainer, fragment)
            .commit();
    }
}

PdfUiFragment

PdfUiFragment works similar to how PdfFragment does, but you should use PdfUiFragmentBuilder to obtain an instance of PdfUiFragment:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_custom_fragment)

    // First, try to restore a previously created fragment. If no fragment exists, create a new one.
    val fragment = supportFragmentManager.findFragmentById(R.id.fragmentContainer) as PdfUiFragment
        ?: createFragment(documentUri, configuration)
}

private fun createFragment(documentUri: Uri, configuration: PdfActivityConfiguration): PdfFragment {
    val fragment = PdfUiFragmentBuilder.fromUri(this, documentUri)
        .configuration(configuration)
        .build()
    supportFragmentManager.beginTransaction()
        .replace(R.id.fragmentContainer, fragment)
        .commit()
    return fragment
}
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_custom_fragment);

    // First, try to restore a previously created fragment.
    PdfUiFragment fragment = (PdfUiFragment) getSupportFragmentManager()
        .findFragmentById(R.id.fragmentContainer);

    // If no fragment exists, create a new one.
    if (fragment == null) {
        fragment = PdfUiFragmentBuilder.fromUri(this, documentUri)
            .configuration(configuration)
            .build();
        getSupportFragmentManager()
            .beginTransaction()
            .replace(R.id.fragmentContainer, fragment)
            .commit();
    }
}

Make sure your Activity doesn’t have an action bar (e.g. by using a .NoActionBar theme), because PdfUiFragment comes with its own.

ℹ️ Note: Since PdfFragment and PdfUiFragment extend androidx.fragment.app.Fragment, your activity needs to subclass FragmentActivity, which is part of the AndroidX libraries. Once this is done, you can then access the fragment manager using getSupportFragmentManager().

Building an activity around PdfFragment

Nutrient ships with all the views used in PdfActivity as standalone widgets. If you wish to use these existing Nutrient widgets in your custom activities, follow the building an activity around PdfFragment guide.