AVAILABLE NOW: Spring 2025 Release

How to Add a PDF Viewer to an Android Jetpack Compose App

By Branden Fung | 2019 Nov 07

Sanity Image
Read time

3 min

This year at the Android Dev Summit Google released the first canary of Android Studio 4.0. One of the biggest changes is the built-in support for Jetpack Compose, a declarative UI toolkit for building native Android UI. With this new update for Android Studio, developers can now easily experiment with the new Jetpack Compose libraries in their apps.

One of the main selling points of Compose is its ability to work alongside existing Android UI components, allowing you to adopt Compose components into your app at your own pace. In this blog post we will build a sample bookshelf app with Compose alongside the Apryse document viewer.

Please note that Jetpack Compose is currently in Developer Preview and should not be used in production apps.

Build UI with Composable Functions

Copied to clipboard

Compose is built around using composable functions, called composables, that define your app's UI. To create a composable, add the @Composable annotation to a function. Let's start by creating the bookshelf that contains the document thumbnails.

First we'll create a data class that will hold our collection of documents.

@Model
class BookshelfState() {
    val documents =
        listOf(
            "contract.pdf",
            "sample.pdf",
            "blueprint.pdf",
            "drawing.pdf",
            "floorplan.pdf",
            "formula.pdf",
            "invoice.pdf",
            "music.pdf",
            "news.pdf"
        )
}

In terms of data flow, we'll use a top-down data approach where the document data is passed in from upper-level composables to its children. We'll pass this data to a BookshelfItem composable which will contain a thumbnail preview and title of the document.

@Composable
fun BookshelfItem(docName: String) {
    val context = +ambient(ContextAmbient)
    val thumbnail = imageFromResource(
        context.resources,
        getThumbnailResourceFromString(context, docName)!!
    )
    Padding(4.dp) {
        Card(shape = RoundedCornerShape(4.dp), elevation = 2.dp) {
            Column(
                crossAxisAlignment = CrossAxisAlignment.Center,
                crossAxisSize = LayoutSize.Wrap
            ) {
                SimpleImage(thumbnail)
                Padding(8.dp) {
                    Text(
                        text = docName,
                        style = (+themeTextStyle { subtitle1 })
                    )
                }
            }
        }
    }
}

Then we'll put each BookshelfItem into a 3-column Table for better viewing.

@Composable
private fun Bookshelf(bookshelfState: BookshelfState) {
    val columns = 3
    Table(
        columns = columns
    ) {
        val groupedDocs = bookshelfState.documents.chunked(columns)
        groupedDocs.forEach {
            this.tableRow {
                it.forEach {
                    BookshelfItem(it)
                }
            }
        }
    }
}

Finally, we can add this to the root view of our MainActivity.

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val documentsState = BookshelfState();
        setContent {
            MaterialTheme {
                Bookshelf(documentsState)
            }
        }
    }
}

The app should now look something like this:

ComposeViewer thumbnail previews

Display Documents Using Apryse

Copied to clipboard

As mentioned previously, one of the main features of Compose is the ability to use composables alongside existing Android components such as views, fragments, and activities. We can can easily launch the Apryse document viewer in our app with a couple lines of code.

@Composable
fun ClickableBookshelfItem(docName: String) {
    val context = +ambient(ContextAmbient)
    val config = ViewerConfig.Builder()
        .multiTabEnabled(false)
        .build();

    // Wrap bookshelf item with a clickable composable
    // that will launch the viewer
    Ripple(bounded = true) {
        Clickable(onClick = {
            // Launch the viewer for the clicked document
            DocumentActivity.openDocument(
                context,
                getResourceFromString(context, docName),
                config
            );
        }) {
            BookshelfItem(docName)
        }
    }
}

Here we're able to reuse the BookshelfItem composable to add a ripple effect and click functionality. In our app, we can substitute BookshelfItem with ClickableBookshelfItem in the bookshelf composable so that clicking on thumbnails will display the PDF document.

Animation pick a PDF thumbnail preview

Conclusion

Copied to clipboard

With Jetpack Compose comes a new paradigm for Android UI development. It simplifies and accelerates UI development with less code and powerful tools. We're excited to see what's in store for the future of Android development and we look forward to working with Compose as the framework matures.

If you have any questions about Apryse's Android PDF SDK, please feel free to get in touch!

Or if you're interested in our web-based solutions, check out our comprehensive blog on Everything WebViewer.

You can find the source code for this blog post at Github.

Sanity Image

Branden Fung

Share this post

email
linkedIn
twitter