Loupe: Twitter-like Android image viewer library

Issei Aoki
Mar 5 · 3 min read
Photo by João Silas on Unsplash

3 months ago, my boss requested me to implement a Twitter-like image viewer in our app. It supports pinch-to-zoom and swipe-to-dismiss gesture.

Let’s see how the twitter’s image viewer works.

Twitter’s image viewer

Twitter’s image viewer (Android)

Android’s specification

  • supports scrolling when zoomed in
  • supports over scaling
  • supports swipe-to-dismiss gesture with shared elements transition when zoomed out
  • supports horizontal paging
Twitter’s image viewer(iOS)

iOS’s specification

  • supports scrolling & flinging when zoomed in
  • supports over scrolling & scaling
  • supports swipe-to-dismiss gesture with vertical translate animation when zoomed out
  • supports horizontal paging

Super cool…How can I implement this? 🤔

Any libraries?

There are many libraries for image zooming.

Although these great libraries provide pinch-to-zoom gesture, does not provide swipe-to-dismiss gesture(for now) 😫

How about using Behavior with existing libraries?

First, I have tried to use CoordinatorLayout.Behavior(https://developer.android.com/reference/android/support/design/widget/CoordinatorLayout.Behavior) with existing libraries.

I wrote the below code.


It seems to work with normal ImageView.

But, in the case of PhotoView, behavior does not work 😿

Looks like Behavior’s touch event handling is conflicting with PhotoView’s 🤔


This method block was suspicious, but I didn’t realize how to fix this issue .

And I tried the other libraries, but the results were similar 😵

I thought I need to handle the whole TouchEvent of the ImageView by myself.

After two months of work in my private time…finally, I released a new library!


  • supports scrolling & flinging when zoomed in
  • supports over scrolling & scaling
  • supports two type swipe-to-dismiss gesture(shared elements transition & vertical translate animation)
  • supports horizontal paging
  • written in Kotlin
  • just a helper class of ImageView. So you can attach it to any ImageView you want. And working perfect with any image loader libraries.

How to use?

Create Loupe instance with your ImageView and implement the onViewTranslateListener. Code sample in Activity is something like this. (Loupe also works in Fragments)

val loupe = Loupe(imageView, container).apply { // imageView is your full screen ImageView and container is the direct parent of the ImageView  onViewTranslateListener = object : Loupe.OnViewTranslateListener {    override fun onStart(view: ImageView) {

override fun onViewTranslate(view: ImageView, amount: Float) {

override fun onRestore(view: ImageView) {

override fun onDismiss(view: ImageView) {

That’s all. See? It’s easy 😆

For more details, check the repository out 👀


Issei Aoki

Written by

Android Developer. https://github.com/igreenwood/

More From Medium

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade