@apexnative/navigation 1.0.0-alpha.6 → 1.0.0-alpha.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ApexNavigation.podspec +2 -1
- package/CHANGELOG.md +7 -0
- package/android/CLAUDE.md +19 -10
- package/android/CORE.md +3 -2
- package/android/consumer-rules.pro +6 -0
- package/android/src/main/java/dev/apexnative/navigation/options/BottomTabOptions.kt +1 -1
- package/android/src/main/java/dev/apexnative/navigation/options/ButtonOptions.kt +1 -1
- package/android/src/main/java/dev/apexnative/navigation/options/LargeTitleOptions.kt +1 -1
- package/android/src/main/java/dev/apexnative/navigation/options/LayoutAnimation.kt +1 -1
- package/android/src/main/java/dev/apexnative/navigation/options/OptionKey.kt +18 -0
- package/android/src/main/java/dev/apexnative/navigation/options/OptionPaths.kt +91 -0
- package/android/src/main/java/dev/apexnative/navigation/options/SheetOptions.kt +7 -4
- package/android/src/main/java/dev/apexnative/navigation/options/TitleOptions.kt +2 -2
- package/android/src/main/java/dev/apexnative/navigation/options/TopBarAppearanceOptions.kt +1 -1
- package/android/src/main/java/dev/apexnative/navigation/options/TopBarOptions.kt +16 -7
- package/android/src/main/java/dev/apexnative/navigation/react/ContentHeights.kt +95 -0
- package/android/src/main/java/dev/apexnative/navigation/react/ContentMounts.kt +66 -0
- package/android/src/main/java/dev/apexnative/navigation/react/NavigationTurboModule.kt +4 -0
- package/android/src/main/java/dev/apexnative/navigation/react/OptionsCommands.kt +41 -3
- package/android/src/main/java/dev/apexnative/navigation/react/ReactView.kt +16 -1
- package/android/src/main/java/dev/apexnative/navigation/slots/SlotScreenView.kt +27 -7
- package/android/src/main/java/dev/apexnative/navigation/slots/SlotView.kt +12 -1
- package/android/src/main/java/dev/apexnative/navigation/utils/MaterialTheme.kt +5 -6
- package/android/src/main/java/dev/apexnative/navigation/utils/SystemAnimations.kt +36 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalSheet.kt +329 -55
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalViews.kt +26 -5
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/SheetStops.kt +60 -2
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuMotion.kt +8 -2
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/BackPreview.kt +32 -4
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackController.kt +46 -7
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackQueue.kt +15 -3
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackViews.kt +7 -4
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/fab/FabMotion.kt +142 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/fab/FabPresenter.kt +215 -43
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/search/StackSearchPresenter.kt +25 -26
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/BarRowTransition.kt +3 -2
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/ButtonPlaces.kt +11 -5
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/TopBarPresenter.kt +36 -38
- package/android/src/main/java/dev/apexnative/navigation/views/element/ElementTransitions.kt +124 -181
- package/android/src/main/java/dev/apexnative/navigation/views/element/TargetsWait.kt +8 -1
- package/android/src/main/java/dev/apexnative/navigation/views/element/TransitionLayer.kt +37 -112
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ElementPictures.kt +56 -3
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/FlightGeometry.kt +170 -153
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ImageMorph.kt +199 -0
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/SharedAnimatorFactory.kt +55 -45
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/{TextChangeAnimator.kt → TextMorph.kt} +79 -129
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ViewMorph.kt +108 -0
- package/android/src/main/java/dev/apexnative/navigation/views/stack/fab/FabCopy.kt +85 -0
- package/android/src/main/java/dev/apexnative/navigation/views/stack/fab/FabMenu.kt +13 -0
- package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/TitleBar.kt +5 -24
- package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/TopBar.kt +51 -34
- package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/BarButtonComponentCell.kt +6 -6
- package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/BarButtonView.kt +113 -0
- package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/BarMenu.kt +219 -0
- package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/ButtonBar.kt +121 -175
- package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/ButtonMenus.kt +34 -64
- package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/ButtonRow.kt +216 -0
- package/android/src/main/jni/ANNContentHeights.cpp +82 -0
- package/android/src/main/res/drawable/apex_navigation_ic_arrow_right.xml +14 -0
- package/android/src/main/res/layout/apex_navigation_menu_header.xml +19 -0
- package/android/src/main/res/layout/apex_navigation_menu_item.xml +68 -0
- package/android/src/main/res/values/styles.xml +1 -1
- package/android/src/main/res/values-night/styles.xml +1 -1
- package/cli/doctor/checks/app.js +16 -1
- package/cli/project.js +4 -0
- package/cli/setup/index.js +5 -0
- package/cli/setup/steps/metro.js +46 -0
- package/docs-md/architecture/native-screens.md +4 -0
- package/docs-md/architecture/theme-and-context.md +131 -12
- package/docs-md/architecture/transitions.md +43 -4
- package/docs-md/flows/bottom-sheets.md +4 -2
- package/docs-md/fundamentals/screens-and-props.md +9 -1
- package/docs-md/guides/cli.md +3 -1
- package/docs-md/help/troubleshooting.md +1 -1
- package/docs-md/index.json +29 -1
- package/docs-md/screen-ui/back-and-gestures.md +3 -1
- package/docs-md/screen-ui/bar-buttons.md +1 -1
- package/docs-md/screen-ui/toolbar-and-fab.md +2 -0
- package/docs-md/start/installation.md +16 -1
- package/ios/Animations/ANNFrameDriver.h +55 -15
- package/ios/Animations/ANNFrameDriver.mm +214 -60
- package/ios/Animations/ANNTransitionAnimator.h +26 -5
- package/ios/Animations/ANNTransitionAnimator.mm +49 -3
- package/ios/Animations/ANNTransitionPlan.h +2 -2
- package/ios/Animations/ANNTransitionPlan.mm +10 -0
- package/ios/Animations/Elements/ANNElementFinder.h +2 -2
- package/ios/Animations/Elements/ANNElementFinder.mm +2 -2
- package/ios/Animations/Elements/ANNElementTransition.h +3 -3
- package/ios/Animations/Elements/ANNElementTransition.mm +2 -2
- package/ios/Animations/Elements/ANNSharedElementFlight.h +3 -3
- package/ios/Animations/Elements/ANNSharedElementFlight.mm +181 -43
- package/ios/Animations/Interpolators/ANNViewTracks.h +6 -5
- package/ios/Animations/Interpolators/ANNViewTracks.mm +51 -21
- package/ios/CLAUDE.md +15 -7
- package/ios/CORE.md +1 -1
- package/ios/Core/ANNAppDelegate.mm +0 -2
- package/ios/Core/ANNDeepLinkQueue.h +6 -5
- package/ios/Core/ANNDeepLinkQueue.mm +22 -10
- package/ios/Core/ANNSceneDelegate.mm +2 -2
- package/ios/Core/ApexNavigation.mm +6 -2
- package/ios/Layouts/Root/ANNRootCoordinator.mm +45 -15
- package/ios/Layouts/Screen/ANNComponentViewController.mm +4 -1
- package/ios/Layouts/Stack/ANNStackAnimatingDelegate.h +11 -2
- package/ios/Layouts/Stack/ANNStackAnimatingDelegate.mm +14 -7
- package/ios/Layouts/Stack/ANNStackController.h +8 -0
- package/ios/Layouts/Stack/ANNStackController.mm +153 -11
- package/ios/Layouts/Stack/ANNSwipePopInteraction.h +26 -0
- package/ios/Layouts/Stack/ANNSwipePopInteraction.mm +185 -0
- package/ios/Layouts/Stack/InteractivePopGestureDelegate.mm +28 -4
- package/ios/Options/ANNAnimationOptions.h +2 -1
- package/ios/Options/ANNAnimationOptions.mm +1 -1
- package/ios/Options/ANNOptions.h +7 -0
- package/ios/Options/ANNOptions.mm +45 -0
- package/ios/Options/ANNOptionsReader.mm +2 -4
- package/ios/Options/ANNStackPopAnimationOptions.h +13 -0
- package/ios/Options/ANNStackPopAnimationOptions.mm +11 -0
- package/ios/Options/Params/ColorParser.h +4 -3
- package/ios/Options/Params/ColorParser.mm +22 -4
- package/ios/React/ANNSurfaceHostingView.h +8 -0
- package/ios/React/ANNSurfaceHostingView.mm +28 -1
- package/ios/React/Slots/ANNSlotScreenView.mm +8 -2
- package/ios/TurboModules/ANNTurboModule.mm +46 -0
- package/ios/cpp/react/renderer/components/ApexNavigationSpec/ANNSlotState.cpp +20 -0
- package/ios/cpp/react/renderer/components/ApexNavigationSpec/ANNSlotState.h +5 -14
- package/lib/module/ARCHITECTURE.md +9 -3
- package/lib/module/adapters/NativeANNTurboModule.js.map +1 -1
- package/lib/module/api/app/AppRegistry.js +14 -2
- package/lib/module/api/app/AppRegistry.js.map +1 -1
- package/lib/module/api/app/createNavigation.js +188 -66
- package/lib/module/api/app/createNavigation.js.map +1 -1
- package/lib/module/api/events/navigationEvents.js +6 -2
- package/lib/module/api/events/navigationEvents.js.map +1 -1
- package/lib/module/api/linking/linking.js +11 -0
- package/lib/module/api/linking/linking.js.map +1 -1
- package/lib/module/api/screens/defineScreen.js +45 -3
- package/lib/module/api/screens/defineScreen.js.map +1 -1
- package/lib/module/api/screens/nativeScreens.js +31 -6
- package/lib/module/api/screens/nativeScreens.js.map +1 -1
- package/lib/module/api/screens/registerScreens.js +172 -35
- package/lib/module/api/screens/registerScreens.js.map +1 -1
- package/lib/module/api/theme/theme.js +5 -0
- package/lib/module/api/theme/theme.js.map +1 -1
- package/lib/module/engine/commands.js +21 -1
- package/lib/module/engine/commands.js.map +1 -1
- package/lib/module/engine/layout.js +7 -2
- package/lib/module/engine/layout.js.map +1 -1
- package/lib/module/engine/nativeScreens.js +9 -0
- package/lib/module/engine/nativeScreens.js.map +1 -1
- package/lib/module/engine/options.js +5 -4
- package/lib/module/engine/options.js.map +1 -1
- package/lib/module/engine/optionsChange.js +102 -0
- package/lib/module/engine/optionsChange.js.map +1 -0
- package/lib/module/engine/refresh.js +85 -0
- package/lib/module/engine/refresh.js.map +1 -0
- package/lib/module/engine/rememberedOptions.js +60 -0
- package/lib/module/engine/rememberedOptions.js.map +1 -1
- package/lib/module/engine/screens.js +26 -0
- package/lib/module/engine/screens.js.map +1 -1
- package/lib/typescript/adapters/NativeANNTurboModule.d.ts +7 -0
- package/lib/typescript/adapters/NativeANNTurboModule.d.ts.map +1 -1
- package/lib/typescript/api/app/AppRegistry.d.ts.map +1 -1
- package/lib/typescript/api/app/createNavigation.d.ts +5 -0
- package/lib/typescript/api/app/createNavigation.d.ts.map +1 -1
- package/lib/typescript/api/events/navigationEvents.d.ts +2 -2
- package/lib/typescript/api/events/navigationEvents.d.ts.map +1 -1
- package/lib/typescript/api/index.d.ts +1 -1
- package/lib/typescript/api/index.d.ts.map +1 -1
- package/lib/typescript/api/linking/linking.d.ts +8 -0
- package/lib/typescript/api/linking/linking.d.ts.map +1 -1
- package/lib/typescript/api/screens/defineScreen.d.ts +23 -4
- package/lib/typescript/api/screens/defineScreen.d.ts.map +1 -1
- package/lib/typescript/api/screens/nativeScreens.d.ts +8 -1
- package/lib/typescript/api/screens/nativeScreens.d.ts.map +1 -1
- package/lib/typescript/api/screens/registerScreens.d.ts.map +1 -1
- package/lib/typescript/api/theme/theme.d.ts +2 -0
- package/lib/typescript/api/theme/theme.d.ts.map +1 -1
- package/lib/typescript/engine/commands.d.ts +5 -0
- package/lib/typescript/engine/commands.d.ts.map +1 -1
- package/lib/typescript/engine/layout.d.ts.map +1 -1
- package/lib/typescript/engine/nativeScreens.d.ts +5 -0
- package/lib/typescript/engine/nativeScreens.d.ts.map +1 -1
- package/lib/typescript/engine/optionsChange.d.ts +28 -0
- package/lib/typescript/engine/optionsChange.d.ts.map +1 -0
- package/lib/typescript/engine/refresh.d.ts +35 -0
- package/lib/typescript/engine/refresh.d.ts.map +1 -0
- package/lib/typescript/engine/rememberedOptions.d.ts +13 -0
- package/lib/typescript/engine/rememberedOptions.d.ts.map +1 -1
- package/lib/typescript/engine/screens.d.ts +7 -0
- package/lib/typescript/engine/screens.d.ts.map +1 -1
- package/lib/typescript/interfaces/ComponentEvents.d.ts +2 -2
- package/lib/typescript/interfaces/options/animations.d.ts +40 -15
- package/lib/typescript/interfaces/options/animations.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/bottomTabs.d.ts +2 -2
- package/lib/typescript/interfaces/options/buttons.d.ts +2 -2
- package/lib/typescript/interfaces/options/modals.d.ts +6 -7
- package/lib/typescript/interfaces/options/modals.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/stack.d.ts +8 -3
- package/lib/typescript/interfaces/options/stack.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/topBar.d.ts +14 -0
- package/lib/typescript/interfaces/options/topBar.d.ts.map +1 -1
- package/metro/acceptPlugin.js +57 -0
- package/metro/babelTransformer.js +45 -0
- package/metro/index.js +36 -0
- package/package.json +3 -1
- package/src/ARCHITECTURE.md +9 -3
- package/src/adapters/NativeANNTurboModule.ts +7 -0
- package/src/api/app/AppRegistry.ts +16 -2
- package/src/api/app/createNavigation.ts +198 -66
- package/src/api/events/navigationEvents.ts +9 -3
- package/src/api/index.ts +1 -0
- package/src/api/linking/linking.ts +22 -1
- package/src/api/screens/defineScreen.ts +49 -5
- package/src/api/screens/nativeScreens.ts +40 -4
- package/src/api/screens/registerScreens.tsx +170 -42
- package/src/api/theme/theme.ts +5 -0
- package/src/engine/commands.ts +21 -0
- package/src/engine/layout.ts +11 -2
- package/src/engine/nativeScreens.ts +10 -1
- package/src/engine/options.ts +6 -8
- package/src/engine/optionsChange.ts +107 -0
- package/src/engine/refresh.ts +97 -0
- package/src/engine/rememberedOptions.ts +70 -0
- package/src/engine/screens.tsx +24 -0
- package/src/interfaces/ComponentEvents.ts +2 -2
- package/src/interfaces/options/animations.ts +40 -15
- package/src/interfaces/options/bottomTabs.ts +2 -2
- package/src/interfaces/options/buttons.ts +2 -2
- package/src/interfaces/options/modals.ts +6 -7
- package/src/interfaces/options/stack.ts +8 -3
- package/src/interfaces/options/topBar.ts +14 -0
- package/android/src/main/java/dev/apexnative/navigation/views/element/ElementStub.kt +0 -31
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ImageMatrixAnimator.kt +0 -134
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/PlainViewAnimator.kt +0 -78
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/PropertyAnimatorCreator.kt +0 -33
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ReactImageAnimator.kt +0 -57
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ViewChangeAnimator.kt +0 -146
|
@@ -1,75 +1,85 @@
|
|
|
1
1
|
package dev.apexnative.navigation.views.element.animators
|
|
2
2
|
|
|
3
|
-
import android.animation.Animator
|
|
4
3
|
import android.view.View
|
|
5
4
|
import android.widget.ImageView
|
|
6
|
-
import com.facebook.react.views.image.ReactImageView
|
|
7
5
|
import com.facebook.react.views.text.ReactTextView
|
|
8
|
-
import com.facebook.react.views.view.ReactViewGroup
|
|
9
6
|
import dev.apexnative.navigation.options.SharedElementTransitionOptions
|
|
10
7
|
import dev.apexnative.navigation.views.animations.AnimationRules
|
|
11
8
|
import dev.apexnative.navigation.views.animations.Curves
|
|
12
|
-
import dev.apexnative.navigation.views.element.
|
|
9
|
+
import dev.apexnative.navigation.views.element.elementSkipped
|
|
13
10
|
import dev.apexnative.navigation.views.element.pairName
|
|
14
11
|
|
|
15
12
|
/**
|
|
16
|
-
* The
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* Main thread only.
|
|
13
|
+
* The flight of a shared pair, as on iOS: a copy drawn in the transition's layer, chosen by the kinds of the two views,
|
|
14
|
+
* by explicit classes, never by reflection — texts ([TextMorph]), images ([ImageMorph]; one without an image to fit
|
|
15
|
+
* flies as a view), any other views ([ViewMorph]). The views themselves are neither moved nor changed. The animator
|
|
16
|
+
* gets the pair's duration (else the fallback, the screen's fade), its delay and its curve here, each of its own (a
|
|
17
|
+
* spring in real time); an `AnimatorSet` around it never sets them. Main thread only.
|
|
22
18
|
*/
|
|
23
19
|
internal object SharedAnimatorFactory {
|
|
24
|
-
/**
|
|
25
|
-
|
|
26
|
-
* modules), or by moving `to` itself, which shows from the start of the flight.
|
|
27
|
-
*/
|
|
28
|
-
class Flight(val animator: Animator, val drawsPictures: Boolean)
|
|
20
|
+
/** A pair's animator and the copy it moves. */
|
|
21
|
+
class Flight(val animator: MoveAnimator, val picture: FlightPicture)
|
|
29
22
|
|
|
30
23
|
/**
|
|
31
|
-
* The flight of the pair [from] → [to]
|
|
32
|
-
*
|
|
33
|
-
* pair doesn't fly
|
|
24
|
+
* The flight of the pair [from] → [to] in [layer], its pictures taken now; a view or an image shows only the part
|
|
25
|
+
* its parents up to the view of its screen ([fromRoot], [toRoot]) leave visible, a text shows whole, as on iOS.
|
|
26
|
+
* None: the pair doesn't fly — a text that doesn't change, or, with a line in [log], a view without a size or a
|
|
27
|
+
* picture that can't be taken.
|
|
34
28
|
*/
|
|
35
29
|
fun create(
|
|
36
30
|
from: View,
|
|
37
31
|
to: View,
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
layer:
|
|
32
|
+
fromRoot: View?,
|
|
33
|
+
toRoot: View?,
|
|
34
|
+
layer: View,
|
|
41
35
|
options: SharedElementTransitionOptions,
|
|
42
36
|
fallbackDuration: Long,
|
|
43
37
|
log: (String) -> Unit,
|
|
44
38
|
): Flight? {
|
|
45
|
-
val
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
39
|
+
val name = pairName(options.fromId.get(""), options.toId.get(""))
|
|
40
|
+
if (from.width <= 0 || from.height <= 0 || to.width <= 0 || to.height <= 0) {
|
|
41
|
+
elementSkipped(name, "a view of the pair has no size, it isn't laid out", log)
|
|
42
|
+
return null
|
|
43
|
+
}
|
|
44
|
+
val picture = if (from is ReactTextView && to is ReactTextView) {
|
|
45
|
+
val text = TextMorph.of(from, to, layer) ?: return noPicture(name, log)
|
|
46
|
+
if (!text.changes) return null
|
|
47
|
+
text
|
|
48
|
+
} else {
|
|
49
|
+
val image = if (from is ImageView && to is ImageView) {
|
|
50
|
+
ImageMorph.of(from, to, fromRoot, toRoot, layer)
|
|
51
|
+
} else {
|
|
52
|
+
null
|
|
53
|
+
}
|
|
54
|
+
image ?: ViewMorph.of(from, to, fromRoot, toRoot, layer) ?: return noPicture(name, log)
|
|
55
|
+
}
|
|
56
|
+
val animator = MoveAnimator().apply {
|
|
57
|
+
element = name
|
|
58
|
+
onStart {
|
|
59
|
+
picture.shown = true
|
|
60
|
+
picture.update(0f, curve.getInterpolation(0f))
|
|
61
|
+
layer.invalidate()
|
|
62
|
+
}
|
|
63
|
+
onFrame {
|
|
64
|
+
picture.update(it, curve.getInterpolation(it))
|
|
65
|
+
layer.invalidate()
|
|
66
|
+
}
|
|
67
|
+
// A flight that landed keeps its last frame until the transition takes the layer away: the screens may
|
|
68
|
+
// still move. A stopped one draws nothing more.
|
|
69
|
+
onEnd {
|
|
70
|
+
if (!landed) picture.shown = false
|
|
71
|
+
layer.invalidate()
|
|
72
|
+
}
|
|
73
|
+
}
|
|
63
74
|
val duration = AnimationRules.durationOf(options.duration.get(null), fallbackDuration)
|
|
64
75
|
animator.duration = duration
|
|
65
76
|
animator.startDelay = AnimationRules.delayOf(options.startDelay.get(null))
|
|
66
77
|
animator.interpolator = Curves.of(options.interpolation, duration)
|
|
67
|
-
return
|
|
78
|
+
return Flight(animator, picture)
|
|
68
79
|
}
|
|
69
80
|
|
|
70
|
-
private fun
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
private fun hasChildren(view: View): Boolean = view is ReactViewGroup && view.childCount > 0
|
|
81
|
+
private fun noPicture(name: String, log: (String) -> Unit): Flight? {
|
|
82
|
+
elementSkipped(name, "no picture of a view of the pair can be taken", log)
|
|
83
|
+
return null
|
|
84
|
+
}
|
|
75
85
|
}
|
|
@@ -1,91 +1,105 @@
|
|
|
1
1
|
package dev.apexnative.navigation.views.element.animators
|
|
2
2
|
|
|
3
|
-
import android.animation.Animator
|
|
4
3
|
import android.graphics.Canvas
|
|
5
|
-
import android.graphics.ColorFilter
|
|
6
4
|
import android.graphics.Picture
|
|
7
|
-
import android.graphics.PixelFormat
|
|
8
5
|
import android.graphics.PointF
|
|
9
|
-
import android.graphics.drawable.Drawable
|
|
10
6
|
import android.text.Layout
|
|
11
7
|
import android.view.View
|
|
12
|
-
import android.view.ViewGroup
|
|
13
8
|
import android.widget.TextView
|
|
14
9
|
import com.facebook.react.views.text.ReactTextView
|
|
15
|
-
import dev.apexnative.navigation.options.SharedElementTransitionOptions
|
|
16
10
|
import dev.apexnative.navigation.utils.TextViewUtils
|
|
17
11
|
import dev.apexnative.navigation.views.animations.ValueInterpolation
|
|
18
12
|
import kotlin.math.abs
|
|
19
13
|
import kotlin.math.min
|
|
20
14
|
import kotlin.math.roundToInt
|
|
21
15
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
)
|
|
35
|
-
private val pictures by lazy { pictures() }
|
|
16
|
+
/**
|
|
17
|
+
* The text moves as two pictures of itself, of the text that goes away and of the text that comes, the same text or
|
|
18
|
+
* another. Both keep their proportions, scaled by the font size from a point of the first line, and one turns into the
|
|
19
|
+
* other in a quarter of the move: at its start when the text grows, at its end when it shrinks, so the larger picture
|
|
20
|
+
* shows most of the way (as on iOS). Each text is where it is drawn, at the scale and angle its parents and its own
|
|
21
|
+
* properties give it; the angle goes along the shorter arc ([FlightGeometry]). The pictures are drawing commands, not
|
|
22
|
+
* pixels: they stay sharp at any scale and keep the colors, emoji and background of the text.
|
|
23
|
+
*/
|
|
24
|
+
internal class TextMorph private constructor(private val start: TextPicture, private val end: TextPicture) :
|
|
25
|
+
FlightPicture() {
|
|
26
|
+
/** Whether the text changes on the way: another text, another size, or drawn elsewhere. */
|
|
27
|
+
val changes: Boolean
|
|
28
|
+
get() = start.text != end.text || start.fontSize != end.fontSize || start.drawnElsewhere(end)
|
|
36
29
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
30
|
+
private val grows = end.shownSize >= start.shownSize
|
|
31
|
+
private var progress = 0f
|
|
32
|
+
private var time = 0f
|
|
33
|
+
private var changeOver = 0f
|
|
34
|
+
private var mirrorX = 1f
|
|
35
|
+
private var mirrorY = 1f
|
|
36
|
+
|
|
37
|
+
override fun update(time: Float, progress: Float) {
|
|
38
|
+
this.progress = progress
|
|
39
|
+
this.time = time
|
|
40
|
+
val changeOverStart = if (grows) 0f else 1f - CHANGE_OVER
|
|
41
|
+
changeOver = ((time - changeOverStart) / CHANGE_OVER).coerceIn(0f, 1f)
|
|
41
42
|
}
|
|
42
43
|
|
|
43
|
-
override fun
|
|
44
|
-
val
|
|
45
|
-
val
|
|
46
|
-
val
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
44
|
+
override fun draw(canvas: Canvas) {
|
|
45
|
+
val x = start.position.x + (end.position.x - start.position.x) * progress
|
|
46
|
+
val y = start.position.y + (end.position.y - start.position.y) * progress
|
|
47
|
+
val fontSize = start.shownSize + (end.shownSize - start.shownSize) * progress
|
|
48
|
+
val rotation = ValueInterpolation.angle(start.rotation, end.rotation, progress, time)
|
|
49
|
+
mirrorX = ValueInterpolation.number(start.mirrorX, end.mirrorX, progress, time)
|
|
50
|
+
mirrorY = ValueInterpolation.number(start.mirrorY, end.mirrorY, progress, time)
|
|
51
|
+
draw(canvas, start, x, y, fontSize, rotation, 1f - changeOver)
|
|
52
|
+
draw(canvas, end, x, y, fontSize, rotation, changeOver)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
private fun draw(
|
|
56
|
+
canvas: Canvas,
|
|
57
|
+
text: TextPicture,
|
|
58
|
+
x: Float,
|
|
59
|
+
y: Float,
|
|
60
|
+
fontSize: Float,
|
|
61
|
+
rotation: Float,
|
|
62
|
+
shown: Float,
|
|
63
|
+
) {
|
|
64
|
+
val alpha = (shown * text.alpha * 255).roundToInt().coerceIn(0, 255)
|
|
65
|
+
if (alpha == 0) return
|
|
66
|
+
val scale = fontSize / text.fontSize
|
|
67
|
+
val count = canvas.save()
|
|
68
|
+
canvas.translate(x, y)
|
|
69
|
+
canvas.rotate(rotation)
|
|
70
|
+
canvas.scale(scale * mirrorX, scale * mirrorY)
|
|
71
|
+
canvas.translate(-text.anchor.x, -text.anchor.y)
|
|
72
|
+
// The picture fades as a whole: its letters and background don't show through each other.
|
|
73
|
+
if (alpha < 255) {
|
|
74
|
+
canvas.saveLayerAlpha(0f, 0f, text.picture.width.toFloat(), text.picture.height.toFloat(), alpha)
|
|
68
75
|
}
|
|
76
|
+
canvas.drawPicture(text.picture)
|
|
77
|
+
canvas.restoreToCount(count)
|
|
69
78
|
}
|
|
70
79
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
80
|
+
companion object {
|
|
81
|
+
private const val CHANGE_OVER = 0.25f
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* The morph of [from] into [to] in [layer]; none when a text isn't laid out or its picture can't be taken.
|
|
85
|
+
* Texts that line up the same way go from that point of their first lines (the same text lies over itself);
|
|
86
|
+
* others from the start of the line, as on iOS: a centered text no longer sticks out of a text at the start.
|
|
87
|
+
*/
|
|
88
|
+
fun of(from: ReactTextView, to: ReactTextView, layer: View): TextMorph? {
|
|
89
|
+
val fromLayout = from.layout ?: return null
|
|
90
|
+
val toLayout = to.layout ?: return null
|
|
91
|
+
val edge = lineEdge(fromLayout).takeIf { it == lineEdge(toLayout) } ?: LineEdge.START
|
|
92
|
+
val start = TextPicture.of(from, LayerPlace.of(from, layer), edge) ?: return null
|
|
93
|
+
val end = TextPicture.of(to, LayerPlace.of(to, layer), edge) ?: return null
|
|
94
|
+
return TextMorph(start, end)
|
|
95
|
+
}
|
|
83
96
|
}
|
|
84
97
|
}
|
|
85
98
|
|
|
86
|
-
// A text's picture, the point of its first line it is scaled from (in the view) and where that point is
|
|
87
|
-
// transition layer, its font size, the scale and angle it is drawn at, and its opacity.
|
|
99
|
+
// A text's picture and its text, the point of its first line it is scaled from (in the view) and where that point is
|
|
100
|
+
// drawn in the transition layer, its font size, the scale and angle it is drawn at, and its opacity.
|
|
88
101
|
private class TextPicture(
|
|
102
|
+
val text: String,
|
|
89
103
|
val picture: Picture,
|
|
90
104
|
val anchor: PointF,
|
|
91
105
|
val position: PointF,
|
|
@@ -124,7 +138,8 @@ private class TextPicture(
|
|
|
124
138
|
val position = place.point(anchor.x, anchor.y)
|
|
125
139
|
val scale = min(abs(place.scaleX), abs(place.scaleY))
|
|
126
140
|
return TextPicture(
|
|
127
|
-
picture, anchor, PointF(position[0], position[1]), fontSize, scale,
|
|
141
|
+
view.text.toString(), picture, anchor, PointF(position[0], position[1]), fontSize, scale,
|
|
142
|
+
place.rotation,
|
|
128
143
|
mirrorX = if (place.scaleX < 0) -1f else 1f,
|
|
129
144
|
mirrorY = if (place.scaleY < 0) -1f else 1f,
|
|
130
145
|
alpha = view.alpha,
|
|
@@ -159,68 +174,3 @@ private fun lineEdge(layout: Layout): LineEdge {
|
|
|
159
174
|
else -> LineEdge.START
|
|
160
175
|
}
|
|
161
176
|
}
|
|
162
|
-
|
|
163
|
-
// Both pictures where the move has brought the text: the font size it shows at, its angle and the point of the first
|
|
164
|
-
// line go from the start to the end along the transition's curve, the pictures change over by the clock.
|
|
165
|
-
private class TextMorphDrawable(private val start: TextPicture, private val end: TextPicture) : Drawable() {
|
|
166
|
-
private val grows = end.shownSize >= start.shownSize
|
|
167
|
-
private var progress = 0f
|
|
168
|
-
private var time = 0f
|
|
169
|
-
private var changeOver = 0f
|
|
170
|
-
private var mirrorX = 1f
|
|
171
|
-
private var mirrorY = 1f
|
|
172
|
-
|
|
173
|
-
fun update(time: Float, progress: Float) {
|
|
174
|
-
this.progress = progress
|
|
175
|
-
this.time = time
|
|
176
|
-
val changeOverStart = if (grows) 0f else 1f - CHANGE_OVER
|
|
177
|
-
changeOver = ((time - changeOverStart) / CHANGE_OVER).coerceIn(0f, 1f)
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
override fun draw(canvas: Canvas) {
|
|
181
|
-
val x = start.position.x + (end.position.x - start.position.x) * progress
|
|
182
|
-
val y = start.position.y + (end.position.y - start.position.y) * progress
|
|
183
|
-
val fontSize = start.shownSize + (end.shownSize - start.shownSize) * progress
|
|
184
|
-
val rotation = ValueInterpolation.angle(start.rotation, end.rotation, progress, time)
|
|
185
|
-
mirrorX = ValueInterpolation.number(start.mirrorX, end.mirrorX, progress, time)
|
|
186
|
-
mirrorY = ValueInterpolation.number(start.mirrorY, end.mirrorY, progress, time)
|
|
187
|
-
draw(canvas, start, x, y, fontSize, rotation, 1f - changeOver)
|
|
188
|
-
draw(canvas, end, x, y, fontSize, rotation, changeOver)
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
private fun draw(
|
|
192
|
-
canvas: Canvas,
|
|
193
|
-
text: TextPicture,
|
|
194
|
-
x: Float,
|
|
195
|
-
y: Float,
|
|
196
|
-
fontSize: Float,
|
|
197
|
-
rotation: Float,
|
|
198
|
-
shown: Float,
|
|
199
|
-
) {
|
|
200
|
-
val alpha = (shown * text.alpha * 255).roundToInt().coerceIn(0, 255)
|
|
201
|
-
if (alpha == 0) return
|
|
202
|
-
val scale = fontSize / text.fontSize
|
|
203
|
-
val count = canvas.save()
|
|
204
|
-
canvas.translate(x, y)
|
|
205
|
-
canvas.rotate(rotation)
|
|
206
|
-
canvas.scale(scale * mirrorX, scale * mirrorY)
|
|
207
|
-
canvas.translate(-text.anchor.x, -text.anchor.y)
|
|
208
|
-
// The picture fades as a whole: its letters and background don't show through each other.
|
|
209
|
-
if (alpha < 255) {
|
|
210
|
-
canvas.saveLayerAlpha(0f, 0f, text.picture.width.toFloat(), text.picture.height.toFloat(), alpha)
|
|
211
|
-
}
|
|
212
|
-
canvas.drawPicture(text.picture)
|
|
213
|
-
canvas.restoreToCount(count)
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
override fun setAlpha(alpha: Int) = Unit
|
|
217
|
-
|
|
218
|
-
override fun setColorFilter(colorFilter: ColorFilter?) = Unit
|
|
219
|
-
|
|
220
|
-
@Deprecated("Deprecated in Java")
|
|
221
|
-
override fun getOpacity(): Int = PixelFormat.TRANSLUCENT
|
|
222
|
-
|
|
223
|
-
private companion object {
|
|
224
|
-
const val CHANGE_OVER = 0.25f
|
|
225
|
-
}
|
|
226
|
-
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
package dev.apexnative.navigation.views.element.animators
|
|
2
|
+
|
|
3
|
+
import android.graphics.Canvas
|
|
4
|
+
import android.graphics.Paint
|
|
5
|
+
import android.graphics.Picture
|
|
6
|
+
import android.graphics.PorterDuff
|
|
7
|
+
import android.graphics.PorterDuffXfermode
|
|
8
|
+
import android.graphics.RectF
|
|
9
|
+
import android.view.View
|
|
10
|
+
import dev.apexnative.navigation.utils.borderRadius
|
|
11
|
+
import kotlin.math.roundToInt
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* A shared view moves as two pictures of itself, as on iOS: of the view that goes away and of the one that comes, each
|
|
15
|
+
* with its children. The copy goes from where the one is drawn — its center, its size at the scale it is drawn at, its
|
|
16
|
+
* angle and corner radius — to where the other is drawn in its screen ([FlightGeometry]), the angle along the shorter
|
|
17
|
+
* arc; both pictures fill it, and the picture of the destination shows over the other on the way. Where a parent cuts
|
|
18
|
+
* a view (`overflow: hidden`, a scroll view, the screen's edge), only the part that shows flies, the mask going from
|
|
19
|
+
* one end's part to the other's ([FlightMask]), as on iOS. The pictures are drawing commands, taken before the views
|
|
20
|
+
* hide: an avatar's letter grows sharp, and what changes in the views meanwhile shows when they are back.
|
|
21
|
+
*/
|
|
22
|
+
internal class ViewMorph private constructor(
|
|
23
|
+
private val start: ViewPicture,
|
|
24
|
+
private val end: ViewPicture,
|
|
25
|
+
) : FlightPicture() {
|
|
26
|
+
private val flight = FlightGeometry(start.end, end.end)
|
|
27
|
+
private val cut = FlightMask.of(start.visible, end.visible)?.let(::MaskCut)
|
|
28
|
+
private var at = start.end
|
|
29
|
+
private var progress = 0f
|
|
30
|
+
private val rect = RectF()
|
|
31
|
+
private val maskPaint = Paint(Paint.ANTI_ALIAS_FLAG)
|
|
32
|
+
// What is drawn over the mask keeps only the mask's pixels: the corners stay smooth (a clip path on the hardware
|
|
33
|
+
// canvas is not anti-aliased).
|
|
34
|
+
private val contentPaint = Paint().apply { xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN) }
|
|
35
|
+
|
|
36
|
+
override fun update(time: Float, progress: Float) {
|
|
37
|
+
this.progress = progress
|
|
38
|
+
at = flight.at(progress, time)
|
|
39
|
+
cut?.update(time, progress)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
override fun draw(canvas: Canvas) {
|
|
43
|
+
rect.set(-at.width / 2, -at.height / 2, at.width / 2, at.height / 2)
|
|
44
|
+
if (rect.isEmpty) return
|
|
45
|
+
val radius = lerp(start.radius, end.radius)
|
|
46
|
+
// The copy turns about its center, mirrored where a view is.
|
|
47
|
+
canvas.translate(at.centerX, at.centerY)
|
|
48
|
+
canvas.rotate(at.rotation)
|
|
49
|
+
canvas.scale(at.mirrorX, at.mirrorY)
|
|
50
|
+
canvas.saveLayer(rect, null)
|
|
51
|
+
canvas.drawRoundRect(rect, radius, radius, maskPaint)
|
|
52
|
+
cut?.draw(canvas, rect)
|
|
53
|
+
canvas.saveLayer(rect, contentPaint)
|
|
54
|
+
draw(canvas, start, start.alpha)
|
|
55
|
+
draw(canvas, end, end.alpha * progress)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// A picture fills the copy, as on iOS.
|
|
59
|
+
private fun draw(canvas: Canvas, view: ViewPicture, shown: Float) {
|
|
60
|
+
val alpha = (shown * 255).roundToInt().coerceIn(0, 255)
|
|
61
|
+
if (alpha == 0) return
|
|
62
|
+
val width = view.picture.width.toFloat()
|
|
63
|
+
val height = view.picture.height.toFloat()
|
|
64
|
+
val count = canvas.save()
|
|
65
|
+
canvas.translate(rect.left, rect.top)
|
|
66
|
+
canvas.scale(rect.width() / width, rect.height() / height)
|
|
67
|
+
// The picture fades as a whole: its children and background don't show through each other.
|
|
68
|
+
if (alpha < 255) canvas.saveLayerAlpha(0f, 0f, width, height, alpha)
|
|
69
|
+
canvas.drawPicture(view.picture)
|
|
70
|
+
canvas.restoreToCount(count)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
private fun lerp(from: Float, to: Float) = from + (to - from) * progress
|
|
74
|
+
|
|
75
|
+
companion object {
|
|
76
|
+
/**
|
|
77
|
+
* The morph of [from] into [to] in [layer], each cut by its parents up to the view of its screen ([fromRoot],
|
|
78
|
+
* [toRoot]); none when a picture of either can't be taken.
|
|
79
|
+
*/
|
|
80
|
+
fun of(from: View, to: View, fromRoot: View?, toRoot: View?, layer: View): ViewMorph? {
|
|
81
|
+
val start = ViewPicture.of(from, LayerPlace.of(from, layer, fromRoot)) ?: return null
|
|
82
|
+
val end = ViewPicture.of(to, LayerPlace.of(to, layer, toRoot)) ?: return null
|
|
83
|
+
return ViewMorph(start, end)
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// A view's picture, where it is drawn in the transition layer, its corner radius there, its opacity and the part of it
|
|
89
|
+
// that shows.
|
|
90
|
+
private class ViewPicture(
|
|
91
|
+
val picture: Picture,
|
|
92
|
+
val end: FlightEnd,
|
|
93
|
+
val radius: Float,
|
|
94
|
+
val alpha: Float,
|
|
95
|
+
val visible: VisiblePart,
|
|
96
|
+
) {
|
|
97
|
+
companion object {
|
|
98
|
+
fun of(view: View, place: LayerPlace): ViewPicture? {
|
|
99
|
+
if (view.width <= 0 || view.height <= 0) return null
|
|
100
|
+
val picture = recordPicture(view) ?: return null
|
|
101
|
+
val end = place.end(view.width, view.height)
|
|
102
|
+
val radius = view.borderRadius
|
|
103
|
+
return ViewPicture(
|
|
104
|
+
picture, end, radius * end.scale, view.alpha, place.visible(view.width, view.height, radius),
|
|
105
|
+
)
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
package dev.apexnative.navigation.views.stack.fab
|
|
2
|
+
|
|
3
|
+
import android.annotation.SuppressLint
|
|
4
|
+
import android.content.Context
|
|
5
|
+
import android.graphics.Canvas
|
|
6
|
+
import android.graphics.Outline
|
|
7
|
+
import android.graphics.Picture
|
|
8
|
+
import android.os.Build
|
|
9
|
+
import android.view.Gravity
|
|
10
|
+
import android.view.View
|
|
11
|
+
import android.view.ViewGroup
|
|
12
|
+
import android.view.ViewOutlineProvider
|
|
13
|
+
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
|
14
|
+
import dev.apexnative.navigation.views.element.animators.recordPicture
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* The picture of a FAB that leaves with its screen while the new top's FAB arrives: drawn as the button was, with the
|
|
18
|
+
* shadow of its shape, taking no touches and hidden from accessibility. The live button goes from its parent at once.
|
|
19
|
+
*/
|
|
20
|
+
@SuppressLint("ViewConstructor")
|
|
21
|
+
internal class FabCopy private constructor(
|
|
22
|
+
context: Context,
|
|
23
|
+
private val picture: Picture,
|
|
24
|
+
shape: Outline,
|
|
25
|
+
) : View(context) {
|
|
26
|
+
init {
|
|
27
|
+
importantForAccessibility = IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
|
|
28
|
+
outlineProvider = object : ViewOutlineProvider() {
|
|
29
|
+
override fun getOutline(view: View, outline: Outline) = outline.set(shape)
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
override fun onDraw(canvas: Canvas) {
|
|
34
|
+
canvas.drawPicture(picture)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
companion object {
|
|
38
|
+
/**
|
|
39
|
+
* A copy of [button] in [container], a child of [parent] (the button itself, or its menu), as it shows now: in
|
|
40
|
+
* its place in [parent], moved, scaled and faded as it is. None when it doesn't show or can't be recorded (a
|
|
41
|
+
* hardware bitmap in its icon before Android 9).
|
|
42
|
+
*/
|
|
43
|
+
fun of(button: View, container: View, parent: ViewGroup): FabCopy? {
|
|
44
|
+
if (container.parent !== parent || !button.isAttachedToWindow) return null
|
|
45
|
+
if (button.width <= 0 || button.height <= 0) return null
|
|
46
|
+
if (container.visibility != VISIBLE || button.visibility != VISIBLE) return null
|
|
47
|
+
val inner = button !== container
|
|
48
|
+
val alpha = container.alpha * if (inner) button.alpha else 1f
|
|
49
|
+
val scale = container.scaleX * if (inner) button.scaleX else 1f
|
|
50
|
+
if (alpha <= 0f || scale <= 0f) return null
|
|
51
|
+
val picture = recordPicture(button) ?: return null
|
|
52
|
+
val shape = Outline().apply {
|
|
53
|
+
// As the view counts its own outline: opaque unless the provider says otherwise.
|
|
54
|
+
this.alpha = 1f
|
|
55
|
+
button.outlineProvider?.getOutline(button, this)
|
|
56
|
+
}
|
|
57
|
+
val copy = FabCopy(button.context, picture, shape)
|
|
58
|
+
val left = container.left + if (inner) button.left else 0
|
|
59
|
+
val top = container.top + if (inner) button.top else 0
|
|
60
|
+
copy.translationX = container.translationX + if (inner) button.translationX else 0f
|
|
61
|
+
copy.translationY = container.translationY + if (inner) button.translationY else 0f
|
|
62
|
+
copy.scaleX = scale
|
|
63
|
+
copy.scaleY = scale
|
|
64
|
+
copy.alpha = alpha
|
|
65
|
+
copy.elevation = button.elevation
|
|
66
|
+
copy.translationZ = button.translationZ
|
|
67
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
|
68
|
+
copy.outlineAmbientShadowColor = button.outlineAmbientShadowColor
|
|
69
|
+
copy.outlineSpotShadowColor = button.outlineSpotShadowColor
|
|
70
|
+
}
|
|
71
|
+
parent.addView(copy, CoordinatorLayout.LayoutParams(button.width, button.height).apply {
|
|
72
|
+
gravity = Gravity.TOP or Gravity.LEFT
|
|
73
|
+
leftMargin = left
|
|
74
|
+
topMargin = top
|
|
75
|
+
})
|
|
76
|
+
// In its place before the next layout, so its first frame draws.
|
|
77
|
+
copy.measure(
|
|
78
|
+
MeasureSpec.makeMeasureSpec(button.width, MeasureSpec.EXACTLY),
|
|
79
|
+
MeasureSpec.makeMeasureSpec(button.height, MeasureSpec.EXACTLY),
|
|
80
|
+
)
|
|
81
|
+
copy.layout(left, top, left + button.width, top + button.height)
|
|
82
|
+
return copy
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -120,6 +120,19 @@ class FabMenu(context: Context, val fabId: String) : LinearLayout(context), FabA
|
|
|
120
120
|
(view.parent as? ViewGroup)?.removeView(view)
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
+
/**
|
|
124
|
+
* The menu closes and leaves its parent next: a scrim that shows fades out by itself and goes from the parent at
|
|
125
|
+
* the end of its fade, which the menu no longer owns; it takes no touches meanwhile, which belong to the new screen.
|
|
126
|
+
*/
|
|
127
|
+
fun closeToLeave() {
|
|
128
|
+
close()
|
|
129
|
+
scrim?.apply {
|
|
130
|
+
setOnClickListener(null)
|
|
131
|
+
isClickable = false
|
|
132
|
+
}
|
|
133
|
+
scrim = null
|
|
134
|
+
}
|
|
135
|
+
|
|
123
136
|
override fun show() = main.show()
|
|
124
137
|
|
|
125
138
|
override fun hide() {
|