├── app
├── .gitignore
├── src
│ └── main
│ │ ├── res
│ │ ├── drawable
│ │ │ ├── metalogo.png
│ │ │ ├── empty.xml
│ │ │ ├── shape_thumb.xml
│ │ │ ├── ic_home_black_24dp.xml
│ │ │ ├── ic_pause.xml
│ │ │ ├── ic_volume_medium.xml
│ │ │ ├── ic_fast_forward.xml
│ │ │ ├── ic_fast_rewind.xml
│ │ │ ├── ic_baseline_arrow_back_24.xml
│ │ │ ├── ic_dashboard_black_24dp.xml
│ │ │ ├── ic_outline_play_arrow_24.xml
│ │ │ ├── ic_arrow_back.xml
│ │ │ ├── ic_baseline_reorder_24.xml
│ │ │ ├── ic_baseline_save_24.xml
│ │ │ ├── ic_volume_high.xml
│ │ │ ├── ic_volume_bottom.xml
│ │ │ ├── ic_notifications_black_24dp.xml
│ │ │ ├── ic_baseline_search_24.xml
│ │ │ └── ic_launcher_background.xml
│ │ ├── mipmap-hdpi
│ │ │ ├── ic_launcher.webp
│ │ │ └── ic_launcher_round.webp
│ │ ├── mipmap-mdpi
│ │ │ ├── ic_launcher.webp
│ │ │ └── ic_launcher_round.webp
│ │ ├── mipmap-xhdpi
│ │ │ ├── ic_launcher.webp
│ │ │ └── ic_launcher_round.webp
│ │ ├── mipmap-xxhdpi
│ │ │ ├── ic_launcher.webp
│ │ │ └── ic_launcher_round.webp
│ │ ├── mipmap-xxxhdpi
│ │ │ ├── ic_launcher.webp
│ │ │ └── ic_launcher_round.webp
│ │ ├── layout
│ │ │ ├── activity_animations.xml
│ │ │ ├── activity_window_animations.xml
│ │ │ ├── custom_layout.xml
│ │ │ ├── activity_home.xml
│ │ │ ├── fragment_home.xml
│ │ │ ├── activity_main.xml
│ │ │ ├── activity_host_activty.xml
│ │ │ ├── item_artist.xml
│ │ │ ├── fragment_add_note.xml
│ │ │ ├── fragment_list.xml
│ │ │ ├── fragment_dashboard.xml
│ │ │ ├── artist_linear_list.xml
│ │ │ └── fragment_notifications.xml
│ │ ├── raw
│ │ │ ├── grid.json
│ │ │ └── list.json
│ │ ├── values
│ │ │ ├── integers.xml
│ │ │ ├── strings.xml
│ │ │ ├── dimens.xml
│ │ │ ├── colors.xml
│ │ │ └── themes.xml
│ │ ├── anim
│ │ │ ├── layout_animation_fall_down.xml
│ │ │ └── item_animation_fall_down.xml
│ │ ├── mipmap-anydpi-v26
│ │ │ ├── ic_launcher.xml
│ │ │ └── ic_launcher_round.xml
│ │ ├── menu
│ │ │ └── bottom_nav_menu.xml
│ │ ├── values-night
│ │ │ └── themes.xml
│ │ ├── drawable-v24
│ │ │ └── ic_launcher_foreground.xml
│ │ └── navigation
│ │ │ └── mobile_navigation.xml
│ │ ├── java
│ │ └── com
│ │ │ └── androidpoet
│ │ │ └── metaphordemo
│ │ │ ├── ui
│ │ │ ├── home
│ │ │ │ ├── SampleResponse.kt
│ │ │ │ ├── ArtistViewHolder.kt
│ │ │ │ ├── ArtistLinearViewHolder.kt
│ │ │ │ ├── AddNoteFragment.kt
│ │ │ │ ├── ArtistGridListAdapter.kt
│ │ │ │ ├── ArtistLinearListAdapter.kt
│ │ │ │ ├── ArtistDetailFragment.kt
│ │ │ │ └── ArtistListFragment.kt
│ │ │ ├── notifications
│ │ │ │ └── NotificationsFragment.kt
│ │ │ └── dashboard
│ │ │ │ └── DashboardFragment.kt
│ │ │ ├── factory
│ │ │ ├── MetaphorFragmentFactory.kt
│ │ │ └── MetaphorActivityFactory.kt
│ │ │ ├── activties
│ │ │ ├── MainActivity.kt
│ │ │ └── FragmentHostActivty.kt
│ │ │ └── MetaphorUtils.kt
│ │ └── AndroidManifest.xml
├── .editorconfig
├── proguard-rules.pro
└── build.gradle
├── spotless.license.kt
├── metaphor
├── .gitignore
├── consumer-rules.pro
├── src
│ └── main
│ │ ├── java
│ │ └── com
│ │ │ └── androidpoet
│ │ │ └── metaphor
│ │ │ ├── MetaphorInterpolator.kt
│ │ │ ├── MetaphorAnimation.kt
│ │ │ ├── WindowExtenstions.kt
│ │ │ ├── MetaphorLazyExtension.kt
│ │ │ ├── internals
│ │ │ ├── FragmentMetaphorLazy.kt
│ │ │ └── ActivityMetaphorLazy.kt
│ │ │ ├── FragmentExtensions.kt
│ │ │ ├── MetaphorView.kt
│ │ │ ├── ActivityExtenstions.kt
│ │ │ ├── MetaphorWindow.kt
│ │ │ ├── ViewExtensions.kt
│ │ │ ├── AnimationsExtenstions.kt
│ │ │ ├── MetaphorActivity.kt
│ │ │ └── MetaphorFragment.kt
│ │ ├── res
│ │ ├── values
│ │ │ ├── strings.xml
│ │ │ ├── metaphormotion.xml
│ │ │ └── ids.xml
│ │ └── drawable
│ │ │ ├── circle_gray.xml
│ │ │ ├── circle_white.xml
│ │ │ ├── ic_baseline_add_24.xml
│ │ │ ├── ic_home_gray_24dp.xml
│ │ │ └── ic_home_white_24dp.xml
│ │ └── AndroidManifest.xml
├── proguard-rules.pro
└── build.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── .github
└── FUNDING.yml
├── .gitignore
├── usecases.md
├── settings.gradle
├── spotless.gradle
├── dependencies.gradle
├── gradlew.bat
├── gradle.properties
└── gradlew
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/spotless.license.kt:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/metaphor/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/metaphor/consumer-rules.pro:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AndroidPoet/Metaphor/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/app/src/main/res/drawable/metalogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AndroidPoet/Metaphor/HEAD/app/src/main/res/drawable/metalogo.png
--------------------------------------------------------------------------------
/app/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 | [*]
3 | # Most of the standard properties are supported
4 | indent_size=2
5 | max_line_length=100
6 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AndroidPoet/Metaphor/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AndroidPoet/Metaphor/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AndroidPoet/Metaphor/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 | github: AndroidPoet
3 | custom: ["https://www.buymeacoffee.com/AndroidPoet"]
4 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AndroidPoet/Metaphor/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AndroidPoet/Metaphor/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AndroidPoet/Metaphor/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AndroidPoet/Metaphor/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AndroidPoet/Metaphor/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AndroidPoet/Metaphor/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AndroidPoet/Metaphor/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/metaphor/src/main/java/com/androidpoet/metaphor/MetaphorInterpolator.kt:
--------------------------------------------------------------------------------
1 |
2 | package com.androidpoet.metaphor
3 |
4 | public enum class MetaphorInterpolator(public val value: Int) {
5 | Standard(2),
6 | Emphasized(3),
7 | Decelerated(4),
8 | Accelerated(5),
9 | Linear(6)
10 | }
11 |
--------------------------------------------------------------------------------
/app/src/main/java/com/androidpoet/metaphordemo/ui/home/SampleResponse.kt:
--------------------------------------------------------------------------------
1 |
2 | package com.androidpoet.metaphordemo.ui.home
3 |
4 | import android.os.Parcelable
5 | import kotlinx.parcelize.Parcelize
6 |
7 | @Parcelize
8 |
9 | data class SampleResponse(var pos: Int, val blur: String, val img: String) : Parcelable
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea
5 | /.idea/caches
6 | /.idea/libraries
7 | /.idea/modules.xml
8 | /.idea/workspace.xml
9 | /.idea/navEditor.xml
10 | /.idea/assetWizardSettings.xml
11 | .DS_Store
12 | /build
13 | /captures
14 | .externalNativeBuild
15 | .cxx
16 | local.properties
17 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/java/com/androidpoet/metaphordemo/ui/home/ArtistViewHolder.kt:
--------------------------------------------------------------------------------
1 |
2 | package com.androidpoet.metaphordemo.ui.home
3 |
4 | import androidx.recyclerview.widget.RecyclerView
5 | import com.androidpoet.metaphordemo.databinding.ItemArtistBinding
6 |
7 | class ArtistViewHolder(val binding: ItemArtistBinding) : RecyclerView.ViewHolder(binding.root)
8 |
--------------------------------------------------------------------------------
/app/src/main/java/com/androidpoet/metaphordemo/ui/home/ArtistLinearViewHolder.kt:
--------------------------------------------------------------------------------
1 |
2 | package com.androidpoet.metaphordemo.ui.home
3 |
4 | import androidx.recyclerview.widget.RecyclerView
5 | import com.androidpoet.metaphordemo.databinding.ArtistLinearListBinding
6 |
7 | class ArtistLinearViewHolder(val binding: ArtistLinearListBinding) : RecyclerView.ViewHolder(binding.root)
8 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_animations.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_window_animations.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/java/com/androidpoet/metaphordemo/factory/MetaphorFragmentFactory.kt:
--------------------------------------------------------------------------------
1 |
2 | package com.androidpoet.metaphordemo.factory
3 |
4 | import androidx.fragment.app.Fragment
5 | import com.androidpoet.metaphor.MetaphorAnimation
6 | import com.androidpoet.metaphor.MetaphorFragment
7 |
8 | class MetaphorFragmentFactory : MetaphorFragment.Factory() {
9 | override fun create(fragment: Fragment): MetaphorFragment {
10 | return MetaphorFragment.Builder(fragment)
11 | .setEnterAnimation(MetaphorAnimation.ElevationScale)
12 | .setExitAnimation(MetaphorAnimation.SharedAxisXBackward)
13 | .build()
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/app/src/main/java/com/androidpoet/metaphordemo/factory/MetaphorActivityFactory.kt:
--------------------------------------------------------------------------------
1 |
2 | package com.androidpoet.metaphordemo.factory
3 |
4 | import androidx.appcompat.app.AppCompatActivity
5 | import com.androidpoet.metaphor.MetaphorActivity
6 | import com.androidpoet.metaphor.MetaphorAnimation
7 |
8 | class MetaphorActivityFactory() : MetaphorActivity.Factory() {
9 | override fun create(fragment: AppCompatActivity): MetaphorActivity {
10 | return MetaphorActivity.Builder(fragment)
11 | .setEnterAnimation(MetaphorAnimation.ElevationScale)
12 | .setExitAnimation(MetaphorAnimation.SharedAxisXBackward)
13 | .build()
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/usecases.md:
--------------------------------------------------------------------------------
1 |
2 | # Who's using Metaphor?
3 |
4 | If your project uses Metaphor, let me know by creating a new issue or PR! 🤗
5 |
6 |
7 |
8 | # License
9 | ```xml
10 | Copyright 2022 AndroidPoet (Ranbir Singh)
11 |
12 | Licensed under the Apache License, Version 2.0 (the "License");
13 | you may not use this file except in compliance with the License.
14 | You may obtain a copy of the License at
15 |
16 | http://www.apache.org/licenses/LICENSE-2.0
17 |
18 | Unless required by applicable law or agreed to in writing, software
19 | distributed under the License is distributed on an "AS IS" BASIS,
20 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21 | See the License for the specific language governing permissions and
22 | limitations under the License.
23 | ```
24 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 |
2 | /*
3 | *
4 | * * Copyright 2022 AndroidPoet (Ranbir Singh)
5 | * *
6 | * * Licensed under the Apache License, Version 2.0 (the "License");
7 | * * you may not use this file except in compliance with the License.
8 | * * You may obtain a copy of the License at
9 | * *
10 | * * http://www.apache.org/licenses/LICENSE-2.0
11 | * *
12 | * * Unless required by applicable law or agreed to in writing, software
13 | * * distributed under the License is distributed on an "AS IS" BASIS,
14 | * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * * See the License for the specific language governing permissions and
16 | * * limitations under the License.
17 | *
18 | *
19 | */
20 |
21 | rootProject.name = "MetaphorDemo"
22 | include ':app'
23 | include ':metaphor'
24 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/metaphor/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/metaphor/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
25 |
26 |
--------------------------------------------------------------------------------
/app/src/main/res/raw/grid.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "blur": "LEHV6nWB2yk8pyoJadR*.7kCMdnj",
4 | "pos": 1,
5 | "img": "https://unsplash.com/photos/MvxMvPO3S1M/download?ixid=MnwxMjA3fDB8MXxzZWFyY2h8MTA0fHx3b21hbnxlbnwwfHx8fDE2NDY2NTI2ODE&force=true&w=640"
6 | },
7 | {
8 | "blur": "LGF5]+Yk^6#M@-5c,1J5@[or[Q6.",
9 | "pos": 2,
10 | "img": "https://unsplash.com/photos/kg9YQ1aDQr8/download?ixid=MnwxMjA3fDB8MXx0b3BpY3x8NnNNVmpUTFNrZVF8fHx8fDJ8fDE2NDY2NTI3MjA&force=true&w=640"
11 | },
12 | {
13 | "blur": "L6Pj0^i_.AyE_3t7t7R**0o#DgR4",
14 | "pos": 3,
15 | "img": "https://unsplash.com/photos/2fa1zztCgBQ/download?ixid=MnwxMjA3fDB8MXx0b3BpY3x8NnNNVmpUTFNrZVF8fHx8fDJ8fDE2NDY2NTI3MjA&force=true&w=640"
16 | },
17 | {
18 | "blur": "LKO2?U%2Tw=w]~RBVZRi};RPxuwH",
19 | "pos": 4,
20 | "img": "https://unsplash.com/photos/aNo_entwaVY/download?ixid=MnwxMjA3fDB8MXx0b3BpY3x8X2hiLWRsNFEtNFV8fHx8fDJ8fDE2NDY2NTI3Njg&force=true&w=640"
21 | }
22 | ]
--------------------------------------------------------------------------------
/app/src/main/res/raw/list.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "blur": "LEHV6nWB2yk8pyoJadR*.7kCMdnj",
4 | "pos": 1,
5 | "img": "https://unsplash.com/photos/cuPH-o6TmvI/download?ixid=MnwxMjA3fDB8MXx0b3BpY3x8cm5TS0RId3dZVWt8fHx8fDJ8fDE2NDY2NTI3OTQ&force=true&w=640"
6 | },
7 | {
8 | "blur": "LGF5]+Yk^6#M@-5c,1J5@[or[Q6.",
9 | "pos": 2,
10 | "img": "https://unsplash.com/photos/SQeoekKJ--4/download?ixid=MnwxMjA3fDB8MXx0b3BpY3x8Ym84alFLVGFFMFl8fHx8fDJ8fDE2NDY2NTI4MTQ&force=true&w=640"
11 | },
12 | {
13 | "blur": "L6Pj0^i_.AyE_3t7t7R**0o#DgR4",
14 | "pos": 3,
15 | "img": "https://unsplash.com/photos/W1PaOgpZ-J0/download?ixid=MnwxMjA3fDB8MXx0b3BpY3x8d256cEx4czBuUVl8fHx8fDJ8fDE2NDY2NTI4NDU&force=true&w=640"
16 | },
17 | {
18 | "blur": "LKO2?U%2Tw=w]~RBVZRi};RPxuwH",
19 | "pos": 4,
20 | "img": "https://unsplash.com/photos/5SXBhUVR9_Y/download?ixid=MnwxMjA3fDB8MXx0b3BpY3x8eGpQUjRobGtCR0F8fHx8fDJ8fDE2NDY2NTI4NzU&force=true&w=640"
21 | }
22 | ]
--------------------------------------------------------------------------------
/app/src/main/res/values/integers.xml:
--------------------------------------------------------------------------------
1 |
19 |
20 |
21 | 300
22 | 400
23 |
--------------------------------------------------------------------------------
/metaphor/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
26 |
27 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 |
2 |
3 | #
4 | # /*
5 | # * Copyright 2022 AndroidPoet (Ranbir Singh)
6 | # *
7 | # * Licensed under the Apache License, Version 2.0 (the "License");
8 | # * you may not use this file except in compliance with the License.
9 | # * You may obtain a copy of the License at
10 | # *
11 | # * http://www.apache.org/licenses/LICENSE-2.0
12 | # *
13 | # * Unless required by applicable law or agreed to in writing, software
14 | # * distributed under the License is distributed on an "AS IS" BASIS,
15 | # * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | # * See the License for the specific language governing permissions and
17 | # * limitations under the License.
18 | # */
19 | #
20 | #
21 |
22 | #Wed Mar 02 13:27:46 IST 2022
23 | distributionBase=GRADLE_USER_HOME
24 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
25 | distributionPath=wrapper/dists
26 | zipStorePath=wrapper/dists
27 | zipStoreBase=GRADLE_USER_HOME
28 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/layout_animation_fall_down.xml:
--------------------------------------------------------------------------------
1 |
2 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/empty.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
24 |
25 |
28 |
29 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/custom_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
20 |
21 |
25 |
26 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/shape_thumb.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
24 |
25 |
27 |
29 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/metaphor/src/main/res/drawable/circle_gray.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
26 |
27 |
30 |
31 |
33 |
34 |
37 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/spotless.gradle:
--------------------------------------------------------------------------------
1 |
2 |
3 | /*
4 | *
5 | * * Copyright 2022 AndroidPoet (Ranbir Singh)
6 | * *
7 | * * Licensed under the Apache License, Version 2.0 (the "License");
8 | * * you may not use this file except in compliance with the License.
9 | * * You may obtain a copy of the License at
10 | * *
11 | * * http://www.apache.org/licenses/LICENSE-2.0
12 | * *
13 | * * Unless required by applicable law or agreed to in writing, software
14 | * * distributed under the License is distributed on an "AS IS" BASIS,
15 | * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * * See the License for the specific language governing permissions and
17 | * * limitations under the License.
18 | *
19 | *
20 | */
21 |
22 | apply plugin: "com.diffplug.spotless"
23 | apply from: "$rootDir/dependencies.gradle"
24 | spotless {
25 | kotlin {
26 | target "**/*.kt"
27 | ktlint("$versions.ktlintGradle").userData(['indent_size': '2', 'continuation_indent_size': '2'])
28 | licenseHeaderFile "$rootDir/spotless.license.kt"
29 | trimTrailingWhitespace()
30 | endWithNewline()
31 | }
32 | }
--------------------------------------------------------------------------------
/metaphor/src/main/res/values/metaphormotion.xml:
--------------------------------------------------------------------------------
1 |
2 |
20 |
21 |
22 |
23 |
24 |
25 | 300
26 | 225
27 | 175
28 |
29 |
--------------------------------------------------------------------------------
/metaphor/src/main/res/drawable/circle_white.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
26 |
27 |
30 |
31 |
33 |
34 |
37 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_home_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
23 |
24 |
29 |
32 |
33 |
--------------------------------------------------------------------------------
/metaphor/src/main/res/drawable/ic_baseline_add_24.xml:
--------------------------------------------------------------------------------
1 |
19 |
20 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/metaphor/src/main/res/drawable/ic_home_gray_24dp.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
25 |
26 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_pause.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
23 |
24 |
29 |
32 |
33 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_volume_medium.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
23 |
24 |
29 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_fast_forward.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
23 |
24 |
29 |
32 |
33 |
--------------------------------------------------------------------------------
/metaphor/src/main/res/drawable/ic_home_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
25 |
26 |
31 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_fast_rewind.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
23 |
24 |
29 |
32 |
33 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_arrow_back_24.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
23 |
24 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_dashboard_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
23 |
24 |
29 |
32 |
33 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_outline_play_arrow_24.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
23 |
24 |
30 |
33 |
34 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
19 |
20 |
21 | MetaphorDemo
22 |
23 | Home
24 | Dashboard
25 | Notifications
26 | Artist
27 |
28 |
29 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
23 |
24 |
25 |
26 | 160dp
27 | 28dp
28 | 230dp
29 |
30 |
31 | 32dp
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_arrow_back.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
23 |
24 |
30 |
33 |
34 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_reorder_24.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
23 |
24 |
30 |
33 |
34 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_save_24.xml:
--------------------------------------------------------------------------------
1 |
19 |
20 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/java/com/androidpoet/metaphordemo/activties/MainActivity.kt:
--------------------------------------------------------------------------------
1 |
2 | package com.androidpoet.metaphordemo.activties
3 |
4 | import android.content.Intent
5 | import android.os.Build
6 | import android.os.Bundle
7 | import android.os.Handler
8 | import android.view.View
9 | import androidx.appcompat.app.AppCompatActivity
10 | import com.androidpoet.metaphordemo.R
11 | import com.androidpoet.metaphordemo.databinding.ActivityMainBinding
12 | import com.bumptech.glide.Glide
13 |
14 | class MainActivity : AppCompatActivity() {
15 |
16 | private lateinit var binding: ActivityMainBinding
17 |
18 | override fun onCreate(savedInstanceState: Bundle?) {
19 | super.onCreate(savedInstanceState)
20 | binding = ActivityMainBinding.inflate(layoutInflater)
21 | setContentView(binding.root)
22 |
23 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
24 | val decor: View = window.decorView
25 | decor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR)
26 | }
27 |
28 | Glide.with(this).load(R.drawable.metalogo).into(binding.logo)
29 | Handler().postDelayed(
30 | {
31 | val intent = Intent(this, FragmentHostActivty::class.java)
32 | startActivity(intent)
33 | finish()
34 | },
35 | 2000
36 | )
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_volume_high.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
23 |
24 |
29 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_volume_bottom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
23 |
24 |
29 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_notifications_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
23 |
24 |
29 |
32 |
33 |
--------------------------------------------------------------------------------
/metaphor/src/main/java/com/androidpoet/metaphor/MetaphorAnimation.kt:
--------------------------------------------------------------------------------
1 |
2 | package com.androidpoet.metaphor
3 |
4 | /*
5 | *
6 | * * Copyright 2022 AndroidPoet (Ranbir Singh)
7 | * *
8 | * * Licensed under the Apache License, Version 2.0 (the "License");
9 | * * you may not use this file except in compliance with the License.
10 | * * You may obtain a copy of the License at
11 | * *
12 | * * http://www.apache.org/licenses/LICENSE-2.0
13 | * *
14 | * * Unless required by applicable law or agreed to in writing, software
15 | * * distributed under the License is distributed on an "AS IS" BASIS,
16 | * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * * See the License for the specific language governing permissions and
18 | * * limitations under the License.
19 | *
20 | *
21 | */
22 |
23 | /** MetaphorAnimation is an animation attribute of [MetaphorAnimation]'s the showing and dismissing. */
24 |
25 | public enum class MetaphorAnimation(public val value: Int) {
26 | None(1),
27 | ContainerTransform(2),
28 | FadeThrough(3),
29 | Fade(4),
30 | SharedAxisXForward(5),
31 | SharedAxisYForward(6),
32 | SharedAxisZForward(7),
33 | SharedAxisXBackward(8),
34 | SharedAxisYBackward(9),
35 | SharedAxisZBackward(10),
36 | ElevationScaleGrow(11),
37 | ElevationScale(12),
38 | }
39 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
14 |
17 |
20 |
23 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/metaphor/src/main/java/com/androidpoet/metaphor/WindowExtenstions.kt:
--------------------------------------------------------------------------------
1 |
2 | package com.androidpoet.metaphor
3 |
4 | import android.os.Build
5 | import android.widget.PopupWindow
6 | import androidx.annotation.RequiresApi
7 |
8 | /** applies Animation form attributes to a View instance. */
9 | @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
10 | @JvmSynthetic
11 | internal fun PopupWindow.applyAnimation(
12 | window: MetaphorWindow
13 | ) {
14 |
15 | val enterAnimation =
16 | getWindowMetaphorAnimation(window.enterAnimation)?.let {
17 | addAnimationProperties(
18 | it,
19 | window,
20 | window.enterDuration
21 | )
22 | }
23 | val exitAnimation =
24 | getWindowMetaphorAnimation(window.exitAnimation)?.let {
25 | addAnimationProperties(
26 | it,
27 | window,
28 | window.exitDuration
29 | )
30 | }
31 |
32 | this.enterTransition = enterAnimation
33 | this.exitTransition = exitAnimation
34 | }
35 |
36 | /** applies Properties on Animation form attributes. */
37 | @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
38 | @JvmSynthetic
39 | internal fun PopupWindow.addAnimationProperties(
40 | transition: android.transition.Transition,
41 | window: MetaphorWindow,
42 | animationDuration: Long
43 | ): android.transition.Transition {
44 |
45 | transition.apply {
46 | duration = animationDuration
47 | }
48 | return transition
49 | }
50 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_search_24.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
23 |
24 |
30 |
33 |
34 |
--------------------------------------------------------------------------------
/metaphor/src/main/java/com/androidpoet/metaphor/MetaphorLazyExtension.kt:
--------------------------------------------------------------------------------
1 |
2 | package com.androidpoet.metaphor
3 |
4 | import androidx.annotation.MainThread
5 | import androidx.appcompat.app.AppCompatActivity
6 | import androidx.fragment.app.Fragment
7 | import com.androidpoet.metaphor.internals.ActivityMetaphorLazy
8 | import com.androidpoet.metaphor.internals.FragmentMetaphorLazy
9 |
10 | /**
11 | * Returns a [Lazy] delegate to access the [MetaphorFragment]'s Balloon property.
12 | * The balloon property will be initialized lazily.
13 | *
14 | * @see [Lazy Initialization](https://github.com/skydoves/Balloon#lazy-initialization)
15 | */
16 | @MainThread
17 | @JvmSynthetic
18 | @MetaphorFragmentInlineDsl
19 | public inline fun Fragment.metaphorFragment(): Lazy {
20 | return FragmentMetaphorLazy(fragment = this, factory = T::class)
21 | }
22 |
23 | /**
24 | * Returns a [Lazy] delegate to access the [MetaphorActivity]'s Balloon property.
25 | * The balloon property will be initialized lazily.
26 | *
27 | * @see [Lazy Initialization](https://github.com/skydoves/Balloon#lazy-initialization)
28 | */
29 | @MainThread
30 | @JvmSynthetic
31 | @MetaphorActivityInlineDsl
32 | public inline fun AppCompatActivity.metaphorActivity(): Lazy {
33 | return ActivityMetaphorLazy(activity = this, factory = T::class)
34 | }
35 |
--------------------------------------------------------------------------------
/metaphor/src/main/java/com/androidpoet/metaphor/internals/FragmentMetaphorLazy.kt:
--------------------------------------------------------------------------------
1 |
2 | package com.androidpoet.metaphor.internals
3 |
4 | import androidx.fragment.app.Fragment
5 | import com.androidpoet.metaphor.MetaphorFragment
6 | import java.io.Serializable
7 | import kotlin.reflect.KClass
8 |
9 | /**
10 | * An implementation of [Lazy] for creating an instance of the [MetaphorFragment] lazily in Fragments.
11 | *
12 | * @param Fragment A context for creating resources of the [MetaphorFragment] lazily.
13 | * @param factory A [MetaphorFragment.Factory] kotlin class for creating a new instance of the MetaphorFragment.
14 | */
15 | @PublishedApi
16 | internal class FragmentMetaphorLazy(
17 | private val fragment: Fragment,
18 | private val factory: KClass
19 | ) : Lazy, Serializable {
20 |
21 | private var cached: MetaphorFragment? = null
22 |
23 | override val value: MetaphorFragment
24 | get() {
25 | var instance = cached
26 | if (instance === null) {
27 | val factory = factory::java.get().newInstance()
28 | instance = factory.create(fragment)
29 | cached = instance
30 | }
31 |
32 | return instance
33 | }
34 |
35 | override fun isInitialized(): Boolean = cached !== null
36 |
37 | override fun toString(): String =
38 | if (isInitialized()) value.toString() else "Lazy value not initialized yet."
39 | }
40 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/bottom_nav_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
24 |
25 |
--------------------------------------------------------------------------------
/metaphor/src/main/java/com/androidpoet/metaphor/internals/ActivityMetaphorLazy.kt:
--------------------------------------------------------------------------------
1 |
2 | package com.androidpoet.metaphor.internals
3 |
4 | import androidx.appcompat.app.AppCompatActivity
5 | import com.androidpoet.metaphor.MetaphorActivity
6 | import java.io.Serializable
7 | import kotlin.reflect.KClass
8 |
9 | /**
10 | * An implementation of [Lazy] for creating an instance of the [MetaphorActivity] lazily in Activities.
11 | * Tied to the given [lifecycleOwner], [factory].
12 | *
13 | * @param AppCompatActivity A context for creating resources of the [MetaphorActivity] lazily.
14 | * @param factory A [MetaphorActivity.Factory] kotlin class for creating a new instance of the MetaphorActivity.
15 | */
16 | @PublishedApi
17 | internal class ActivityMetaphorLazy(
18 | private val activity: AppCompatActivity,
19 | private val factory: KClass
20 | ) : Lazy, Serializable {
21 |
22 | private var cached: MetaphorActivity? = null
23 |
24 | override val value: MetaphorActivity
25 | get() {
26 | var instance = cached
27 | if (instance === null) {
28 | val factory = factory::java.get().newInstance()
29 | instance = factory.create(activity)
30 | cached = instance
31 | }
32 |
33 | return instance
34 | }
35 |
36 | override fun isInitialized(): Boolean = cached !== null
37 |
38 | override fun toString(): String =
39 | if (isInitialized()) value.toString() else "Lazy value not initialized yet."
40 | }
41 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/item_animation_fall_down.xml:
--------------------------------------------------------------------------------
1 |
2 |
20 |
21 |
23 |
24 |
29 |
30 |
35 |
36 |
45 |
46 |
--------------------------------------------------------------------------------
/app/src/main/java/com/androidpoet/metaphordemo/ui/home/AddNoteFragment.kt:
--------------------------------------------------------------------------------
1 |
2 | package com.androidpoet.metaphordemo.ui.home
3 |
4 | import android.os.Build
5 | import android.os.Bundle
6 | import android.view.LayoutInflater
7 | import android.view.View
8 | import android.view.ViewGroup
9 | import androidx.annotation.RequiresApi
10 | import androidx.fragment.app.Fragment
11 | import com.androidpoet.metaphordemo.R
12 | import com.androidpoet.metaphordemo.databinding.FragmentAddNoteBinding
13 | import com.google.gson.Gson
14 | import com.google.gson.reflect.TypeToken
15 |
16 | class AddNoteFragment : Fragment() {
17 |
18 | private lateinit var viewBinding: FragmentAddNoteBinding
19 |
20 | override fun onCreate(savedInstanceState: Bundle?) {
21 | super.onCreate(savedInstanceState)
22 | }
23 |
24 | private fun sampleResponse(): List {
25 | val response = resources.openRawResource(R.raw.grid).bufferedReader()
26 | .use { it.readText() }
27 | return Gson().fromJson(response, object : TypeToken>() {}.type)
28 | }
29 |
30 | override fun onCreateView(
31 | inflater: LayoutInflater,
32 | container: ViewGroup?,
33 | savedInstanceState: Bundle?
34 | ): View {
35 | viewBinding = FragmentAddNoteBinding.inflate(inflater, container, false).apply {
36 | lifecycleOwner = viewLifecycleOwner
37 | }
38 | return viewBinding.root
39 | }
40 |
41 | @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
42 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
43 | super.onViewCreated(view, savedInstanceState)
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
24 |
25 |
26 | #FFBB86FC
27 | #FF6200EE
28 | #FF3700B3
29 | #FF03DAC5
30 | #FF018786
31 | #FF000000
32 | #FFFFFFFF
33 | #AFAFAF
34 | #004e47
35 | #016e64
36 | #f612517b
37 | #009688
38 |
39 |
40 | #03a9f4
41 | #2196F3
42 | #F8E21E
43 |
44 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_home.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
13 |
14 |
22 |
23 |
33 |
34 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/dependencies.gradle:
--------------------------------------------------------------------------------
1 |
2 | /*
3 | *
4 | * * Copyright 2022 AndroidPoet (Ranbir Singh)
5 | * *
6 | * * Licensed under the Apache License, Version 2.0 (the "License");
7 | * * you may not use this file except in compliance with the License.
8 | * * You may obtain a copy of the License at
9 | * *
10 | * * http://www.apache.org/licenses/LICENSE-2.0
11 | * *
12 | * * Unless required by applicable law or agreed to in writing, software
13 | * * distributed under the License is distributed on an "AS IS" BASIS,
14 | * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * * See the License for the specific language governing permissions and
16 | * * limitations under the License.
17 | *
18 | *
19 | */
20 |
21 | ext.versions = [
22 | minSdk : 17,
23 | compileSdk : 31,
24 | versionCode : 42,
25 | versionName : '1.4.1',
26 | ktx : '1.7.0',
27 |
28 | gradleBuildTool : '7.1.0',
29 | spotlessGradle : '6.2.1',
30 | kotlin : '1.5.32',
31 | ktlintGradle : '0.43.2',
32 | dokkaGradle : '1.5.31',
33 | binaryValidator : '0.8.0',
34 | mavenPublish : '0.18.0',
35 |
36 | androidxAppcompat: '1.4.1',
37 | androidxFragment : '1.3.3',
38 | lifecycle : '2.4.1',
39 | annotation : '1.3.0',
40 | lottieVersion : '5.0.2',
41 | // for demo
42 | constraintVersion: '2.0.4',
43 | googleMaterial : '1.5.0',
44 |
45 | glide : '4.13.0',
46 | gson : '2.8.6',
47 | recyclerview : '1.2.1'
48 |
49 |
50 | ]
51 |
--------------------------------------------------------------------------------
/app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
23 |
24 |
25 |
26 |
41 |
--------------------------------------------------------------------------------
/app/src/main/res/values-night/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
23 |
24 |
25 |
26 |
41 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_home.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
22 |
23 |
29 |
30 |
43 |
--------------------------------------------------------------------------------
/metaphor/src/main/res/values/ids.xml:
--------------------------------------------------------------------------------
1 |
2 |
20 |
21 |
23 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/app/src/main/java/com/androidpoet/metaphordemo/MetaphorUtils.kt:
--------------------------------------------------------------------------------
1 |
2 | package com.androidpoet.metaphordemo
3 |
4 | import android.view.View
5 | import android.widget.PopupWindow
6 | import androidx.appcompat.app.AppCompatActivity
7 | import androidx.fragment.app.Fragment
8 | import com.androidpoet.metaphor.MetaphorActivity
9 | import com.androidpoet.metaphor.MetaphorAnimation
10 | import com.androidpoet.metaphor.MetaphorFragment
11 | import com.androidpoet.metaphor.MetaphorView
12 | import com.androidpoet.metaphor.MetaphorWindow
13 | import com.google.android.material.transition.MaterialArcMotion
14 |
15 | object MetaphorUtils {
16 |
17 | fun getFragmentMetaphor(
18 | fragment: Fragment,
19 | enterAnimation: MetaphorAnimation,
20 | exitAnimation: MetaphorAnimation
21 | ): MetaphorFragment {
22 |
23 | return MetaphorFragment.Builder(fragment)
24 | .setEnterDuration(500)
25 | .setEnterAnimation(enterAnimation)
26 | .setExitAnimation(exitAnimation)
27 | .build()
28 | }
29 |
30 | fun getActivityMetaphor(
31 | appCompatActivity: AppCompatActivity,
32 | enterAnimation: MetaphorAnimation,
33 | exitAnimation: MetaphorAnimation
34 | ): MetaphorActivity {
35 |
36 | return MetaphorActivity.Builder(appCompatActivity)
37 | .setEnterAnimation(enterAnimation)
38 | .setExitAnimation(exitAnimation)
39 | .build()
40 | }
41 |
42 | fun View.getViewMetaphor(
43 | metaphorAnimation: MetaphorAnimation,
44 | end: View
45 | ): MetaphorView {
46 |
47 | return MetaphorView.Builder(this)
48 | .setDuration(1000)
49 | .setEndView(end)
50 | .setMetaphorAnimation(metaphorAnimation)
51 | .setMotion(MaterialArcMotion())
52 | .build()
53 | }
54 |
55 | fun PopupWindow.getPopupWindowMetaphor(
56 | metaphorAnimation: MetaphorAnimation,
57 | ): MetaphorWindow {
58 |
59 | return MetaphorWindow.Builder(this)
60 | .setEnterDuration(500)
61 | .setExitDuration(500)
62 | .setEnterAnimation(metaphorAnimation)
63 | .setExitAnimation(metaphorAnimation)
64 | .build()
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
21 |
22 |
23 |
24 |
29 |
30 |
36 |
37 |
44 |
45 |
46 |
51 |
52 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/app/src/main/java/com/androidpoet/metaphordemo/ui/home/ArtistGridListAdapter.kt:
--------------------------------------------------------------------------------
1 |
2 | package com.androidpoet.metaphordemo.ui.home
3 |
4 | import android.content.Context
5 | import android.os.Build
6 | import android.view.LayoutInflater
7 | import android.view.View
8 | import android.view.ViewGroup
9 | import androidx.annotation.RequiresApi
10 | import androidx.recyclerview.widget.DiffUtil
11 | import androidx.recyclerview.widget.ListAdapter
12 | import com.androidpoet.metaphordemo.databinding.ItemArtistBinding
13 | import com.bumptech.glide.Glide
14 | import com.bumptech.glide.RequestManager
15 |
16 | class ArtistGridListAdapter(
17 | private val context: Context,
18 | private val requestManager: RequestManager
19 | ) : ListAdapter(object : DiffUtil
20 | .ItemCallback() {
21 | override fun areItemsTheSame(oldItem: SampleResponse, newItem: SampleResponse): Boolean {
22 | return oldItem.blur == newItem.blur
23 | }
24 |
25 | override fun areContentsTheSame(oldItem: SampleResponse, newItem: SampleResponse): Boolean {
26 | return oldItem == newItem
27 | }
28 | }) {
29 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ArtistViewHolder {
30 | return ArtistViewHolder(
31 | ItemArtistBinding.inflate(
32 | LayoutInflater.from(parent.context),
33 | parent, false
34 | )
35 | ).apply {
36 | binding.root.setOnClickListener {
37 | if (bindingAdapterPosition >= 0) {
38 | callback?.onClick(
39 | binding.imgv,
40 | getItem(bindingAdapterPosition),
41 | getItem(bindingAdapterPosition).img
42 | )
43 | }
44 | }
45 | }
46 | }
47 |
48 | @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
49 | override fun onBindViewHolder(holder: ArtistViewHolder, position: Int) {
50 | Glide.with(holder.itemView.context).load(getItem(position).img).into(holder.binding.imgv)
51 | holder.binding.imgv.transitionName = getItem(position).img
52 | holder.binding.executePendingBindings()
53 | }
54 |
55 | fun setData(list: List) {
56 | submitList(list)
57 | }
58 |
59 | var callback: Callback? = null
60 |
61 | interface Callback {
62 | fun onClick(view: View, item: SampleResponse, imageUrl: String)
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/app/src/main/java/com/androidpoet/metaphordemo/ui/home/ArtistLinearListAdapter.kt:
--------------------------------------------------------------------------------
1 |
2 | package com.androidpoet.metaphordemo.ui.home
3 |
4 | import android.content.Context
5 | import android.os.Build
6 | import android.view.LayoutInflater
7 | import android.view.View
8 | import android.view.ViewGroup
9 | import androidx.annotation.RequiresApi
10 | import androidx.recyclerview.widget.DiffUtil
11 | import androidx.recyclerview.widget.ListAdapter
12 | import com.androidpoet.metaphordemo.databinding.ArtistLinearListBinding
13 | import com.bumptech.glide.Glide
14 | import com.bumptech.glide.RequestManager
15 |
16 | /**
17 | * Created by Phong Huynh on 11/15/2020
18 | */
19 | class ArtistLinearListAdapter(
20 | private val context: Context,
21 | private val requestManager: RequestManager
22 | ) : ListAdapter(object : DiffUtil
23 | .ItemCallback() {
24 | override fun areItemsTheSame(oldItem: SampleResponse, newItem: SampleResponse): Boolean {
25 | return oldItem.blur == newItem.blur
26 | }
27 |
28 | override fun areContentsTheSame(oldItem: SampleResponse, newItem: SampleResponse): Boolean {
29 | return oldItem == newItem
30 | }
31 | }) {
32 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ArtistLinearViewHolder {
33 | return ArtistLinearViewHolder(
34 | ArtistLinearListBinding.inflate(
35 | LayoutInflater.from(parent.context),
36 | parent, false
37 | )
38 | ).apply {
39 | binding.root.setOnClickListener {
40 | if (bindingAdapterPosition >= 0) {
41 | callback?.onClick(
42 | binding.imgv,
43 | getItem(bindingAdapterPosition),
44 | getItem(bindingAdapterPosition).img
45 | )
46 | }
47 | }
48 | }
49 | }
50 |
51 | @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
52 | override fun onBindViewHolder(holder: ArtistLinearViewHolder, position: Int) {
53 | Glide.with(holder.itemView.context).load(getItem(position).img).into(holder.binding.imgv)
54 | holder.binding.imgv.transitionName = getItem(position).img
55 | holder.binding.executePendingBindings()
56 | }
57 |
58 | fun setData(list: List) {
59 | submitList(list)
60 | }
61 |
62 | var callback: Callback? = null
63 |
64 | interface Callback {
65 | fun onClick(view: View, item: SampleResponse, imageUrl: String)
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/metaphor/src/main/java/com/androidpoet/metaphor/FragmentExtensions.kt:
--------------------------------------------------------------------------------
1 |
2 | package com.androidpoet.metaphor
3 |
4 | import android.app.Activity
5 | import android.content.Context
6 | import android.content.ContextWrapper
7 | import android.os.Build
8 | import androidx.annotation.RequiresApi
9 | import androidx.core.view.doOnPreDraw
10 | import androidx.fragment.app.Fragment
11 | import androidx.transition.Transition
12 | import com.google.android.material.transition.MaterialContainerTransform
13 |
14 | public fun Context.activity(): Activity? = when (this) {
15 | is Activity -> this
16 | else -> (this as? ContextWrapper)?.baseContext?.activity()
17 | }
18 |
19 | /** applies Animation form attributes to a View instance. */
20 | @JvmSynthetic
21 | internal fun Fragment.applyAnimation(
22 | metaphor: MetaphorFragment
23 | ) {
24 | enterTransition = getMetaphorAnimation(metaphor.enterAnimation)?.let { addAnimationProperties(it, metaphor, metaphor.enterDuration) }
25 | exitTransition = getMetaphorAnimation(metaphor.exitAnimation)?.let { addAnimationProperties(it, metaphor, metaphor.exitDuration) }
26 | reenterTransition = getMetaphorAnimation(metaphor.reenterAnimation)?.let { addAnimationProperties(it, metaphor, metaphor.reenterDuration) }
27 | returnTransition = getMetaphorAnimation(metaphor.returnAnimation)?.let { addAnimationProperties(it, metaphor, metaphor.returnDuration) }
28 | }
29 | /** applies Properties on Animation form attributes. */
30 | @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
31 | @JvmSynthetic
32 | internal fun Fragment.addAnimationProperties(
33 | transition: Transition,
34 | metaphor: MetaphorFragment,
35 | animationDuration: Long
36 | ): Transition {
37 |
38 | if (transition is MaterialContainerTransform) {
39 | metaphor.view?.transitionName = metaphor.transitionName
40 | sharedElementEnterTransition = transition.apply {
41 | startView?.let { addTarget(it) }
42 | setAllContainerColors(metaphor.containerColors)
43 | scrimColor = metaphor.scrimColor
44 | }
45 | }
46 |
47 | transition.apply {
48 | duration = animationDuration
49 | setPathMotion(metaphor.motion)
50 | allowEnterTransitionOverlap = metaphor.enterTransitionOverlap
51 | allowReturnTransitionOverlap = metaphor.returnTransitionOverlap
52 | }
53 | return transition
54 | }
55 |
56 | // hold extension to use in container transform.
57 | @JvmSynthetic
58 | public fun Fragment.hold() {
59 | postponeEnterTransition()
60 | view?.doOnPreDraw { startPostponedEnterTransition() }
61 | }
62 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_host_activty.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
22 |
23 |
28 |
29 |
32 |
33 |
44 |
45 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
23 |
24 |
30 |
31 |
32 |
38 |
41 |
44 |
45 |
46 |
47 |
53 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 |
2 | /*
3 | *
4 | * * Copyright 2022 AndroidPoet (Ranbir Singh)
5 | * *
6 | * * Licensed under the Apache License, Version 2.0 (the "License");
7 | * * you may not use this file except in compliance with the License.
8 | * * You may obtain a copy of the License at
9 | * *
10 | * * http://www.apache.org/licenses/LICENSE-2.0
11 | * *
12 | * * Unless required by applicable law or agreed to in writing, software
13 | * * distributed under the License is distributed on an "AS IS" BASIS,
14 | * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * * See the License for the specific language governing permissions and
16 | * * limitations under the License.
17 | *
18 | *
19 | */
20 |
21 | apply plugin: 'com.android.application'
22 | apply plugin: 'org.jetbrains.kotlin.android'
23 | apply plugin: 'kotlin-kapt'
24 | apply plugin: 'androidx.navigation.safeargs.kotlin'
25 | apply plugin: 'kotlin-parcelize'
26 | apply from: "$rootDir/dependencies.gradle"
27 |
28 | android {
29 | compileSdkVersion versions.compileSdk
30 | defaultConfig {
31 | applicationId "com.androidpoet.metaphordemo"
32 | minSdkVersion versions.minSdk
33 | targetSdkVersion versions.compileSdk
34 | vectorDrawables.useSupportLibrary = true
35 | versionCode versions.versionCode
36 | versionName versions.versionName
37 | }
38 | compileOptions {
39 | sourceCompatibility JavaVersion.VERSION_11
40 | targetCompatibility JavaVersion.VERSION_11
41 | }
42 | kotlinOptions {
43 | jvmTarget = "11"
44 | }
45 | buildFeatures {
46 | viewBinding true
47 | dataBinding true
48 | }
49 | lintOptions {
50 | abortOnError false
51 | }
52 | }
53 |
54 | dependencies {
55 | implementation "androidx.core:core-ktx:$versions.ktx"
56 | implementation "androidx.appcompat:appcompat:$versions.androidxAppcompat"
57 | implementation "com.google.android.material:material:$versions.googleMaterial"
58 | implementation project(":metaphor")
59 | implementation "com.github.bumptech.glide:glide:$versions.glide"
60 | implementation "com.airbnb.android:lottie:$versions.lottieVersion"
61 | implementation "androidx.lifecycle:lifecycle-livedata-ktx:$versions.lifecycle"
62 | implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$versions.lifecycle"
63 | implementation "androidx.navigation:navigation-fragment-ktx:$versions.lifecycle"
64 | implementation "androidx.navigation:navigation-ui-ktx:$versions.lifecycle"
65 | implementation "com.google.code.gson:gson:$versions.gson"
66 | implementation "androidx.recyclerview:recyclerview:$versions.recyclerview"
67 | implementation 'androidx.legacy:legacy-support-v4:1.0.0'
68 | implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
69 | }
70 |
71 | apply from: "$rootDir/spotless.gradle"
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
--------------------------------------------------------------------------------
/metaphor/build.gradle:
--------------------------------------------------------------------------------
1 |
2 |
3 | /*
4 | *
5 | * * Copyright 2022 AndroidPoet (Ranbir Singh)
6 | * *
7 | * * Licensed under the Apache License, Version 2.0 (the "License");
8 | * * you may not use this file except in compliance with the License.
9 | * * You may obtain a copy of the License at
10 | * *
11 | * * http://www.apache.org/licenses/LICENSE-2.0
12 | * *
13 | * * Unless required by applicable law or agreed to in writing, software
14 | * * distributed under the License is distributed on an "AS IS" BASIS,
15 | * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * * See the License for the specific language governing permissions and
17 | * * limitations under the License.
18 | *
19 | *
20 | */
21 |
22 | apply plugin: 'com.android.library'
23 | apply plugin: 'kotlin-android'
24 | apply plugin: 'org.jetbrains.dokka'
25 | apply plugin: 'binary-compatibility-validator'
26 | apply from: "$rootDir/dependencies.gradle"
27 |
28 | android {
29 | compileSdkVersion versions.compileSdk
30 | defaultConfig {
31 | minSdkVersion versions.minSdk
32 | targetSdkVersion versions.compileSdk
33 | versionCode versions.versionCode
34 | versionName versions.versionName
35 | }
36 |
37 | resourcePrefix 'metaphor'
38 |
39 | buildFeatures {
40 | buildConfig false
41 | viewBinding true
42 | }
43 |
44 | compileOptions {
45 | sourceCompatibility JavaVersion.VERSION_1_8
46 | targetCompatibility JavaVersion.VERSION_1_8
47 | }
48 |
49 | kotlinOptions {
50 | jvmTarget = "1.8"
51 | }
52 |
53 | lintOptions {
54 | abortOnError false
55 | }
56 | }
57 |
58 | tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
59 | kotlinOptions.freeCompilerArgs += ["-Xexplicit-api=strict"]
60 | }
61 |
62 | apiValidation {
63 |
64 | nonPublicMarkers += [
65 | "kotlin.PublishedApi",
66 | ]
67 | }
68 |
69 | dependencies {
70 | implementation "androidx.appcompat:appcompat:$versions.androidxAppcompat"
71 | implementation "androidx.fragment:fragment-ktx:$versions.androidxFragment"
72 | implementation "androidx.core:core-ktx:$versions.ktx"
73 | implementation "com.google.android.material:material:$versions.googleMaterial"
74 | implementation "androidx.lifecycle:lifecycle-common-java8:2.4.1"
75 | implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.4.1"
76 |
77 | }
78 |
79 | dokkaHtml.configure {
80 | dokkaSourceSets {
81 | named("main") {
82 | noAndroidSdkLink.set(false)
83 | }
84 | }
85 | }
86 |
87 |
88 | allprojects {
89 | plugins.withId("com.vanniktech.maven.publish") {
90 | mavenPublish {
91 | sonatypeHost = "S01"
92 | }
93 | }
94 | }
95 |
96 | apply plugin: "com.vanniktech.maven.publish"
97 | apply from: "$rootDir/spotless.gradle"
98 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_artist.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
21 |
22 |
25 |
26 |
27 |
28 |
36 |
37 |
46 |
47 |
54 |
55 |
64 |
65 |
74 |
75 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/app/src/main/res/navigation/mobile_navigation.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
24 |
25 |
30 |
31 |
36 |
39 |
40 |
41 |
42 |
47 |
50 |
53 |
56 |
57 |
62 |
63 |
64 |
68 |
71 |
72 |
73 |
74 |
78 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 |
2 | #
3 | # /*
4 | # * Copyright 2022 AndroidPoet (Ranbir Singh)
5 | # *
6 | # * Licensed under the Apache License, Version 2.0 (the "License");
7 | # * you may not use this file except in compliance with the License.
8 | # * You may obtain a copy of the License at
9 | # *
10 | # * http://www.apache.org/licenses/LICENSE-2.0
11 | # *
12 | # * Unless required by applicable law or agreed to in writing, software
13 | # * distributed under the License is distributed on an "AS IS" BASIS,
14 | # * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # * See the License for the specific language governing permissions and
16 | # * limitations under the License.
17 | # */
18 | #
19 | #
20 |
21 | # Project-wide Gradle settings.
22 | # IDE (e.g. Android Studio) users:
23 | # Gradle settings configured through the IDE *will override*
24 | # any settings specified in this file.
25 | # For more details on how to configure your build environment visit
26 | # http://www.gradle.org/docs/current/userguide/build_environment.html
27 | # Specifies the JVM arguments used for the daemon process.
28 | # The setting is particularly useful for tweaking memory settings.
29 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
30 | # When configured, Gradle will run in incubating parallel mode.
31 | # This option should only be used with decoupled projects. More details, visit
32 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
33 | # org.gradle.parallel=true
34 | # AndroidX package structure to make it clearer which packages are bundled with the
35 | # Android operating system, and which are packaged with your app"s APK
36 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
37 | android.useAndroidX=true
38 | # Kotlin code style for this project: "official" or "obsolete":
39 | kotlin.code.style=official
40 | # Enables namespacing of each library's R class so that its R class includes only the
41 | # resources declared in the library itself and none from the library's dependencies,
42 | # thereby reducing the size of the R class for that library
43 | android.nonTransitiveRClass=true
44 |
45 | # Required to publish to Nexus
46 | systemProp.org.gradle.internal.publish.checksums.insecure=true
47 |
48 | # Increase timeout when pushing to Sonatype
49 | systemProp.org.gradle.internal.http.connectionTimeout=120000
50 | systemProp.org.gradle.internal.http.socketTimeout=120000
51 |
52 | # Maven
53 | GROUP=io.github.androidpoet
54 | POM_PACKAGING=aar
55 |
56 | VERSION_NAME=1.1.6
57 |
58 | POM_ARTIFACT_ID=metaphor
59 | POM_NAME=metaphor
60 | POM_DESCRIPTION=Metaphor is the library to easily add Material Motion animation.
61 |
62 | POM_URL=https://github.com/AndroidPoet/Metaphor/
63 | POM_SCM_URL=https://github.com/AndroidPoet/Metaphor/
64 | POM_SCM_CONNECTION=scm:git:git://github.com/AndroidPoet/Metaphor.git
65 | POM_SCM_DEV_CONNECTION=scm:git:git://github.com/AndroidPoet/Metaphor.git
66 |
67 | POM_LICENCE_NAME=The Apache Software License, Version 2.0
68 | POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt
69 | POM_LICENCE_DIST=repo
70 |
71 | POM_DEVELOPER_ID=ranbirk66
72 | POM_DEVELOPER_NAME=Ranbir Singh
73 | POM_DEVELOPER_URL=https://github.com/AndroidPoet/
74 |
75 |
--------------------------------------------------------------------------------
/metaphor/src/main/java/com/androidpoet/metaphor/MetaphorView.kt:
--------------------------------------------------------------------------------
1 |
2 | package com.androidpoet.metaphor
3 |
4 | import android.view.View
5 | import androidx.annotation.MainThread
6 | import androidx.transition.ArcMotion
7 | import androidx.transition.PathMotion
8 |
9 | @DslMarker
10 | internal annotation class MetaphorViewInlineDsl
11 |
12 | /**
13 | * Creates an instance of the [MetaphorView] by scope of the [MetaphorView.Builder] using kotlin dsl.
14 | *
15 | * @param view A context for creating resources of the [MetaphorView].
16 | * @param block A dsl scope lambda from the [MetaphorView.Builder].
17 | * */
18 | @MainThread
19 | @JvmSynthetic
20 | @MetaphorViewInlineDsl
21 | public inline fun metaphorView(
22 | view: View,
23 | crossinline block: MetaphorView.Builder.() -> Unit
24 | ): MetaphorView =
25 | MetaphorView.Builder(view).apply(block).build()
26 |
27 | /**
28 | * MetaphorFragment implements material motion animations.
29 | *
30 | * @see [MetaphorView](https://github.com/AndroidPoet/Metaphor)
31 | *
32 | * @param builder A [MetaphorView.Builder] for creating an instance of the [MetaphorView].
33 | */
34 | public class MetaphorView private constructor(
35 | builder: Builder
36 | ) {
37 |
38 | /** end view to transform into View */
39 | public val endView: View? = builder.endView
40 |
41 | /** duration of the animations. */
42 | public val duration: Long = builder.duration
43 |
44 | /** Animation of View. */
45 | public val animation: MetaphorAnimation = builder.animation
46 |
47 | /** Motion path of on View animation */
48 | public val motion: PathMotion = builder.motion
49 |
50 | /** start view to transform into View */
51 | private val starView: View = builder.startView
52 |
53 | /** Builder class for [MetaphorView]. */
54 | @MetaphorViewInlineDsl
55 | public class Builder(public val startView: View) {
56 |
57 | @set:JvmSynthetic
58 | public var duration: Long = 300
59 |
60 | @set:JvmSynthetic
61 | public var animation: MetaphorAnimation = MetaphorAnimation.FadeThrough
62 |
63 | @set:JvmSynthetic
64 | public var endView: View? = null
65 |
66 | @set:JvmSynthetic
67 | public var motion: PathMotion = ArcMotion()
68 |
69 | /** sets the duration of the View. */
70 | public fun setDuration(value: Long): Builder = apply { this.duration = value }
71 |
72 | /** sets the animation of the animation. */
73 | public fun setMetaphorAnimation(value: MetaphorAnimation): Builder =
74 | apply { this.animation = value }
75 |
76 | /** sets the endView of the animation. */
77 | public fun setEndView(value: View): Builder =
78 | apply { this.endView = value }
79 |
80 | /** sets the motion of the animation. */
81 | public fun setMotion(value: PathMotion): Builder =
82 | apply { this.motion = value }
83 |
84 | public fun build(): MetaphorView = MetaphorView(this)
85 | }
86 | /** starts animation. */
87 | @MainThread
88 | public fun animate() {
89 | starView.applyAnimation(this)
90 | }
91 |
92 | public abstract class Factory {
93 |
94 | /**
95 | * Creates a new instance of [MetaphorView].
96 | *
97 | * @return A new created instance of the [MetaphorView].
98 | */
99 | public abstract fun create(view: View): MetaphorView
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/metaphor/src/main/java/com/androidpoet/metaphor/ActivityExtenstions.kt:
--------------------------------------------------------------------------------
1 |
2 | package com.androidpoet.metaphor
3 |
4 | import android.app.Activity
5 | import android.graphics.Color
6 | import android.os.Build
7 | import androidx.annotation.RequiresApi
8 | import androidx.interpolator.view.animation.FastOutSlowInInterpolator
9 | import com.google.android.material.transition.platform.MaterialContainerTransform
10 | import com.google.android.material.transition.platform.MaterialContainerTransformSharedElementCallback
11 |
12 | /** applies Animation form attributes to a View instance. */
13 | @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
14 | @JvmSynthetic
15 | internal fun Activity.applyAnimation(
16 | metaphor: MetaphorActivity
17 | ) {
18 | val enterAnimation =
19 | getWindowMetaphorAnimation(metaphor.enterAnimation)?.let {
20 | addAnimationProperties(
21 | it,
22 | metaphor,
23 | metaphor.enterDuration
24 | )
25 | }
26 | val exitAnimation =
27 | getWindowMetaphorAnimation(metaphor.exitAnimation)?.let {
28 | addAnimationProperties(
29 | it,
30 | metaphor,
31 | metaphor.exitDuration
32 | )
33 | }
34 | val reenterAnimation =
35 | getWindowMetaphorAnimation(metaphor.reenterAnimation)?.let {
36 | addAnimationProperties(
37 | it,
38 | metaphor,
39 | metaphor.reenterDuration
40 | )
41 | }
42 | val returnAnimation =
43 | getWindowMetaphorAnimation(metaphor.returnAnimation)?.let {
44 | addAnimationProperties(
45 | it,
46 | metaphor,
47 | metaphor.returnDuration
48 | )
49 | }
50 |
51 | window.enterTransition = enterAnimation
52 | window.exitTransition = exitAnimation
53 | window.reenterTransition = reenterAnimation
54 | window.returnTransition = returnAnimation
55 | }
56 |
57 | /** applies Properties on Animation form attributes. */
58 | @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
59 | @JvmSynthetic
60 | internal fun Activity.addAnimationProperties(
61 | transition: android.transition.Transition,
62 | metaphor: MetaphorActivity,
63 | animationDuration: Long
64 | ): android.transition.Transition {
65 |
66 | if (transition is MaterialContainerTransform) {
67 |
68 | if (metaphor.startActivity) {
69 | setExitSharedElementCallback(MaterialContainerTransformSharedElementCallback())
70 | } else {
71 | setEnterSharedElementCallback(MaterialContainerTransformSharedElementCallback())
72 | metaphor.view?.transitionName = metaphor.transitionName
73 |
74 | transition.apply {
75 | interpolator = FastOutSlowInInterpolator()
76 | fadeMode = MaterialContainerTransform.FADE_MODE_IN
77 | }
78 | window.sharedElementEnterTransition = transition.apply {
79 | setAllContainerColors(Color.TRANSPARENT)
80 | scrimColor = Color.TRANSPARENT
81 | }
82 | window.sharedElementReturnTransition = transition.apply {
83 | setAllContainerColors(Color.TRANSPARENT)
84 | scrimColor = Color.TRANSPARENT
85 | }
86 | }
87 | }
88 | transition.apply {
89 | duration = animationDuration
90 | pathMotion = metaphor.motion
91 |
92 | addTarget(metaphor.view)
93 | window.allowEnterTransitionOverlap = metaphor.enterTransitionOverlap
94 | window.allowReturnTransitionOverlap = metaphor.returnTransitionOverlap
95 | }
96 | return transition
97 | }
98 |
--------------------------------------------------------------------------------
/app/src/main/java/com/androidpoet/metaphordemo/activties/FragmentHostActivty.kt:
--------------------------------------------------------------------------------
1 |
2 | package com.androidpoet.metaphordemo.activties
3 |
4 | import android.os.Build
5 | import android.os.Bundle
6 | import android.view.View
7 | import android.widget.FrameLayout
8 | import androidx.annotation.RequiresApi
9 | import androidx.appcompat.app.AppCompatActivity
10 | import androidx.core.view.ViewCompat
11 | import androidx.core.view.WindowInsetsCompat
12 | import androidx.lifecycle.lifecycleScope
13 | import androidx.navigation.findNavController
14 | import androidx.navigation.ui.AppBarConfiguration
15 | import androidx.navigation.ui.setupWithNavController
16 | import com.androidpoet.metaphor.hide
17 | import com.androidpoet.metaphor.show
18 | import com.androidpoet.metaphordemo.R
19 | import com.androidpoet.metaphordemo.databinding.ActivityHostActivtyBinding
20 | import com.google.android.material.bottomnavigation.BottomNavigationView
21 |
22 | class FragmentHostActivty : AppCompatActivity() {
23 |
24 | private lateinit var binding: ActivityHostActivtyBinding
25 |
26 | @RequiresApi(Build.VERSION_CODES.M)
27 | override fun onCreate(savedInstanceState: Bundle?) {
28 | super.onCreate(savedInstanceState)
29 | binding = ActivityHostActivtyBinding.inflate(layoutInflater)
30 | setContentView(binding.container)
31 |
32 | val navView: BottomNavigationView = binding.navView
33 |
34 | val navController = findNavController(R.id.nav_host_fragment_activity_host_activty)
35 | // Passing each menu ID as a set of Ids because each
36 | // menu should be considered as top level destinations.
37 | val appBarConfiguration = AppBarConfiguration(
38 | setOf(
39 | R.id.navigation_home, R.id.navigation_dashboard, R.id.navigation_notifications
40 | )
41 | )
42 | navView.setupWithNavController(navController)
43 | // Hide bottom nav on screens which don't require it
44 | lifecycleScope.launchWhenResumed {
45 | navController.addOnDestinationChangedListener { _, destination, _ ->
46 | when (destination.id) {
47 | R.id.navigation_home, R.id.navigation_dashboard, R.id.navigation_notifications -> navView.show()
48 |
49 | else -> navView.hide()
50 | }
51 | }
52 | }
53 | if (Build.VERSION.SDK_INT >= 30) {
54 |
55 | // Root ViewGroup of my activity
56 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
57 | val decor: View = window.decorView
58 | decor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR)
59 | }
60 | ViewCompat.setOnApplyWindowInsetsListener(binding.root) { view, windowInsets ->
61 |
62 | val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
63 |
64 | // Apply the insets as a margin to the view. Here the system is setting
65 | // only the bottom, left, and right dimensions, but apply whichever insets are
66 | // appropriate to your layout. You can also update the view padding
67 | // if that's more appropriate.
68 |
69 | view.layoutParams = (view.layoutParams as FrameLayout.LayoutParams).apply {
70 | leftMargin = insets.left
71 | bottomMargin = insets.bottom
72 | rightMargin = insets.right
73 | }
74 |
75 | // Return CONSUMED if you don't want want the window insets to keep being
76 | // passed down to descendant views.
77 | WindowInsetsCompat.CONSUMED
78 | }
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_add_note.xml:
--------------------------------------------------------------------------------
1 |
2 |
20 |
21 |
22 |
23 |
28 |
29 |
33 |
34 |
35 |
50 |
51 |
65 |
66 |
77 |
78 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
21 |
22 |
25 |
26 |
32 |
33 |
34 |
38 |
39 |
48 |
49 |
55 |
56 |
65 |
66 |
74 |
75 |
76 |
77 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_dashboard.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
21 |
22 |
29 |
33 |
34 |
43 |
44 |
50 |
51 |
60 |
61 |
69 |
70 |
71 |
72 |
78 |
79 |
80 |
92 |
93 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/artist_linear_list.xml:
--------------------------------------------------------------------------------
1 |
19 |
20 |
21 |
27 |
28 |
29 |
34 |
35 |
40 |
41 |
48 |
49 |
59 |
60 |
61 |
62 |
72 |
73 |
81 |
82 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
--------------------------------------------------------------------------------
/app/src/main/java/com/androidpoet/metaphordemo/ui/notifications/NotificationsFragment.kt:
--------------------------------------------------------------------------------
1 |
2 | package com.androidpoet.metaphordemo.ui.notifications
3 |
4 | import android.os.Build
5 | import android.os.Bundle
6 | import android.view.LayoutInflater
7 | import android.view.View
8 | import android.view.ViewGroup
9 | import androidx.annotation.RequiresApi
10 | import androidx.fragment.app.Fragment
11 | import com.androidpoet.metaphor.MetaphorAnimation
12 | import com.androidpoet.metaphor.MetaphorFragment
13 | import com.androidpoet.metaphor.MetaphorView
14 | import com.androidpoet.metaphordemo.R
15 | import com.androidpoet.metaphordemo.databinding.FragmentNotificationsBinding
16 | import com.bumptech.glide.Glide
17 | import java.util.Random
18 |
19 | class NotificationsFragment : Fragment() {
20 |
21 | private var _binding: FragmentNotificationsBinding? = null
22 |
23 | // This property is only valid between onCreateView and
24 | // onDestroyView.
25 | private val binding get() = _binding!!
26 |
27 | private val images = arrayListOf(
28 | R.drawable.undraw_drag,
29 | R.drawable.undraw_winners,
30 | R.drawable.undraw_social_sharing,
31 | R.drawable.undraw_drag,
32 | R.drawable.undraw_winners,
33 | R.drawable.undraw_social_sharing,
34 | R.drawable.undraw_drag,
35 | R.drawable.undraw_winners,
36 | R.drawable.undraw_social_sharing,
37 | R.drawable.undraw_winners
38 | )
39 |
40 | override fun onCreate(savedInstanceState: Bundle?) {
41 | super.onCreate(savedInstanceState)
42 | // FadeThrough inside fragment
43 | val meta = MetaphorFragment.Builder(this)
44 | .setEnterAnimation(MetaphorAnimation.ElevationScale)
45 | .setExitAnimation(MetaphorAnimation.ElevationScaleGrow)
46 | .build()
47 | meta.animate()
48 | }
49 |
50 | override fun onCreateView(
51 | inflater: LayoutInflater,
52 | container: ViewGroup?,
53 | savedInstanceState: Bundle?
54 | ): View {
55 |
56 | _binding = FragmentNotificationsBinding.inflate(inflater, container, false)
57 |
58 | return binding.root
59 | }
60 |
61 | @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
62 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
63 | super.onViewCreated(view, savedInstanceState)
64 |
65 | Glide.with(requireContext()).load(getRandomItem(images)).into(binding.img)
66 | Glide.with(requireContext()).load(getRandomItem(images)).into(binding.img2)
67 | Glide.with(requireContext()).load(getRandomItem(images)).into(binding.img3)
68 |
69 | binding.SharedX.setOnClickListener {
70 |
71 | val meta = MetaphorView.Builder(binding.img)
72 | .setDuration(1000)
73 | .setEndView(binding.img)
74 | .setMetaphorAnimation(MetaphorAnimation.Fade)
75 | .build()
76 | meta.animate()
77 | }
78 |
79 | binding.SharedY.setOnClickListener {
80 |
81 | val meta = MetaphorView.Builder(binding.img)
82 | .setDuration(1000)
83 | .setEndView(binding.img)
84 | .setMetaphorAnimation(MetaphorAnimation.Fade)
85 | .build()
86 | meta.animate()
87 | }
88 | binding.SharedZ.setOnClickListener {
89 |
90 | val meta = MetaphorView.Builder(binding.img)
91 | .setDuration(1000)
92 | .setEndView(binding.img)
93 | .setMetaphorAnimation(MetaphorAnimation.FadeThrough)
94 | .build()
95 | meta.animate()
96 | }
97 |
98 | binding.materialFadeThrough.setOnClickListener {
99 |
100 | val meta = MetaphorView.Builder(binding.img2)
101 | .setDuration(1000)
102 | .setEndView(binding.img2)
103 | .setMetaphorAnimation(MetaphorAnimation.FadeThrough)
104 | .build()
105 | meta.animate()
106 | }
107 |
108 | binding.materialFade.setOnClickListener {
109 |
110 | Glide.with(requireContext()).load(getRandomItem(images)).into(binding.img3)
111 | val meta = MetaphorView.Builder(binding.img3)
112 | .setDuration(1000)
113 | .setEndView(binding.img3)
114 | .setMetaphorAnimation(MetaphorAnimation.FadeThrough)
115 | .build()
116 | meta.animate()
117 | }
118 | }
119 |
120 | override fun onDestroyView() {
121 | super.onDestroyView()
122 |
123 | _binding = null
124 | }
125 |
126 | private fun getRandomItem(list: List): T {
127 | val random = Random()
128 | val listSize = list.size
129 | val randomIndex: Int = random.nextInt(listSize)
130 | return list[randomIndex]
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/app/src/main/java/com/androidpoet/metaphordemo/ui/home/ArtistDetailFragment.kt:
--------------------------------------------------------------------------------
1 |
2 | package com.androidpoet.metaphordemo.ui.home
3 |
4 | import android.graphics.drawable.Drawable
5 | import android.os.Build
6 | import android.os.Bundle
7 | import android.view.LayoutInflater
8 | import android.view.View
9 | import android.view.ViewGroup
10 | import androidx.annotation.RequiresApi
11 | import androidx.fragment.app.Fragment
12 | import androidx.navigation.fragment.findNavController
13 | import androidx.navigation.fragment.navArgs
14 | import com.androidpoet.metaphor.MetaphorAnimation
15 | import com.androidpoet.metaphor.MetaphorFragment
16 | import com.androidpoet.metaphor.MetaphorView
17 | import com.androidpoet.metaphor.metaphorView
18 | import com.androidpoet.metaphordemo.R
19 | import com.androidpoet.metaphordemo.databinding.FragmentArtistDetailBinding
20 | import com.bumptech.glide.Glide
21 | import com.bumptech.glide.Priority
22 | import com.bumptech.glide.load.DataSource
23 | import com.bumptech.glide.load.engine.GlideException
24 | import com.bumptech.glide.request.RequestListener
25 | import com.bumptech.glide.request.target.Target
26 | import com.google.android.material.transition.MaterialArcMotion
27 |
28 | class ArtistDetailFragment : Fragment() {
29 |
30 | val args: ArtistDetailFragmentArgs by navArgs()
31 | private lateinit var viewBinding: FragmentArtistDetailBinding
32 |
33 | override fun onCreate(savedInstanceState: Bundle?) {
34 | super.onCreate(savedInstanceState)
35 | }
36 |
37 | @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
38 | override fun onCreateView(
39 | inflater: LayoutInflater,
40 | container: ViewGroup?,
41 | savedInstanceState: Bundle?
42 | ): View {
43 | viewBinding = FragmentArtistDetailBinding.inflate(inflater, container, false).apply {
44 | lifecycleOwner = viewLifecycleOwner
45 | }
46 | return viewBinding.root
47 | }
48 |
49 | @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
50 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
51 | super.onViewCreated(view, savedInstanceState)
52 |
53 | /** This is the method to perform MaterialContainerTransform which we need to call inside onViewCreated
54 | * it is important to call this method inside onViewCreated */
55 | // metaphorDestinationFragmentMaterialContainerTransform(view, args.data.pos.toString())
56 |
57 | val metaphor = MetaphorFragment.Builder(this)
58 | .setEnterDuration(1000)
59 | .setView(view)
60 | .setTransitionName(args.data.pos.toString())
61 | .setExitAnimation(MetaphorAnimation.ContainerTransform)
62 | .setMotion(MaterialArcMotion())
63 | .build()
64 | metaphor.animate()
65 |
66 | viewBinding.toolBar.setNavigationIcon(R.drawable.ic_baseline_arrow_back_24); // your drawable
67 | viewBinding.toolBar.setNavigationOnClickListener(
68 | View.OnClickListener {
69 | // back button pressed
70 | findNavController().popBackStack()
71 | }
72 | )
73 |
74 | viewBinding.fabDetail.setOnClickListener {
75 |
76 | val meta = metaphorView(viewBinding.fabDetail) {
77 | setDuration(1000)
78 | setEndView(viewBinding.controls)
79 | setMetaphorAnimation(MetaphorAnimation.ContainerTransform)
80 | setMotion(MaterialArcMotion())
81 | build()
82 | }
83 |
84 | meta.animate()
85 | }
86 |
87 | viewBinding.controls.setOnClickListener {
88 | // it is reference for the currant view
89 | // params[endView]you need to pass end view for the transformation
90 | val meta = MetaphorView.Builder(it)
91 | .setDuration(1000)
92 | .setEndView(viewBinding.fabDetail)
93 | .setMetaphorAnimation(MetaphorAnimation.ContainerTransform)
94 | .setMotion(MaterialArcMotion())
95 | .build()
96 | meta.animate()
97 | }
98 |
99 | // load image with palette
100 | Glide.with(requireContext())
101 | .load(args.data.img)
102 | .thumbnail(
103 | Glide.with(requireContext())
104 | .load(args.data.img)
105 | .priority(Priority.IMMEDIATE)
106 |
107 | )
108 | .addListener(object : RequestListener {
109 | override fun onLoadFailed(
110 | e: GlideException?,
111 | model: Any?,
112 | target: Target?,
113 | isFirstResource: Boolean
114 | ): Boolean {
115 | return false
116 | }
117 |
118 | override fun onResourceReady(
119 | resource: Drawable?,
120 | model: Any?,
121 | target: Target?,
122 | dataSource: DataSource?,
123 | isFirstResource: Boolean
124 | ): Boolean {
125 |
126 | return false
127 | }
128 | })
129 | .into(viewBinding.artistImageView)
130 | }
131 |
132 | override fun onDestroyView() {
133 |
134 | super.onDestroyView()
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/metaphor/src/main/java/com/androidpoet/metaphor/MetaphorWindow.kt:
--------------------------------------------------------------------------------
1 |
2 | package com.androidpoet.metaphor
3 |
4 | import android.view.View
5 | import android.widget.PopupWindow
6 | import androidx.annotation.MainThread
7 |
8 | @DslMarker
9 | internal annotation class MetaphorWindowInlineDsl
10 |
11 | /**
12 | * Creates an instance of the [MetaphorWindow] by scope of the [MetaphorWindow.Builder] using kotlin dsl.
13 | *
14 | * @param activity A context for creating resources of the [MetaphorWindow].
15 | * @param block A dsl scope lambda from the [MetaphorWindow.Builder].
16 | * */
17 | @MainThread
18 | @JvmSynthetic
19 | @MetaphorWindowInlineDsl
20 | public inline fun metaphorWindow(
21 | popupWindow: PopupWindow,
22 | crossinline block: MetaphorWindow.Builder.() -> Unit
23 | ): MetaphorWindow =
24 | MetaphorWindow.Builder(popupWindow).apply(block).build()
25 |
26 | /**
27 | * MetaphorActivity implements material motion animations.
28 | *
29 | * @see [MetaphorWindow](https://github.com/AndroidPoet/Metaphor)
30 | *
31 | * @param builder A [MetaphorWindow.Builder] for creating an instance of the [MetaphorWindow].
32 | */
33 | public class MetaphorWindow private constructor(
34 | builder: Builder
35 | ) {
36 | /** duration of enter the animations. */
37 | public val enterDuration: Long = builder.enterDuration
38 |
39 | /** duration of exit the animations. */
40 | public val exitDuration: Long = builder.exitDuration
41 |
42 | /** Enter AnimationOverlap of Activity. */
43 | public val enterTransitionOverlap: Boolean = builder.enterTransitionOverlap
44 |
45 | /** Return AnimationOverlap of Activity. */
46 | public val returnTransitionOverlap: Boolean = builder.returnTransitionOverlap
47 |
48 | /** Enter Animation of fragment. */
49 | public var enterAnimation: MetaphorAnimation = builder.enterAnimation
50 |
51 | /** Exit Animation of fragment. */
52 | public var exitAnimation: MetaphorAnimation = builder.exitAnimation
53 |
54 | /** Motion path of on fragment animation */
55 | public val motion: android.transition.PathMotion = builder.motion
56 |
57 | /** Fragment on which animation will apply */
58 | public val window: PopupWindow = builder.popupWindow
59 |
60 | /** Builder class for [MetaphorFragment]. */
61 | @MetaphorViewInlineDsl
62 | public class Builder(public val popupWindow: PopupWindow) {
63 |
64 | @set:JvmSynthetic
65 | public var enterDuration: Long = 300
66 |
67 | @set:JvmSynthetic
68 | public var reenterDuration: Long = 300
69 |
70 | @set:JvmSynthetic
71 | public var exitDuration: Long = 300
72 |
73 | @set:JvmSynthetic
74 | public var returnDuration: Long = 300
75 |
76 | @set:JvmSynthetic
77 | public var enterAnimation: MetaphorAnimation = MetaphorAnimation.None
78 |
79 | @set:JvmSynthetic
80 | public var exitAnimation: MetaphorAnimation = MetaphorAnimation.None
81 |
82 | @set:JvmSynthetic
83 | public var motion: android.transition.PathMotion = android.transition.ArcMotion()
84 |
85 | @set:JvmSynthetic
86 | public var view: View? = null
87 |
88 | @set:JvmSynthetic
89 | public var transitionName: String = ""
90 |
91 | @set:JvmSynthetic
92 | public var enterTransitionOverlap: Boolean = false
93 |
94 | @set:JvmSynthetic
95 | public var returnTransitionOverlap: Boolean = false
96 |
97 | /** sets the duration of the Animation. */
98 | public fun setEnterDuration(value: Long): Builder = apply { this.enterDuration = value }
99 |
100 | /** sets the duration of the Animation. */
101 | public fun setExitDuration(value: Long): Builder = apply { this.exitDuration = value }
102 |
103 | /** sets enter the animation of the Activity. */
104 | public fun setEnterAnimation(value: MetaphorAnimation): Builder =
105 | apply { this.enterAnimation = value }
106 |
107 | /** sets the exit animation of the Activity. */
108 | public fun setExitAnimation(value: MetaphorAnimation): Builder =
109 | apply { this.exitAnimation = value }
110 |
111 | /** sets the view of the Activity. */
112 | public fun setView(value: View): Builder = apply { this.view = value }
113 |
114 | /** sets the motion of the View. */
115 | public fun setMotion(value: android.transition.PathMotion): Builder =
116 | apply { this.motion = value }
117 |
118 | /** sets the transition of the View. */
119 | public fun setTransitionName(value: String): Builder = apply { this.transitionName = value }
120 |
121 | /** sets the enter overlap of the Activity. */
122 | public fun setEnterOverlap(value: Boolean): Builder =
123 | apply { this.enterTransitionOverlap = value }
124 |
125 | /** sets the return overlap of the Activity. */
126 | public fun setReturnOverlap(value: Boolean): Builder =
127 | apply { this.returnTransitionOverlap = value }
128 |
129 | public fun build(): MetaphorWindow = MetaphorWindow(this)
130 | }
131 |
132 | /** starts animation. */
133 | public fun animate() {
134 | window.applyAnimation(this)
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/app/src/main/java/com/androidpoet/metaphordemo/ui/home/ArtistListFragment.kt:
--------------------------------------------------------------------------------
1 |
2 | package com.androidpoet.metaphordemo.ui.home
3 |
4 | import android.os.Build
5 | import android.os.Bundle
6 | import android.view.LayoutInflater
7 | import android.view.View
8 | import android.view.ViewGroup
9 | import androidx.annotation.RequiresApi
10 | import androidx.fragment.app.Fragment
11 | import androidx.lifecycle.lifecycleScope
12 | import androidx.navigation.fragment.FragmentNavigatorExtras
13 | import androidx.navigation.fragment.findNavController
14 | import androidx.recyclerview.widget.GridLayoutManager
15 | import androidx.recyclerview.widget.LinearLayoutManager
16 | import com.androidpoet.metaphor.MetaphorAnimation
17 | import com.androidpoet.metaphor.hold
18 | import com.androidpoet.metaphor.metaphorFragment
19 | import com.androidpoet.metaphordemo.R
20 | import com.androidpoet.metaphordemo.databinding.FragmentListBinding
21 | import com.bumptech.glide.Glide
22 | import com.google.gson.Gson
23 | import com.google.gson.reflect.TypeToken
24 |
25 | class ArtistListFragment : Fragment() {
26 |
27 | private lateinit var artistGridListAdapter: ArtistGridListAdapter
28 | private lateinit var artistLinearListAdapter: ArtistLinearListAdapter
29 | private lateinit var viewBinding: FragmentListBinding
30 |
31 | private var isGrid: Boolean = true
32 |
33 | override fun onCreate(savedInstanceState: Bundle?) {
34 | super.onCreate(savedInstanceState)
35 |
36 | val meta = metaphorFragment(this) {
37 | setExitAnimation(MetaphorAnimation.ElevationScaleGrow)
38 | setReenterAnimation(MetaphorAnimation.ElevationScale)
39 |
40 | build()
41 | }
42 | meta.animate()
43 |
44 | artistGridListAdapter = ArtistGridListAdapter(requireContext(), Glide.with(requireContext()))
45 | artistLinearListAdapter =
46 | ArtistLinearListAdapter(requireContext(), Glide.with(requireContext()))
47 | artistGridListAdapter.callback = object : ArtistGridListAdapter.Callback {
48 | override fun onClick(view: View, item: SampleResponse, imageUrl: String) {
49 | /**this method is used for MaterialContainerTransform it add MaterialElevationScale
50 | * to components] */
51 |
52 | val extras = FragmentNavigatorExtras(view to item.pos.toString())
53 | val action = ArtistListFragmentDirections.navToCharacterDetailFragment(item)
54 | findNavController().navigate(action, extras)
55 | }
56 | }
57 |
58 | artistLinearListAdapter.callback = object : ArtistLinearListAdapter.Callback {
59 | override fun onClick(view: View, item: SampleResponse, imageUrl: String) {
60 | /**this method is used for MaterialContainerTransform it add MaterialElevationScale
61 | * to components] */
62 |
63 | val extras = FragmentNavigatorExtras(view to item.pos.toString())
64 | val action = ArtistListFragmentDirections.navToCharacterDetailFragment(item)
65 | findNavController().navigate(action, extras)
66 | }
67 | }
68 | }
69 |
70 | private fun sampleResponse(): List {
71 | val response = resources.openRawResource(R.raw.grid).bufferedReader()
72 | .use { it.readText() }
73 | return Gson().fromJson(response, object : TypeToken>() {}.type)
74 | }
75 |
76 | override fun onCreateView(
77 | inflater: LayoutInflater,
78 | container: ViewGroup?,
79 | savedInstanceState: Bundle?
80 | ): View {
81 | viewBinding = FragmentListBinding.inflate(inflater, container, false).apply {
82 | lifecycleOwner = viewLifecycleOwner
83 | }
84 | return viewBinding.root
85 | }
86 |
87 | @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
88 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
89 | super.onViewCreated(view, savedInstanceState)
90 | /**this method is used for MaterialContainerTransform it add some delay to load animation basically it will wait for recyclerview to be drawn */
91 | hold()
92 |
93 | loadRecyclerView(isGrid)
94 | viewBinding.reorder.setOnClickListener {
95 |
96 | if (isGrid) {
97 | isGrid = false
98 | loadRecyclerView(isGrid)
99 | } else {
100 | isGrid = true
101 |
102 | loadRecyclerView(isGrid)
103 | }
104 | }
105 | }
106 |
107 | fun loadRecyclerView(isGrid: Boolean) {
108 |
109 | if (isGrid) {
110 | viewBinding.rcv.apply {
111 |
112 | layoutManager = GridLayoutManager(requireContext(), 2)
113 | adapter = artistGridListAdapter.apply {
114 | viewLifecycleOwner.lifecycleScope.launchWhenStarted {
115 | submitList(sampleResponse())
116 | }
117 | }
118 | }
119 | } else {
120 | viewBinding.rcv.apply {
121 |
122 | layoutManager = LinearLayoutManager(requireContext())
123 | adapter = artistLinearListAdapter.apply {
124 | viewLifecycleOwner.lifecycleScope.launchWhenStarted {
125 | submitList(sampleResponse())
126 | }
127 | }
128 | }
129 | }
130 | }
131 | }
132 |
--------------------------------------------------------------------------------
/app/src/main/java/com/androidpoet/metaphordemo/ui/dashboard/DashboardFragment.kt:
--------------------------------------------------------------------------------
1 |
2 | package com.androidpoet.metaphordemo.ui.dashboard
3 |
4 | import android.os.Build
5 | import android.os.Bundle
6 | import android.view.LayoutInflater
7 | import android.view.View
8 | import android.view.ViewGroup
9 | import androidx.annotation.RequiresApi
10 | import androidx.fragment.app.Fragment
11 | import androidx.lifecycle.lifecycleScope
12 | import androidx.navigation.fragment.FragmentNavigatorExtras
13 | import androidx.navigation.fragment.findNavController
14 | import androidx.recyclerview.widget.GridLayoutManager
15 | import androidx.recyclerview.widget.LinearLayoutManager
16 | import com.androidpoet.metaphor.metaphorFragment
17 | import com.androidpoet.metaphordemo.R
18 | import com.androidpoet.metaphordemo.databinding.FragmentDashboardBinding
19 | import com.androidpoet.metaphordemo.factory.MetaphorFragmentFactory
20 | import com.androidpoet.metaphordemo.ui.home.ArtistGridListAdapter
21 | import com.androidpoet.metaphordemo.ui.home.ArtistLinearListAdapter
22 | import com.androidpoet.metaphordemo.ui.home.SampleResponse
23 | import com.bumptech.glide.Glide
24 | import com.google.gson.Gson
25 | import com.google.gson.reflect.TypeToken
26 |
27 | class DashboardFragment : Fragment() {
28 |
29 | private var _binding: FragmentDashboardBinding? = null
30 |
31 | // This property is only valid between onCreateView and
32 | // onDestroyView.
33 | private val viewBinding get() = _binding!!
34 | private lateinit var artistGridListAdapter: ArtistGridListAdapter
35 | private lateinit var artistLinearListAdapter: ArtistLinearListAdapter
36 |
37 | private var isGrid: Boolean = true
38 | private val metaphorFragment by metaphorFragment()
39 | override fun onCreate(savedInstanceState: Bundle?) {
40 | super.onCreate(savedInstanceState)
41 | metaphorFragment.animate()
42 |
43 | artistGridListAdapter = ArtistGridListAdapter(requireContext(), Glide.with(requireContext()))
44 | artistLinearListAdapter =
45 | ArtistLinearListAdapter(requireContext(), Glide.with(requireContext()))
46 | artistGridListAdapter.callback = object : ArtistGridListAdapter.Callback {
47 | override fun onClick(view: View, item: SampleResponse, imageUrl: String) {
48 | /**this method is used for MaterialContainerTransform it add MaterialElevationScale
49 | * to components] */
50 |
51 | val extras = FragmentNavigatorExtras(view to item.pos.toString())
52 | val action = DashboardFragmentDirections.navToCharacterDetailFragment(item)
53 | findNavController().navigate(action, extras)
54 | }
55 | }
56 |
57 | artistLinearListAdapter.callback = object : ArtistLinearListAdapter.Callback {
58 | override fun onClick(view: View, item: SampleResponse, imageUrl: String) {
59 | /**this method is used for MaterialContainerTransform it add MaterialElevationScale
60 | * to components] */
61 |
62 | val extras = FragmentNavigatorExtras(view to item.pos.toString())
63 | val action = DashboardFragmentDirections.navToCharacterDetailFragment(item)
64 | findNavController().navigate(action, extras)
65 | }
66 | }
67 | }
68 |
69 | @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
70 | override fun onCreateView(
71 | inflater: LayoutInflater,
72 | container: ViewGroup?,
73 | savedInstanceState: Bundle?
74 | ): View {
75 |
76 | _binding = FragmentDashboardBinding.inflate(inflater, container, false)
77 | val root: View = viewBinding.root
78 |
79 | viewBinding.fab.setOnClickListener {
80 | val action = DashboardFragmentDirections.actionNavigationHomeToAddnoteFragment()
81 | findNavController().navigate(action)
82 | }
83 |
84 | return root
85 | }
86 |
87 | @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
88 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
89 | super.onViewCreated(view, savedInstanceState)
90 | loadRecyclerView(isGrid)
91 | viewBinding.reorder.setOnClickListener {
92 |
93 | if (isGrid) {
94 | isGrid = false
95 |
96 | loadRecyclerView(isGrid)
97 | } else {
98 | isGrid = true
99 |
100 | loadRecyclerView(isGrid)
101 | }
102 | }
103 | }
104 |
105 | private fun loadRecyclerView(isGrid: Boolean) {
106 |
107 | if (isGrid) {
108 | viewBinding.rcv.apply {
109 | layoutManager = GridLayoutManager(requireContext(), 2)
110 | adapter = artistGridListAdapter.apply {
111 | viewLifecycleOwner.lifecycleScope.launchWhenStarted {
112 | submitList(sampleResponse())
113 | }
114 | }
115 | }
116 | } else {
117 | viewBinding.rcv.apply {
118 | layoutManager = LinearLayoutManager(requireContext())
119 | adapter = artistLinearListAdapter.apply {
120 | viewLifecycleOwner.lifecycleScope.launchWhenStarted {
121 |
122 | submitList(sampleResponse())
123 | }
124 | }
125 | }
126 | }
127 | }
128 |
129 | override fun onDestroyView() {
130 | super.onDestroyView()
131 | _binding = null
132 | }
133 |
134 | private fun sampleResponse(): List {
135 | val response = resources.openRawResource(R.raw.list).bufferedReader()
136 | .use { it.readText() }
137 | return Gson().fromJson(response, object : TypeToken>() {}.type)
138 | }
139 | }
140 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_notifications.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
22 |
23 |
29 |
30 |
34 |
35 |
36 |
39 |
40 |
45 |
46 |
47 |
48 |
49 |
57 |
58 |
75 |
76 |
91 |
92 |
108 |
109 |
110 |
111 |
115 |
116 |
117 |
128 |
129 |
133 |
134 |
135 |
136 |
137 |
138 |
149 |
150 |
151 |
152 |
153 |
--------------------------------------------------------------------------------
/metaphor/src/main/java/com/androidpoet/metaphor/ViewExtensions.kt:
--------------------------------------------------------------------------------
1 |
2 | package com.androidpoet.metaphor
3 |
4 | import android.animation.ValueAnimator
5 | import android.annotation.SuppressLint
6 | import android.graphics.Bitmap
7 | import android.graphics.Bitmap.Config.ARGB_8888
8 | import android.graphics.Color
9 | import android.graphics.drawable.BitmapDrawable
10 | import android.os.Build
11 | import android.view.View
12 | import android.view.View.GONE
13 | import android.view.View.VISIBLE
14 | import android.view.ViewGroup
15 | import android.view.animation.AnimationUtils
16 | import androidx.annotation.Px
17 | import androidx.annotation.RequiresApi
18 | import androidx.core.animation.doOnEnd
19 | import androidx.core.graphics.applyCanvas
20 | import androidx.core.view.ViewCompat
21 | import androidx.core.view.isVisible
22 | import androidx.transition.TransitionManager
23 | import com.google.android.material.bottomnavigation.BottomNavigationView
24 | import com.google.android.material.transition.MaterialContainerTransform
25 |
26 | /** applies Animation form attributes to a View instance. */
27 | @JvmSynthetic
28 | internal fun View.applyAnimation(
29 | metaphor: MetaphorView
30 | ) {
31 | val parent = parent as? ViewGroup
32 | if (parent != null) {
33 | val transition = getMetaphorAnimation(metaphor.animation)
34 | if (transition != null) {
35 | transition.duration = metaphor.duration
36 | transition.setPathMotion(metaphor.motion)
37 | }
38 |
39 | if (transition is MaterialContainerTransform) {
40 | transition.scrimColor = Color.TRANSPARENT
41 | transition.startView = this
42 | transition.endView = metaphor.endView
43 |
44 | metaphor.endView?.let { transition.addTarget(it) }
45 | }
46 | TransitionManager.beginDelayedTransition(
47 | parent,
48 | transition
49 | )
50 |
51 | // Make any changes to the hierarchy to be animated by the shared axis transition.
52 |
53 | if (this == metaphor.endView) {
54 |
55 | if (metaphor.endView.isVisible) {
56 | this.visibility = GONE
57 | } else {
58 | this.visibility = VISIBLE
59 | }
60 | } else {
61 |
62 | visibility = GONE
63 | if (metaphor.endView != null) {
64 | metaphor.endView.visibility = VISIBLE
65 | }
66 | }
67 | }
68 | }
69 | /**
70 | * Potentially animate showing a [BottomNavigationView].
71 | *
72 | * Abruptly changing the visibility leads to a re-layout of main content, animating
73 | * `translationY` leaves a gap where the view was that content does not fill.
74 | *
75 | * Instead, take a snapshot of the view, and animate this in, only changing the visibility (and
76 | * thus layout) when the animation completes.
77 | */
78 | @SuppressLint("NewApi")
79 | @RequiresApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
80 | @JvmSynthetic
81 | public fun BottomNavigationView.show() {
82 | if (visibility == VISIBLE) return
83 |
84 | val parent = parent as ViewGroup
85 | // View needs to be laid out to create a snapshot & know position to animate. If view isn't
86 | // laid out yet, need to do this manually.
87 | if (!isLaidOut) {
88 | measure(
89 | View.MeasureSpec.makeMeasureSpec(parent.width, View.MeasureSpec.EXACTLY),
90 | View.MeasureSpec.makeMeasureSpec(parent.height, View.MeasureSpec.AT_MOST)
91 | )
92 | layout(parent.left, parent.height - measuredHeight, parent.right, parent.height)
93 | }
94 |
95 | val drawable = BitmapDrawable(context.resources, drawToBitmap())
96 | drawable.setBounds(left, parent.height, right, parent.height + height)
97 | parent.overlay.add(drawable)
98 | ValueAnimator.ofInt(parent.height, top).apply {
99 | startDelay = 100L
100 | duration = 300L
101 | interpolator = AnimationUtils.loadInterpolator(
102 | context,
103 | android.R.interpolator.linear_out_slow_in
104 | )
105 | addUpdateListener {
106 | val newTop = it.animatedValue as Int
107 | drawable.setBounds(left, newTop, right, newTop + height)
108 | }
109 | doOnEnd {
110 | parent.overlay.remove(drawable)
111 | visibility = VISIBLE
112 | }
113 | start()
114 | }
115 | }
116 |
117 | /**
118 | * Potentially animate hiding a [BottomNavigationView].
119 | *
120 | * Abruptly changing the visibility leads to a re-layout of main content, animating
121 | * `translationY` leaves a gap where the view was that content does not fill.
122 | *
123 | * Instead, take a snapshot, instantly hide the view (so content lays out to fill), then animate
124 | * out the snapshot.
125 | */
126 | @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
127 | @JvmSynthetic
128 | public fun BottomNavigationView.hide() {
129 | if (visibility == GONE) return
130 |
131 | val drawable = BitmapDrawable(context.resources, drawToBitmap())
132 | val parent = parent as ViewGroup
133 | drawable.setBounds(left, top, right, bottom)
134 | parent.overlay.add(drawable)
135 | visibility = GONE
136 | ValueAnimator.ofInt(top, parent.height).apply {
137 | startDelay = 100L
138 | duration = 200L
139 | interpolator = AnimationUtils.loadInterpolator(
140 | context,
141 | android.R.interpolator.fast_out_linear_in
142 | )
143 | addUpdateListener {
144 | val newTop = it.animatedValue as Int
145 | drawable.setBounds(left, newTop, right, newTop + height)
146 | }
147 | doOnEnd {
148 | parent.overlay.remove(drawable)
149 | }
150 | start()
151 | }
152 | }
153 |
154 | /**
155 | * A copy of the KTX method, adding the ability to add extra padding the bottom of the [Bitmap];
156 | * useful when it will be used in a [android.graphics.BitmapShader]with
157 | * a [android.graphics.Shader.TileMode.CLAMP][CLAMP tile mode].
158 | */
159 | @JvmSynthetic
160 | public fun View.drawToBitmap(@Px extraPaddingBottom: Int = 0): Bitmap {
161 | if (!ViewCompat.isLaidOut(this)) {
162 | throw IllegalStateException("View needs to be laid out before calling drawToBitmap()")
163 | }
164 | return Bitmap.createBitmap(width, height + extraPaddingBottom, ARGB_8888).applyCanvas {
165 | translate(-scrollX.toFloat(), -scrollY.toFloat())
166 | draw(this)
167 | }
168 | }
169 |
--------------------------------------------------------------------------------
/metaphor/src/main/java/com/androidpoet/metaphor/AnimationsExtenstions.kt:
--------------------------------------------------------------------------------
1 |
2 | package com.androidpoet.metaphor
3 |
4 | import android.os.Build
5 | import android.view.animation.Interpolator
6 | import android.view.animation.LinearInterpolator
7 | import android.view.animation.PathInterpolator
8 | import androidx.annotation.RequiresApi
9 | import androidx.core.graphics.PathParser
10 | import androidx.interpolator.view.animation.FastOutLinearInInterpolator
11 | import androidx.interpolator.view.animation.FastOutSlowInInterpolator
12 | import androidx.interpolator.view.animation.LinearOutSlowInInterpolator
13 | import androidx.transition.Transition
14 | import com.google.android.material.transition.MaterialContainerTransform
15 | import com.google.android.material.transition.MaterialElevationScale
16 | import com.google.android.material.transition.MaterialFade
17 | import com.google.android.material.transition.MaterialFadeThrough
18 | import com.google.android.material.transition.MaterialSharedAxis
19 |
20 | /** applies Metaphor form attributes to a View instance. */
21 | @JvmSynthetic
22 | @PublishedApi
23 | internal fun getMetaphorAnimation(animation: MetaphorAnimation): Transition? {
24 |
25 | when (animation) {
26 | MetaphorAnimation.ContainerTransform -> {
27 | return MaterialContainerTransform()
28 | }
29 | MetaphorAnimation.FadeThrough -> {
30 |
31 | return MaterialFadeThrough()
32 | }
33 |
34 | MetaphorAnimation.Fade -> {
35 | return MaterialFade()
36 | }
37 | MetaphorAnimation.SharedAxisXForward -> {
38 |
39 | return MaterialSharedAxis(MaterialSharedAxis.X, true)
40 | }
41 |
42 | MetaphorAnimation.SharedAxisYForward -> {
43 |
44 | return MaterialSharedAxis(MaterialSharedAxis.Y, true)
45 | }
46 |
47 | MetaphorAnimation.SharedAxisZForward -> {
48 |
49 | return MaterialSharedAxis(MaterialSharedAxis.Z, true)
50 | }
51 | MetaphorAnimation.SharedAxisXBackward -> {
52 |
53 | return MaterialSharedAxis(MaterialSharedAxis.X, false)
54 | }
55 |
56 | MetaphorAnimation.SharedAxisYBackward -> {
57 | return MaterialSharedAxis(MaterialSharedAxis.Y, false)
58 | }
59 |
60 | MetaphorAnimation.SharedAxisZBackward -> {
61 |
62 | return MaterialSharedAxis(MaterialSharedAxis.Z, false)
63 | }
64 |
65 | MetaphorAnimation.ElevationScale -> {
66 | return MaterialElevationScale(false)
67 | }
68 | MetaphorAnimation.ElevationScaleGrow -> {
69 | return MaterialElevationScale(true)
70 | }
71 |
72 | MetaphorAnimation.None -> {
73 | // trick for no animations
74 | return null
75 | }
76 | }
77 | }
78 |
79 | /** applies Metaphor form attributes to a View instance. */
80 | @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
81 | @JvmSynthetic
82 | @PublishedApi
83 | internal fun getWindowMetaphorAnimation(animation: MetaphorAnimation): android.transition.Transition? {
84 |
85 | when (animation) {
86 | MetaphorAnimation.ContainerTransform -> {
87 | return com.google.android.material.transition.platform.MaterialContainerTransform()
88 | }
89 | MetaphorAnimation.FadeThrough -> {
90 |
91 | return com.google.android.material.transition.platform.MaterialFadeThrough()
92 | }
93 |
94 | MetaphorAnimation.Fade -> {
95 | return com.google.android.material.transition.platform.MaterialFade()
96 | }
97 | MetaphorAnimation.SharedAxisXForward -> {
98 |
99 | return com.google.android.material.transition.platform.MaterialSharedAxis(
100 | com.google.android.material.transition.platform.MaterialSharedAxis.X,
101 | true
102 | )
103 | }
104 |
105 | MetaphorAnimation.SharedAxisYForward -> {
106 |
107 | return com.google.android.material.transition.platform.MaterialSharedAxis(
108 | com.google.android.material.transition.platform.MaterialSharedAxis.Y,
109 | true
110 | )
111 | }
112 |
113 | MetaphorAnimation.SharedAxisZForward -> {
114 |
115 | return com.google.android.material.transition.platform.MaterialSharedAxis(
116 | com.google.android.material.transition.platform.MaterialSharedAxis.Z,
117 | true
118 | )
119 | }
120 | MetaphorAnimation.SharedAxisXBackward -> {
121 |
122 | return com.google.android.material.transition.platform.MaterialSharedAxis(
123 | com.google.android.material.transition.platform.MaterialSharedAxis.X,
124 | true
125 | )
126 | }
127 |
128 | MetaphorAnimation.SharedAxisYBackward -> {
129 | return com.google.android.material.transition.platform.MaterialSharedAxis(
130 | com.google.android.material.transition.platform.MaterialSharedAxis.Y,
131 | true
132 | )
133 | }
134 |
135 | MetaphorAnimation.SharedAxisZBackward -> {
136 |
137 | return com.google.android.material.transition.platform.MaterialSharedAxis(
138 | com.google.android.material.transition.platform.MaterialSharedAxis.Z,
139 | true
140 | )
141 | }
142 |
143 | MetaphorAnimation.ElevationScale -> {
144 | return com.google.android.material.transition.platform.MaterialElevationScale(false)
145 | }
146 | MetaphorAnimation.ElevationScaleGrow -> {
147 | return com.google.android.material.transition.platform.MaterialElevationScale(true)
148 | }
149 |
150 | MetaphorAnimation.None -> {
151 | // trick for no animations
152 | return null
153 | }
154 | }
155 | }
156 |
157 | @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
158 | @JvmSynthetic
159 | @PublishedApi
160 | internal fun getInterpolator(animation: MetaphorInterpolator): Interpolator {
161 |
162 | when (animation) {
163 | MetaphorInterpolator.Standard -> {
164 | return FastOutSlowInInterpolator()
165 | }
166 | MetaphorInterpolator.Emphasized -> {
167 | return fastOutExtraSlowIn()
168 | }
169 | MetaphorInterpolator.Decelerated -> {
170 | return LinearOutSlowInInterpolator()
171 | }
172 | MetaphorInterpolator.Accelerated -> {
173 | return FastOutLinearInInterpolator()
174 | }
175 | MetaphorInterpolator.Linear -> {
176 | return LinearInterpolator()
177 | }
178 | }
179 | }
180 |
181 | @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
182 | private fun fastOutExtraSlowIn(): Interpolator {
183 | return PathInterpolator(PathParser.createPathFromPathData("M 0,0 C 0.05, 0, 0.133333, 0.06, 0.166666, 0.4 C 0.208333, 0.82, 0.25, 1, 1, 1"))
184 | }
185 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # Copyright 2015 the original author or authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | ##
21 | ## Gradle start up script for UN*X
22 | ##
23 | ##############################################################################
24 |
25 | # Attempt to set APP_HOME
26 | # Resolve links: $0 may be a link
27 | PRG="$0"
28 | # Need this for relative symlinks.
29 | while [ -h "$PRG" ] ; do
30 | ls=`ls -ld "$PRG"`
31 | link=`expr "$ls" : '.*-> \(.*\)$'`
32 | if expr "$link" : '/.*' > /dev/null; then
33 | PRG="$link"
34 | else
35 | PRG=`dirname "$PRG"`"/$link"
36 | fi
37 | done
38 | SAVED="`pwd`"
39 | cd "`dirname \"$PRG\"`/" >/dev/null
40 | APP_HOME="`pwd -P`"
41 | cd "$SAVED" >/dev/null
42 |
43 | APP_NAME="Gradle"
44 | APP_BASE_NAME=`basename "$0"`
45 |
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48 |
49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
50 | MAX_FD="maximum"
51 |
52 | warn () {
53 | echo "$*"
54 | }
55 |
56 | die () {
57 | echo
58 | echo "$*"
59 | echo
60 | exit 1
61 | }
62 |
63 | # OS specific support (must be 'true' or 'false').
64 | cygwin=false
65 | msys=false
66 | darwin=false
67 | nonstop=false
68 | case "`uname`" in
69 | CYGWIN* )
70 | cygwin=true
71 | ;;
72 | Darwin* )
73 | darwin=true
74 | ;;
75 | MINGW* )
76 | msys=true
77 | ;;
78 | NONSTOP* )
79 | nonstop=true
80 | ;;
81 | esac
82 |
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84 |
85 |
86 | # Determine the Java command to use to start the JVM.
87 | if [ -n "$JAVA_HOME" ] ; then
88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
89 | # IBM's JDK on AIX uses strange locations for the executables
90 | JAVACMD="$JAVA_HOME/jre/sh/java"
91 | else
92 | JAVACMD="$JAVA_HOME/bin/java"
93 | fi
94 | if [ ! -x "$JAVACMD" ] ; then
95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
96 |
97 | Please set the JAVA_HOME variable in your environment to match the
98 | location of your Java installation."
99 | fi
100 | else
101 | JAVACMD="java"
102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
103 |
104 | Please set the JAVA_HOME variable in your environment to match the
105 | location of your Java installation."
106 | fi
107 |
108 | # Increase the maximum file descriptors if we can.
109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
110 | MAX_FD_LIMIT=`ulimit -H -n`
111 | if [ $? -eq 0 ] ; then
112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
113 | MAX_FD="$MAX_FD_LIMIT"
114 | fi
115 | ulimit -n $MAX_FD
116 | if [ $? -ne 0 ] ; then
117 | warn "Could not set maximum file descriptor limit: $MAX_FD"
118 | fi
119 | else
120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
121 | fi
122 | fi
123 |
124 | # For Darwin, add options to specify how the application appears in the dock
125 | if $darwin; then
126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
127 | fi
128 |
129 | # For Cygwin or MSYS, switch paths to Windows format before running java
130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
133 |
134 | JAVACMD=`cygpath --unix "$JAVACMD"`
135 |
136 | # We build the pattern for arguments to be converted via cygpath
137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
138 | SEP=""
139 | for dir in $ROOTDIRSRAW ; do
140 | ROOTDIRS="$ROOTDIRS$SEP$dir"
141 | SEP="|"
142 | done
143 | OURCYGPATTERN="(^($ROOTDIRS))"
144 | # Add a user-defined pattern to the cygpath arguments
145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
147 | fi
148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
149 | i=0
150 | for arg in "$@" ; do
151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
153 |
154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
156 | else
157 | eval `echo args$i`="\"$arg\""
158 | fi
159 | i=`expr $i + 1`
160 | done
161 | case $i in
162 | 0) set -- ;;
163 | 1) set -- "$args0" ;;
164 | 2) set -- "$args0" "$args1" ;;
165 | 3) set -- "$args0" "$args1" "$args2" ;;
166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
172 | esac
173 | fi
174 |
175 | # Escape application args
176 | save () {
177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
178 | echo " "
179 | }
180 | APP_ARGS=`save "$@"`
181 |
182 | # Collect all arguments for the java command, following the shell quoting and substitution rules
183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
184 |
185 | exec "$JAVACMD" "$@"
186 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
24 |
25 |
30 |
33 |
38 |
43 |
48 |
53 |
58 |
63 |
68 |
73 |
78 |
83 |
88 |
93 |
98 |
103 |
108 |
113 |
118 |
123 |
128 |
133 |
138 |
143 |
148 |
153 |
158 |
163 |
168 |
173 |
178 |
183 |
188 |
193 |
194 |
--------------------------------------------------------------------------------
/metaphor/src/main/java/com/androidpoet/metaphor/MetaphorActivity.kt:
--------------------------------------------------------------------------------
1 |
2 | package com.androidpoet.metaphor
3 |
4 | import android.view.View
5 | import androidx.activity.ComponentActivity
6 | import androidx.annotation.MainThread
7 | import androidx.appcompat.app.AppCompatActivity
8 |
9 | @DslMarker
10 | internal annotation class MetaphorActivityInlineDsl
11 |
12 | /**
13 | * Creates an instance of the [MetaphorActivity] by scope of the [MetaphorActivity.Builder] using kotlin dsl.
14 | *
15 | * @param activity A context for creating resources of the [MetaphorActivity].
16 | * @param block A dsl scope lambda from the [MetaphorActivity.Builder].
17 | * */
18 | @MainThread
19 | @JvmSynthetic
20 | @MetaphorActivityInlineDsl
21 | public inline fun metaphorActivity(
22 | activity: ComponentActivity,
23 | crossinline block: MetaphorActivity.Builder.() -> Unit
24 | ): MetaphorActivity =
25 | MetaphorActivity.Builder(activity).apply(block).build()
26 |
27 | /**
28 | * MetaphorActivity implements material motion animations.
29 | *
30 | * @see [MetaphorActivity](https://github.com/AndroidPoet/Metaphor)
31 | *
32 | * @param builder A [MetaphorActivity.Builder] for creating an instance of the [MetaphorActivity].
33 | */
34 | public class MetaphorActivity private constructor(
35 | builder: Builder
36 | ) {
37 | /** duration of enter the animations. */
38 | public val enterDuration: Long = builder.enterDuration
39 |
40 | /** duration of reenter the animations. */
41 | public val reenterDuration: Long = builder.reenterDuration
42 |
43 | /** duration of exit the animations. */
44 | public val exitDuration: Long = builder.exitDuration
45 |
46 | /** duration of return the animations. */
47 | public val returnDuration: Long = builder.returnDuration
48 |
49 | /** Enter AnimationOverlap of Activity. */
50 | public val enterTransitionOverlap: Boolean = builder.enterTransitionOverlap
51 |
52 | /** Return AnimationOverlap of Activity. */
53 | public val returnTransitionOverlap: Boolean = builder.returnTransitionOverlap
54 |
55 | /** Enter Animation of fragment. */
56 | public val enterAnimation: MetaphorAnimation = builder.enterAnimation
57 |
58 | /** Exit Animation of fragment. */
59 | public val exitAnimation: MetaphorAnimation = builder.exitAnimation
60 |
61 | /** Reenter Animation of fragment. */
62 | public val reenterAnimation: MetaphorAnimation = builder.reenterAnimation
63 |
64 | /** Return Animation of fragment. */
65 | public val returnAnimation: MetaphorAnimation = builder.returnAnimation
66 |
67 | /** Motion path of on fragment animation */
68 | public val motion: android.transition.PathMotion = builder.motion
69 |
70 | /** Fragment on which animation will apply */
71 | public val activity: ComponentActivity = builder.activity
72 |
73 | /** start view to transform into fragment */
74 | public val view: View? = builder.view
75 |
76 | /** transitionName to transform view to another fragment */
77 | public val transitionName: String = builder.transitionName
78 |
79 | /** Fragment on which animation will apply */
80 | public val startActivity: Boolean = builder.startActivity
81 |
82 | /** Builder class for [MetaphorFragment]. */
83 | @MetaphorViewInlineDsl
84 | public class Builder(public val activity: ComponentActivity) {
85 |
86 | @set:JvmSynthetic
87 | public var enterDuration: Long = 300
88 |
89 | @set:JvmSynthetic
90 | public var reenterDuration: Long = 300
91 |
92 | @set:JvmSynthetic
93 | public var exitDuration: Long = 300
94 |
95 | @set:JvmSynthetic
96 | public var returnDuration: Long = 300
97 |
98 | @set:JvmSynthetic
99 | public var enterAnimation: MetaphorAnimation = MetaphorAnimation.None
100 |
101 | @set:JvmSynthetic
102 | public var exitAnimation: MetaphorAnimation = MetaphorAnimation.None
103 |
104 | @set:JvmSynthetic
105 | public var reenterAnimation: MetaphorAnimation = MetaphorAnimation.None
106 |
107 | @set:JvmSynthetic
108 | public var returnAnimation: MetaphorAnimation = MetaphorAnimation.None
109 |
110 | @set:JvmSynthetic
111 | public var motion: android.transition.PathMotion = android.transition.ArcMotion()
112 |
113 | @set:JvmSynthetic
114 | public var view: View? = null
115 |
116 | @set:JvmSynthetic
117 | public var transitionName: String = ""
118 |
119 | @set:JvmSynthetic
120 | public var enterTransitionOverlap: Boolean = false
121 |
122 | @set:JvmSynthetic
123 | public var returnTransitionOverlap: Boolean = false
124 |
125 | @set:JvmSynthetic
126 | public var startActivity: Boolean = false
127 |
128 | /** sets the duration of the Animation. */
129 | public fun setEnterDuration(value: Long): Builder = apply { this.enterDuration = value }
130 |
131 | /** sets the duration of the Animation. */
132 | public fun setExitDuration(value: Long): Builder = apply { this.exitDuration = value }
133 |
134 | /** sets the duration of the Animation. */
135 | public fun setReenterDuration(value: Long): Builder = apply { this.reenterDuration = value }
136 |
137 | /** sets the duration of the Animation. */
138 | public fun setReturnDuration(value: Long): Builder = apply { this.returnDuration = value }
139 |
140 | /** sets enter the animation of the Activity. */
141 | public fun setEnterAnimation(value: MetaphorAnimation): Builder =
142 | apply { this.enterAnimation = value }
143 |
144 | /** sets the exit animation of the Activity. */
145 | public fun setExitAnimation(value: MetaphorAnimation): Builder =
146 | apply { this.exitAnimation = value }
147 |
148 | /** sets the return animation of the Activity. */
149 | public fun setReturnAnimation(value: MetaphorAnimation): Builder =
150 | apply { this.returnAnimation = value }
151 |
152 | /** sets the reenter animation of the Activity. */
153 | public fun setReenterAnimation(value: MetaphorAnimation): Builder =
154 | apply { this.reenterAnimation = value }
155 |
156 | /** sets the view of the Activity. */
157 | public fun setView(value: View): Builder = apply { this.view = value }
158 |
159 | /** sets the motion of the View. */
160 | public fun setMotion(value: android.transition.PathMotion): Builder =
161 | apply { this.motion = value }
162 |
163 | /** sets the transition of the View. */
164 | public fun setTransitionName(value: String): Builder = apply { this.transitionName = value }
165 |
166 | /** sets the enter overlap of the Activity. */
167 | public fun setEnterOverlap(value: Boolean): Builder =
168 | apply { this.enterTransitionOverlap = value }
169 |
170 | /** sets the return overlap of the Activity. */
171 | public fun setReturnOverlap(value: Boolean): Builder =
172 | apply { this.returnTransitionOverlap = value }
173 |
174 | /** sets start Activity of MetaphorActivity. */
175 | public fun setStartActivity(value: Boolean): Builder =
176 | apply { this.startActivity = value }
177 |
178 | public fun build(): MetaphorActivity = MetaphorActivity(this)
179 | }
180 |
181 | /** starts animation. */
182 | public fun animate() {
183 | activity.applyAnimation(this)
184 | }
185 |
186 | public abstract class Factory {
187 |
188 | /**
189 | * Creates a new instance of [MetaphorActivity].
190 | *
191 | * @return A new created instance of the [MetaphorActivity].
192 | */
193 | public abstract fun create(fragment: AppCompatActivity): MetaphorActivity
194 | }
195 | }
196 |
--------------------------------------------------------------------------------
/metaphor/src/main/java/com/androidpoet/metaphor/MetaphorFragment.kt:
--------------------------------------------------------------------------------
1 |
2 | package com.androidpoet.metaphor
3 |
4 | import android.graphics.Color
5 | import android.view.View
6 | import androidx.annotation.MainThread
7 | import androidx.fragment.app.Fragment
8 | import androidx.transition.ArcMotion
9 | import androidx.transition.PathMotion
10 |
11 | @DslMarker
12 | public annotation class MetaphorFragmentInlineDsl
13 |
14 | /**
15 | * Creates an instance of the [MetaphorFragment] by scope of the [MetaphorFragment.Builder] using kotlin dsl.
16 | *
17 | * @param fragment A context for creating resources of the [MetaphorFragment].
18 | * @param block A dsl scope lambda from the [MetaphorFragment.Builder].
19 | * */
20 | @MainThread
21 | @JvmSynthetic
22 | @MetaphorFragmentInlineDsl
23 | public inline fun metaphorFragment(
24 | fragment: Fragment,
25 | crossinline block: MetaphorFragment.Builder.() -> Unit
26 | ): MetaphorFragment =
27 | MetaphorFragment.Builder(fragment).apply(block).build()
28 |
29 | /**
30 | * MetaphorFragment implements material motion animations.
31 | *
32 | * @see [MetaphorFragment](https://github.com/AndroidPoet/Metaphor)
33 | *
34 | * @param builder A [MetaphorFragment.Builder] for creating an instance of the [MetaphorFragment].
35 | */
36 | public class MetaphorFragment private constructor(
37 | builder: Builder
38 | ) {
39 |
40 | /** duration of enter the animations. */
41 | public val enterDuration: Long = builder.enterDuration
42 |
43 | /** duration of reenter the animations. */
44 | public val reenterDuration: Long = builder.reenterDuration
45 |
46 | /** duration of exit the animations. */
47 | public val exitDuration: Long = builder.exitDuration
48 |
49 | /** duration of return the animations. */
50 | public val returnDuration: Long = builder.returnDuration
51 |
52 | /** Enter Animation of fragment. */
53 | public val enterAnimation: MetaphorAnimation = builder.enterAnimation
54 |
55 | /** Exit Animation of fragment. */
56 | public val exitAnimation: MetaphorAnimation = builder.exitAnimation
57 |
58 | /** Reenter Animation of fragment. */
59 | public val reenterAnimation: MetaphorAnimation = builder.reenterAnimation
60 |
61 | /** Return Animation of fragment. */
62 | public val returnAnimation: MetaphorAnimation = builder.returnAnimation
63 |
64 | /** Enter AnimationOverlap of fragment. */
65 | public val enterTransitionOverlap: Boolean = builder.enterTransitionOverlap
66 |
67 | /** Return AnimationOverlap of fragment. */
68 | public val returnTransitionOverlap: Boolean = builder.returnTransitionOverlap
69 |
70 | /** Motion path of on fragment animation */
71 | public val motion: PathMotion = builder.motion
72 |
73 | /** Fragment on which animation will apply */
74 | public val fragment: Fragment = builder.fragment
75 |
76 | /** start view to transform into fragment */
77 | public val view: View? = builder.view
78 |
79 | /** transitionName to transform view to another fragment */
80 | public val transitionName: String = builder.transitionName
81 |
82 | /** scrimColor while performing animation */
83 | public val scrimColor: Int = builder.scrimColor
84 |
85 | /** containerColors while performing animation */
86 | public val containerColors: Int = builder.containerColors
87 |
88 | /** Builder class for [MetaphorFragment]. */
89 | @MetaphorViewInlineDsl
90 | public class Builder(public val fragment: Fragment) {
91 |
92 | @set:JvmSynthetic
93 | public var enterDuration: Long = 300
94 |
95 | @set:JvmSynthetic
96 | public var reenterDuration: Long = 300
97 |
98 | @set:JvmSynthetic
99 | public var exitDuration: Long = 300
100 |
101 | @set:JvmSynthetic
102 | public var returnDuration: Long = 300
103 |
104 | @set:JvmSynthetic
105 | public var enterAnimation: MetaphorAnimation = MetaphorAnimation.None
106 |
107 | @set:JvmSynthetic
108 | public var exitAnimation: MetaphorAnimation = MetaphorAnimation.None
109 |
110 | @set:JvmSynthetic
111 | public var reenterAnimation: MetaphorAnimation = MetaphorAnimation.None
112 |
113 | @set:JvmSynthetic
114 | public var returnAnimation: MetaphorAnimation = MetaphorAnimation.None
115 |
116 | @set:JvmSynthetic
117 | public var enterTransitionOverlap: Boolean = false
118 |
119 | @set:JvmSynthetic
120 | public var returnTransitionOverlap: Boolean = false
121 |
122 | @set:JvmSynthetic
123 | public var motion: PathMotion = ArcMotion()
124 |
125 | @set:JvmSynthetic
126 | public var view: View? = null
127 |
128 | @set:JvmSynthetic
129 | public var transitionName: String = ""
130 |
131 | @set:JvmSynthetic
132 | public var scrimColor: Int = Color.TRANSPARENT
133 |
134 | @set:JvmSynthetic
135 | public var containerColors: Int = Color.TRANSPARENT
136 |
137 | /** sets the duration of the animation. */
138 | public fun setEnterDuration(value: Long): Builder = apply { this.enterDuration = value }
139 |
140 | /** sets the duration of the animation. */
141 | public fun setExitDuration(value: Long): Builder = apply { this.exitDuration = value }
142 |
143 | /** sets the duration of the animation. */
144 | public fun setReenterDuration(value: Long): Builder = apply { this.reenterDuration = value }
145 |
146 | /** sets the duration of the animation. */
147 | public fun setReturnDuration(value: Long): Builder = apply { this.returnDuration = value }
148 |
149 | /** sets enter the animation of the Fragment. */
150 | public fun setEnterAnimation(value: MetaphorAnimation): Builder =
151 | apply { this.enterAnimation = value }
152 |
153 | /** sets the exit animation of the Fragment. */
154 | public fun setExitAnimation(value: MetaphorAnimation): Builder =
155 | apply { this.exitAnimation = value }
156 |
157 | /** sets the return animation of the Fragment. */
158 | public fun setReturnAnimation(value: MetaphorAnimation): Builder =
159 | apply { this.returnAnimation = value }
160 |
161 | /** sets the reenter animation of the Fragment. */
162 | public fun setReenterAnimation(value: MetaphorAnimation): Builder =
163 | apply { this.reenterAnimation = value }
164 |
165 | /** sets the SetView of the Fragment. */
166 | public fun setView(value: View): Builder =
167 | apply { this.view = value }
168 |
169 | /** sets the Motion of the animation. */
170 | public fun setMotion(value: PathMotion): Builder =
171 | apply { this.motion = value }
172 |
173 | /** sets the TransitionName of the View. */
174 | public fun setTransitionName(value: String): Builder =
175 | apply { this.transitionName = value }
176 |
177 | /** sets the enter Overlap of the Fragment. */
178 | public fun setEnterOverlap(value: Boolean): Builder =
179 | apply { this.enterTransitionOverlap = value }
180 |
181 | /** sets the return Overlap of the Fragment. */
182 | public fun setReturnOverlap(value: Boolean): Builder =
183 | apply { this.returnTransitionOverlap = value }
184 |
185 | /** sets the ScrimColor of the Fragment. */
186 | public fun setScrimColor(value: Int): Builder =
187 | apply { this.scrimColor = value }
188 |
189 | /** sets the ScrimColor of the Fragment. */
190 | public fun setContainerColor(value: Int): Builder =
191 | apply { this.containerColors = value }
192 |
193 | public fun build(): MetaphorFragment = MetaphorFragment(this)
194 | }
195 |
196 | /** starts animation. */
197 | public fun animate() {
198 | fragment.applyAnimation(this)
199 | }
200 |
201 | public abstract class Factory {
202 |
203 | /**
204 | * Creates a new instance of [MetaphorFragment].
205 | *
206 | * @return A new created instance of the [MetaphorFragment].
207 | */
208 | public abstract fun create(fragment: Fragment): MetaphorFragment
209 | }
210 | }
211 |
--------------------------------------------------------------------------------