Add material fab transition #178

Closed
ztimms73 wants to merge 4 commits from feature/fab-transition into devel

@ -6,6 +6,7 @@ import android.os.Bundle
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import android.view.ViewGroup.MarginLayoutParams import android.view.ViewGroup.MarginLayoutParams
import android.view.Window
import androidx.activity.result.ActivityResultCallback import androidx.activity.result.ActivityResultCallback
import androidx.appcompat.app.ActionBarDrawerToggle import androidx.appcompat.app.ActionBarDrawerToggle
import androidx.appcompat.view.ActionMode import androidx.appcompat.view.ActionMode
@ -24,6 +25,7 @@ import com.google.android.material.appbar.AppBarLayout.LayoutParams.*
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.navigation.NavigationView import com.google.android.material.navigation.NavigationView
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import com.google.android.material.transition.platform.MaterialContainerTransformSharedElementCallback
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.koin.android.ext.android.get import org.koin.android.ext.android.get
@ -84,6 +86,11 @@ class MainActivity :
get() = binding.appbar get() = binding.appbar
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
window.requestFeature(Window.FEATURE_ACTIVITY_TRANSITIONS)
setExitSharedElementCallback(MaterialContainerTransformSharedElementCallback())
window.sharedElementsUseOverlay = false
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(ActivityMainBinding.inflate(layoutInflater)) setContentView(ActivityMainBinding.inflate(layoutInflater))
navHeaderBinding = NavigationHeaderBinding.inflate(layoutInflater) navHeaderBinding = NavigationHeaderBinding.inflate(layoutInflater)
@ -320,8 +327,20 @@ class MainActivity :
} }
private fun onOpenReader(manga: Manga) { private fun onOpenReader(manga: Manga) {
val options = ActivityOptions.makeScaleUpAnimation(binding.fab, 0, 0, binding.fab.width, binding.fab.height) apply {
startActivity(ReaderActivity.newIntent(this, manga), options?.toBundle()) val intent = ReaderActivity.newIntent(this, manga)
val options = ActivityOptions.makeSceneTransitionAnimation(
this,
binding.fab,
ReaderActivity.SHARED_ELEMENT_NAME
)
startActivity(
intent.apply {
putExtra(ReaderActivity.EXTRA_IS_TRANSITION, true)
},
options.toBundle()
)
}
} }
private fun onError(e: Throwable) { private fun onError(e: Throwable) {
@ -389,6 +408,7 @@ class MainActivity :
private fun setPrimaryFragment(fragment: Fragment) { private fun setPrimaryFragment(fragment: Fragment) {
supportFragmentManager.beginTransaction() supportFragmentManager.beginTransaction()
.setCustomAnimations(R.anim.fragment_fade_in, R.anim.fragment_fade_out)
.replace(R.id.container, fragment, TAG_PRIMARY) .replace(R.id.container, fragment, TAG_PRIMARY)
.commit() .commit()
adjustFabVisibility(topFragment = fragment) adjustFabVisibility(topFragment = fragment)

@ -19,6 +19,8 @@ import androidx.transition.TransitionManager
import androidx.transition.TransitionSet import androidx.transition.TransitionSet
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import com.google.android.material.transition.platform.MaterialContainerTransform
import com.google.android.material.transition.platform.MaterialContainerTransformSharedElementCallback
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
@ -80,6 +82,21 @@ class ReaderActivity :
private val hideUiRunnable = Runnable { setUiIsVisible(false) } private val hideUiRunnable = Runnable { setUiIsVisible(false) }
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
// Setup shared element transitions
if (intent.extras?.getBoolean(EXTRA_IS_TRANSITION) == true) {
window.requestFeature(Window.FEATURE_ACTIVITY_TRANSITIONS)
findViewById<View>(android.R.id.content)?.let { contentView ->
contentView.transitionName = SHARED_ELEMENT_NAME
setEnterSharedElementCallback(MaterialContainerTransformSharedElementCallback())
window.sharedElementEnterTransition = buildContainerTransform(true)
window.sharedElementReturnTransition = buildContainerTransform(false)
// Postpone custom transition until manga ready
postponeEnterTransition()
}
}
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(ActivityReaderBinding.inflate(layoutInflater)) setContentView(ActivityReaderBinding.inflate(layoutInflater))
readerManager = ReaderManager(supportFragmentManager, R.id.container) readerManager = ReaderManager(supportFragmentManager, R.id.container)
@ -114,6 +131,12 @@ class ReaderActivity :
} }
} }
private fun buildContainerTransform(entering: Boolean): MaterialContainerTransform {
return MaterialContainerTransform(this, entering).apply {
addTarget(android.R.id.content)
}
}
private fun onInitReader(mode: ReaderMode) { private fun onInitReader(mode: ReaderMode) {
if (readerManager.currentMode != mode) { if (readerManager.currentMode != mode) {
readerManager.replace(mode) readerManager.replace(mode)
@ -130,6 +153,7 @@ class ReaderActivity :
if (binding.appbarTop.isVisible) { if (binding.appbarTop.isVisible) {
lifecycle.postDelayed(hideUiRunnable, TimeUnit.SECONDS.toMillis(1)) lifecycle.postDelayed(hideUiRunnable, TimeUnit.SECONDS.toMillis(1))
} }
startPostponedEnterTransition()
} }
override fun onCreateOptionsMenu(menu: Menu): Boolean { override fun onCreateOptionsMenu(menu: Menu): Boolean {
@ -400,6 +424,8 @@ class ReaderActivity :
companion object { companion object {
const val SHARED_ELEMENT_NAME = "reader_shared_element_root"
const val EXTRA_IS_TRANSITION = "${BuildConfig.APPLICATION_ID}.READER_IS_TRANSITION"
const val ACTION_MANGA_READ = "${BuildConfig.APPLICATION_ID}.action.READ_MANGA" const val ACTION_MANGA_READ = "${BuildConfig.APPLICATION_ID}.action.READ_MANGA"
private const val EXTRA_STATE = "state" private const val EXTRA_STATE = "state"
private const val EXTRA_BRANCH = "branch" private const val EXTRA_BRANCH = "branch"

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<alpha
xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@integer/fade_in_duration"
android:fromAlpha="0.0"
android:toAlpha="1.0" />

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<alpha
xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@integer/fade_out_duration"
android:fromAlpha="1.0"
android:toAlpha="0.0" />

@ -3,4 +3,5 @@
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pager" android:id="@+id/pager"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" /> android:layout_height="match_parent"
android:background="?android:colorBackground" />

@ -5,5 +5,6 @@
android:id="@+id/recyclerView" android:id="@+id/recyclerView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="?android:colorBackground"
android:orientation="vertical" android:orientation="vertical"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" /> app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<integer name="manga_badge_max_character_count">3</integer> <integer name="manga_badge_max_character_count">3</integer>
<integer name="fade_in_duration">210</integer>
<integer name="fade_out_duration">90</integer>
</resources> </resources>
Loading…
Cancel
Save