Android Full Screen Activity to View Zoomable Image
July 21, 2018using Glide and PhotoView
The following library are used
The activity shall have the following features
- Full screen: no status bar
- Action toolbar shall overlay the image: maintain back icon to close the activity
- Click the on image will toggle dark mode (background change to dark color and hide toolbar)
- Image shown shall be zoomable
Enable Fullscreen Mode
Edit AndroidManifest.xml
<manifest ...>
<application ...>
<activity
android:name=".view.support.ImageViewActivity"
android:label="@string/title_activity_image_view"
android:parentActivityName=".MainActivity"
android:theme="@style/AppTheme.Fullscreen">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".MainActivity" />
</activity>
</application>
</manifest>
Edit res/values/styles.xml
.
<resources>
<style name="AppTheme.Fullscreen">
<item name="android:windowFullscreen">true</item>
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
</resources>
Activity and layout
Code of ImageViewActivity
.
ViewModel is used to maintain Dark Mode
status to survice screen rotation/configuration change.
NOTE: Optional ViewModel and Dagger2 dependency injection is used. You can remove them.
class ImageViewActivity : AppCompatActivity() {
companion object {
private const val EXTRA_IMAGE_RESOURCE = "image_resource"
fun newInstance(context: Context, imageResource: String) = Intent(context, ImageViewActivity::class.java).apply {
// imageResource can be file path or URL
putExtra(EXTRA_IMAGE_RESOURCE, imageResource)
}
}
@Inject
lateinit var viewModelFactory: ViewModelFactory
private lateinit var viewModel: ImageViewViewModel
override fun onCreate(savedInstanceState: Bundle?) {
AndroidInjection.inject(this)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_image_view)
setSupportActionBar(toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
viewModel = ViewModelProviders.of(this, viewModelFactory).get(ImageViewViewModel::class.java)
val imageResource = intent.getStringExtra(EXTRA_IMAGE_RESOURCE)
GlideApp.with(this)
.load(imageResource)
// .override(SimpleTarget.SIZE_ORIGINAL, SimpleTarget.SIZE_ORIGINAL)
.into(photoView)
photoView.setOnClickListener {
viewModel.darkMode.value = !(viewModel.darkMode.value ?: false)
}
viewModel.darkMode.observe(this, Observer {
it?.also {
val color = if (it) {
toolbar.isVisible = false
android.R.color.black
}
else {
toolbar.isVisible = true
android.R.color.white
}
container.setBackgroundColor(ContextCompat.getColor(context, color))
}
})
}
override fun onSupportNavigateUp(): Boolean {
onBackPressed()
return true
}
}
class ImageViewViewModel @Inject constructor(private val db: AppDatabase): ViewModel() {
internal val darkMode = MutableLiveData<Boolean>()
init {
darkMode.value = false
}
}
activity_image_view.xml
- Change
AppBarLayout
to transparent background. - Don’t apply
app:layout_behavior="@string/appbar_scrolling_view_behavior"
to content (ensure content can be fullscreen without restriction ofAppBarLayout
) - Put
AppBarLayout
after content (PhotoView
), else toolbar button are not clickable.
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".view.support.ImageViewActivity">
<!--
<include layout="@layout/content_image_view" />
-->
<!-- app:layout_behavior="@string/appbar_scrolling_view_behavior" -->
<com.github.chrisbanes.photoview.PhotoView
android:id="@+id/photoView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
/>
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay.Light"
android:background="@android:color/transparent"
app:elevation="0dp">
<!-- android:background="?attr/colorPrimary" -->
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:popupTheme="@style/AppTheme.PopupOverlay" />
</android.support.design.widget.AppBarLayout>
<!--
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="@dimen/fab_margin"
app:srcCompat="@android:drawable/ic_dialog_email" />
-->
</android.support.design.widget.CoordinatorLayout>
- algo-trading
- algolia
- analytics
- android
- android-ktx
- android-permission
- android-studio
- apps-script
- bash
- binance
- bootstrap
- bootstrapvue
- chartjs
- chrome
- cloud-functions
- coding-interview
- contentresolver
- coroutines
- crashlytics
- crypto
- css
- dagger2
- datastore
- datetime
- docker
- eslint
- firebase
- firebase-auth
- firebase-hosting
- firestore
- firestore-security-rules
- flask
- fontawesome
- fresco
- git
- github
- glide
- godot
- google-app-engine
- google-cloud-storage
- google-colab
- google-drive
- google-maps
- google-places
- google-play
- google-sheets
- gradle
- html
- hugo
- inkscape
- java
- java-time
- javascript
- jetpack-compose
- jetson-nano
- kotlin
- kotlin-serialization
- layout
- lets-encrypt
- lifecycle
- linux
- logging
- lubuntu
- markdown
- mate
- material-design
- matplotlib
- md5
- mongodb
- moshi
- mplfinance
- mysql
- navigation
- nginx
- nodejs
- npm
- nuxtjs
- nvm
- pandas
- payment
- pip
- pwa
- pyenv
- python
- recylerview
- regex
- room
- rxjava
- scoped-storage
- selenium
- social-media
- ssh
- ssl
- static-site-generator
- static-website-hosting
- sublime-text
- ubuntu
- unit-test
- uwsgi
- viewmodel
- viewpager2
- virtualbox
- vue-chartjs
- vue-cli
- vue-router
- vuejs
- vuelidate
- vuepress
- web-development
- web-hosting
- webpack
- windows
- workmanager
- wsl
- yarn