Skip to content

Commit 7165b55

Browse files
author
Artem
committed
+ shared elements transition
1 parent 4a15e77 commit 7165b55

File tree

5 files changed

+116
-27
lines changed

5 files changed

+116
-27
lines changed

config.gradle

+4-4
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,18 @@ ext {
88
buildTools = "30.0.2"
99

1010
//version
11-
vCode = 2
12-
vName = "1.0.1"
11+
vCode = 3
12+
vName = "1.0.2"
1313

1414
//gradle
1515
gradleVersion = '4.1.2'
1616

1717
//kotlin
18-
kotlinVersion = '1.4.30'
18+
kotlinVersion = '1.4.31'
1919

2020
//android x
2121
xVersion = '1.2.0'
22-
xFragment = '1.3.1'
22+
xFragment = '1.3.3'
2323

2424
//cicerone
2525
ciceroneVersion = '6.6'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package ru.wearemad.mad_navigation.data
2+
3+
import android.view.View
4+
5+
typealias SharedView = Pair<View, String>
6+
7+
class SharedTransitionInfo {
8+
9+
private val sharedElements = mutableListOf<SharedView>()
10+
11+
val names: List<String>
12+
get() = sharedElements.map { it.second }
13+
14+
val elements: List<SharedView>
15+
get() = sharedElements
16+
17+
val hasSharedElements: Boolean
18+
get() = sharedElements.isNotEmpty()
19+
20+
fun add(data: SharedView) {
21+
sharedElements.add(data)
22+
}
23+
24+
fun add(name: String, view: View) {
25+
sharedElements.add(SharedView(view, name))
26+
}
27+
28+
fun addAll(data: List<SharedView>) {
29+
sharedElements.addAll(data)
30+
}
31+
32+
fun clearResources() {
33+
sharedElements.clear()
34+
}
35+
}

mad-navigation/src/main/java/ru/wearemad/mad_navigation/navigator/BaseNavigator.kt

+47-22
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,12 @@ import com.github.terrakok.cicerone.Navigator
1414
import com.github.terrakok.cicerone.Replace
1515
import com.github.terrakok.cicerone.androidx.ActivityScreen
1616
import com.github.terrakok.cicerone.androidx.AppScreen
17-
import com.github.terrakok.cicerone.androidx.FragmentScreen
1817
import com.github.terrakok.cicerone.androidx.TransactionInfo
19-
import ru.wearemad.mad_navigation.route.FragmentRoute
2018
import ru.wearemad.mad_navigation.commands.AddScreenCommand
2119
import ru.wearemad.mad_navigation.commands.ExitWithFragmentResult
2220
import ru.wearemad.mad_navigation.commands.OpenDialogCommand
2321
import ru.wearemad.mad_navigation.commands.ReplaceTabCommand
22+
import ru.wearemad.mad_navigation.route.FragmentRoute
2423

2524
abstract class BaseNavigator(
2625
private val fragmentManager: FragmentManager,
@@ -65,10 +64,8 @@ abstract class BaseNavigator(
6564

6665
protected open fun forward(command: Forward) {
6766
when (val screen = command.screen as AppScreen) {
68-
is ActivityScreen -> {
69-
checkAndStartActivity(screen)
70-
}
71-
is FragmentScreen -> {
67+
is ActivityScreen -> checkAndStartActivity(screen)
68+
is FragmentRoute -> {
7269
val type = if (command.clearContainer) TransactionInfo.Type.REPLACE else TransactionInfo.Type.ADD
7370
commitNewFragmentScreen(screen, type, true)
7471
}
@@ -81,7 +78,7 @@ abstract class BaseNavigator(
8178
checkAndStartActivity(screen)
8279
activityBack()
8380
}
84-
is FragmentScreen -> {
81+
is FragmentRoute -> {
8582
if (localStackCopy.isNotEmpty()) {
8683
fragmentManager.popBackStack()
8784
val removed = localStackCopy.removeAt(localStackCopy.lastIndex)
@@ -165,29 +162,32 @@ abstract class BaseNavigator(
165162

166163

167164
protected open fun commitNewFragmentScreen(
168-
screen: FragmentScreen,
165+
screen: FragmentRoute,
169166
type: TransactionInfo.Type,
170167
addToBackStack: Boolean
171168
) {
172169
val fragment = screen.createFragment(fragmentFactory)
170+
173171
val transaction = fragmentManager.beginTransaction()
174172
transaction.setReorderingAllowed(true)
175-
if (screen is FragmentRoute) {
176-
screen.animation?.let {
177-
transaction
178-
.setCustomAnimations(
179-
it.enter,
180-
it.exit,
181-
it.popEnter,
182-
it.popExit
183-
)
184-
}
185-
}
173+
186174
setupFragmentTransaction(
187175
transaction,
188176
fragmentManager.findFragmentById(containerId),
189-
fragment
177+
fragment,
178+
screen
190179
)
180+
181+
screen.animation?.let {
182+
transaction
183+
.setCustomAnimations(
184+
it.enter,
185+
it.exit,
186+
it.popEnter,
187+
it.popExit
188+
)
189+
}
190+
191191
when (type) {
192192
TransactionInfo.Type.ADD -> transaction.add(containerId, fragment, screen.screenKey)
193193
TransactionInfo.Type.REPLACE -> transaction.replace(containerId, fragment, screen.screenKey)
@@ -232,9 +232,24 @@ abstract class BaseNavigator(
232232
protected open fun setupFragmentTransaction(
233233
fragmentTransaction: FragmentTransaction,
234234
currentFragment: Fragment?,
235-
nextFragment: Fragment?
235+
nextFragment: Fragment?,
236+
screen: FragmentRoute
236237
) {
237-
// Do nothing by default
238+
val transitionInfo = screen.sharedTransitionInfo
239+
if (transitionInfo.hasSharedElements.not()) {
240+
return
241+
}
242+
screen.applySharedTransitionInfo(nextFragment)
243+
fragmentTransaction.setReorderingAllowed(true)
244+
transitionInfo
245+
.elements
246+
.forEach { pair ->
247+
fragmentTransaction.addSharedElement(
248+
pair.first,
249+
pair.second
250+
)
251+
}
252+
transitionInfo.clearResources()
238253
}
239254

240255
/**
@@ -279,7 +294,17 @@ abstract class BaseNavigator(
279294
private fun addScreen(command: AddScreenCommand) {
280295
val screen = command.screen
281296
val newFragment = screen.createFragment(fragmentFactory)
297+
282298
val fragmentTransaction = fragmentManager.beginTransaction()
299+
fragmentTransaction.setReorderingAllowed(true)
300+
301+
setupFragmentTransaction(
302+
fragmentTransaction,
303+
fragmentManager.findFragmentById(containerId),
304+
newFragment,
305+
screen
306+
)
307+
283308
command.screen.animation?.let {
284309
fragmentTransaction
285310
.setCustomAnimations(

mad-navigation/src/main/java/ru/wearemad/mad_navigation/navigator/FragmentNavigator.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import androidx.fragment.app.Fragment
66
import com.github.terrakok.cicerone.androidx.ActivityScreen
77
import ru.wearemad.mad_navigation.commands.ExitWithFragmentResult
88

9-
class FragmentNavigator(
9+
open class FragmentNavigator(
1010
containerId: Int,
1111
private val fragment: Fragment,
1212
) : BaseNavigator(

mad-navigation/src/main/java/ru/wearemad/mad_navigation/route/FragmentRoute.kt

+29
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,24 @@
11
package ru.wearemad.mad_navigation.route
22

3+
import android.os.Bundle
34
import androidx.fragment.app.Fragment
45
import com.github.terrakok.cicerone.androidx.FragmentScreen
6+
import ru.wearemad.mad_navigation.data.SharedTransitionInfo
7+
8+
private const val ARG_SHARED_ELEMENTS_NAMES = "ru.wearemad.mad_navigation.route.arg_shared_elements_names"
59

610
open class FragmentRoute(
711
private val creator: () -> Fragment
812
) : FragmentScreen(fragmentCreator = { creator() }) {
913

14+
companion object {
15+
16+
fun fetchArgSharedElementsNames(args: Bundle?): List<String> =
17+
(args?.getStringArray(ARG_SHARED_ELEMENTS_NAMES) ?: emptyArray<String>()).toList()
18+
}
19+
20+
val sharedTransitionInfo = SharedTransitionInfo()
21+
1022
var animation: TransitionAnimation? = null
1123

1224
fun withDefaultAnim(): FragmentRoute = this.apply {
@@ -16,4 +28,21 @@ open class FragmentRoute(
1628
fun withCustomAnim(transition: TransitionAnimation): FragmentRoute = this.apply {
1729
animation = transition
1830
}
31+
32+
open fun applySharedTransitionInfo(fragment: Fragment?) {
33+
fragment ?: return
34+
if (sharedTransitionInfo.hasSharedElements.not()) {
35+
return
36+
}
37+
var args = fragment.arguments
38+
if (args == null) {
39+
args = Bundle()
40+
fragment.arguments = args
41+
}
42+
args.putSharedElementsNamesIfExist()
43+
}
44+
45+
private fun Bundle.putSharedElementsNamesIfExist() {
46+
putStringArray(ARG_SHARED_ELEMENTS_NAMES, sharedTransitionInfo.names.toTypedArray())
47+
}
1948
}

0 commit comments

Comments
 (0)