├── .github ├── CODEOWNERS ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── Bug_report.md │ └── Feature_request.md └── pull_request_template.md ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── app ├── .gitignore ├── build.gradle └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── skydoves │ │ └── elasticviewsdemo │ │ ├── ExampleActivity0.kt │ │ ├── ExampleActivity1.kt │ │ ├── ExampleActivity2.kt │ │ └── MainActivity.kt │ └── res │ ├── drawable │ ├── ic_add.png │ └── ic_question.png │ ├── layout │ ├── activity_example0.xml │ ├── activity_example1.xml │ ├── activity_example2.xml │ ├── activity_main.xml │ └── item.xml │ ├── mipmap-hdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-mdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ └── values │ ├── colors.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── dependencies.gradle ├── elasticviews ├── .gitignore ├── api │ └── elasticviews.api ├── build.gradle └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── skydoves │ │ └── elasticviews │ │ ├── Definitions.kt │ │ ├── ElasticAnimation.kt │ │ ├── ElasticButton.kt │ │ ├── ElasticCardView.kt │ │ ├── ElasticCheckButton.kt │ │ ├── ElasticExtensions.kt │ │ ├── ElasticFinishListener.kt │ │ ├── ElasticFloatingActionButton.kt │ │ ├── ElasticImageView.kt │ │ ├── ElasticInterface.kt │ │ ├── ElasticLayout.kt │ │ └── ElasticView.kt │ └── res │ └── values │ └── attrs.xml ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle ├── spotless.gradle └── spotless.license.kt /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Lines starting with '#' are comments. 2 | # Each line is a file pattern followed by one or more owners. 3 | 4 | # More details are here: https://help.github.com/articles/about-codeowners/ 5 | 6 | # The '*' pattern is global owners. 7 | # Not adding in this PR, but I'd like to try adding a global owner set with the entire team. 8 | # One interpretation of their docs is that global owners are added only if not removed 9 | # by a more local rule. 10 | 11 | # Order is important. The last matching pattern has the most precedence. 12 | # The folders are ordered as follows: 13 | 14 | # In each subsection folders are ordered first by depth, then alphabetically. 15 | # This should make it easy to add new rules without breaking existing ones. 16 | * @skydoves -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: skydoves 2 | custom: ["https://www.paypal.me/skydoves", "https://www.buymeacoffee.com/skydoves"] 3 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Something is crashing or not working as intended 4 | 5 | --- 6 | 7 | **Please complete the following information:** 8 | - Library Version [e.g. v2.0.3] 9 | - Affected Device(s) [e.g. Samsung Galaxy s10 with Android 9.0] 10 | 11 | **Describe the Bug:** 12 | 13 | Add a clear description about the problem. 14 | 15 | **Expected Behavior:** 16 | 17 | A clear description of what you expected to happen. 18 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | 5 | --- 6 | 7 | **Is your feature request related to a problem?** 8 | 9 | A clear and concise description of what the problem is. 10 | 11 | **Describe the solution you'd like:** 12 | 13 | A clear and concise description of what you want to happen. 14 | 15 | **Describe alternatives you've considered:** 16 | 17 | A clear description of any alternative solutions you've considered. 18 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Guidelines 2 | Describe the big picture of your changes here to communicate to the maintainers why we should accept this pull request. If it fixes a bug or resolves a feature request, be sure to link to that issue. 3 | 4 | ### Types of changes 5 | What types of changes does your code introduce? 6 | 7 | - [ ] Bugfix (non-breaking change which fixes an issue) 8 | - [ ] New feature (non-breaking change which adds functionality) 9 | - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) 10 | 11 | ### Preparing a pull request for review 12 | Ensure your change is properly formatted by running: 13 | 14 | ```gradle 15 | $ ./gradlew spotlessApply 16 | ``` 17 | 18 | Please correct any failures before requesting a review. -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # Files for the ART/Dalvik VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # Generated files 12 | bin/ 13 | gen/ 14 | out/ 15 | 16 | # Gradle files 17 | /.idea 18 | .gradle/ 19 | build/ 20 | 21 | # Local configuration file (sdk path, etc) 22 | local.properties 23 | 24 | # Proguard folder generated by Eclipse 25 | proguard/ 26 | 27 | # Log Files 28 | *.log 29 | 30 | # Android Studio Navigation editor temp files 31 | .navigation/ 32 | 33 | # Android Studio captures folder 34 | captures/ 35 | 36 | # Intellij 37 | *.iml 38 | .idea/workspace.xml 39 | .idea/tasks.xml 40 | .idea/gradle.xml 41 | .idea/dictionaries 42 | .idea/libraries 43 | 44 | # Mac 45 | *.DS_Store 46 | 47 | # Keystore files 48 | *.jks 49 | 50 | # External native build folder generated in Android Studio 2.2 and later 51 | .externalNativeBuild 52 | 53 | # Google Services (e.g. APIs or Firebase) 54 | google-services.json 55 | 56 | # Freeline 57 | freeline.py 58 | freeline/ 59 | freeline_project_description.json -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: android 2 | 3 | android: 4 | components: 5 | - tools 6 | - platform-tools 7 | - build-tools-29.0.0 8 | - android-29 9 | - extra-android-support 10 | - extra-android-m2repository 11 | - extra-google-m2repository 12 | 13 | jdk: 14 | - openjdk8 15 | 16 | branches: 17 | except: 18 | - gh-pages 19 | 20 | licenses: 21 | - '.+' 22 | 23 | notifications: 24 | email: false 25 | 26 | cache: 27 | directories: 28 | - $HOME/.gradle 29 | 30 | script: 31 | - chmod +x ./gradlew -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 skydoves 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ElasticViews 2 | 3 |

4 | License 5 | API 6 | Build Status 7 | Android Weekly 8 | Javadoc 9 |

10 | 11 |

12 | ✨ An easy way to implement an elastic touch effect for Android. 13 |

14 | 15 |

16 | 17 | 18 |

19 | 20 | ## Including in your project 21 | [![Maven Central](https://img.shields.io/maven-central/v/com.github.skydoves/elasticviews.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22com.github.skydoves%22%20AND%20a:%22elasticviews%22) 22 | [![Kitpack](https://jitpack.io/v/skydoves/ElasticViews.svg)](https://jitpack.io/#skydoves/ElasticViews) 23 | 24 | #### Gradle 25 | Add codes below to your **root** `build.gradle` file (not your module build.gradle file). 26 | ```gradle 27 | allprojects { 28 | repositories { 29 | mavenCentral() 30 | } 31 | } 32 | ``` 33 | And add a dependency code to your **module**'s `build.gradle` file. 34 | ```gradle 35 | dependencies { 36 | implementation "com.github.skydoves:elasticviews:2.1.0" 37 | } 38 | ``` 39 | ## SNAPSHOT 40 | [![ElasticViews](https://img.shields.io/static/v1?label=snapshot&message=elasticviews&logo=apache%20maven&color=C71A36)](https://oss.sonatype.org/content/repositories/snapshots/com/github/skydoves/elasticviews/)
41 | Snapshots of the current development version of ElasticViews are available, which track [the latest versions](https://oss.sonatype.org/content/repositories/snapshots/com/github/skydoves/elasticviews/). 42 | ```Gradle 43 | repositories { 44 | maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' } 45 | } 46 | ``` 47 | 48 | ## Usage 49 | `ElasticViews` lets we use like using normal views and gives all of the Views or GroupViews touch effect very simply. 50 | 51 | #### Add XML Namespace 52 | First add below XML Namespace inside your XML layout file. 53 | 54 | ```gradle 55 | xmlns:app="http://schemas.android.com/apk/res-auto" 56 | ``` 57 | 58 | #### OnClick Method 59 | All of ElasticViews should be set `OnClickListener` or `onClick` method. If not, nothing happens. 60 | ```java 61 | ElasticButton elasticButton = (ElasticButton)findViewById(R.id.elasticbutton); 62 | elasticButton.setOnClickListener(new View.OnClickListener() { 63 | @Override 64 | public void onClick(View v) { 65 | // do something 66 | } 67 | }); 68 | ``` 69 | 70 | ### ElasticButton 71 | ```gradle 72 | 81 | ``` 82 | 83 | ### ElasticCheckButton 84 | ```gradle 85 | 96 | ``` 97 | 98 | ### ElasticImageView 99 | ```gradle 100 | 108 | ``` 109 | 110 | ### ElasticFloatingActionButton 111 | ```gradle 112 | 120 | ``` 121 | 122 | ### ElasticCardView 123 | ```gradle 124 | 132 | 133 | ... 134 | 135 | 136 | ``` 137 | 138 | ### ElasticLayout 139 | ElasticLayout gives elastic animation to all child views. 140 | 141 | ```gradle 142 | 148 | 149 | 156 | 157 | 166 | 167 | ``` 168 | 169 | ### ElasticAnimation 170 | ElasticAnimation implements elastic animations for android views and view groups.
171 | ```java 172 | new ElasticAnimation(clickedView).setScaleX(0.9f).setScaleY(0.9f).setDuration(400) 173 | .setOnFinishListener(onFinishListener).doAction(); 174 | ``` 175 | 176 | 177 | 178 | #### ViewPropertyAnimatorListener 179 | we can set `ViewPropertyAnimatorListener` using `setListener` method and detect animation's status. 180 | ```java 181 | .setListener(new ViewPropertyAnimatorListener() { 182 | @Override 183 | public void onAnimationStart(View view) { 184 | // do something 185 | } 186 | 187 | Override 188 | public void onAnimationEnd(View view) { 189 | finishListener.onFinished(); 190 | } 191 | 192 | Override 193 | public void onAnimationCancel(View view) { 194 | // do something 195 | } 196 | }); 197 | ``` 198 | 199 | #### Kotlin Extension 200 | ElasticAnimation supports kotlin extension `elasticAnimation`. 201 | ```kotlin 202 | val anim = textView.elasticAnimation(0.8f, 0.8f, 400, object: ElasticFinishListener { 203 | override fun onFinished() { 204 | // do anything 205 | } 206 | }) 207 | anim.doAction() 208 | ``` 209 | 210 | #### Kotlin dsl 211 | ```kotlin 212 | elasticAnimation(this) { 213 | setDuration(duration) 214 | setScaleX(scale) 215 | setScaleY(scale) 216 | setOnFinishListener(object : ElasticFinishListener { 217 | override fun onFinished() { 218 | onClick() 219 | } 220 | }) 221 | }.doAction() 222 | ``` 223 | 224 | #### Example : Normal Button 225 | we can implement animation on all of the views like below. 226 | ```java 227 | @OnClick(R.id.button) 228 | public void addNewAlarm(View v){ 229 | // implements animation uising ElasticAnimation 230 | new ElasticAnimation(v).setScaleX(0.85f).setScaleY(0.85f).setDuration(500) 231 | .setOnFinishListener(new ElasticFinishListener() { 232 | @Override 233 | public void onFinished() { 234 | // Do something after duration time 235 | } 236 | }).doAction(); 237 | } 238 | } 239 | ``` 240 | 241 | #### Example : ListView Item 242 | So also we can implement animation on listView's items like below. 243 | ```java 244 | private class ListViewItemClickListener implements AdapterView.OnItemClickListener { 245 | @Override 246 | public void onItemClick(AdapterView adapterView, View clickedView, final int pos, long id) { 247 | new ElasticAnimation(clickedView).setScaleX(0.9f).setScaleY(0.9f).setDuration(400) 248 | .setOnFinishListener(new ElasticFinishListener() { 249 | @Override 250 | public void onFinished() { 251 | // Do something after duration time 252 | Toast.makeText(getBaseContext(), "ListViewItem" + pos, Toast.LENGTH_SHORT).show(); 253 | } 254 | }).doAction(); 255 | } 256 | }; 257 | ``` 258 | 259 | ## Find this library useful? :heart: 260 | Support it by joining __[stargazers](https://github.com/skydoves/ElasticViews/stargazers)__ for this repository. :star:
261 | And __[follow](https://github.com/skydoves)__ me for my next creations! 🤩 262 | 263 | # License 264 | ```xml 265 | The MIT License (MIT) 266 | 267 | Copyright (c) 2017 skydoves 268 | 269 | Permission is hereby granted, free of charge, to any person obtaining a copy 270 | of this software and associated documentation files (the "Software"), to deal 271 | in the Software without restriction, including without limitation the rights 272 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 273 | copies of the Software, and to permit persons to whom the Software is 274 | furnished to do so, subject to the following conditions: 275 | 276 | The above copyright notice and this permission notice shall be included in 277 | all copies or substantial portions of the Software. 278 | 279 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 280 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 281 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 282 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 283 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 284 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 285 | THE SOFTWARE. 286 | ``` 287 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'kotlin-android' 3 | apply from: '../dependencies.gradle' 4 | 5 | android { 6 | compileSdkVersion versions.compileSdk 7 | defaultConfig { 8 | minSdkVersion versions.minSdk 9 | targetSdkVersion versions.compileSdk 10 | versionCode versions.versionCode 11 | versionName versions.versionName 12 | } 13 | compileOptions { 14 | sourceCompatibility JavaVersion.VERSION_1_8 15 | targetCompatibility JavaVersion.VERSION_1_8 16 | } 17 | buildFeatures { 18 | viewBinding true 19 | } 20 | } 21 | 22 | dependencies { 23 | implementation "com.google.android.material:material:$versions.googleMaterial" 24 | implementation project(":elasticviews") 25 | } 26 | 27 | apply from: '../spotless.gradle' -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/skydoves/elasticviewsdemo/ExampleActivity0.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2017 skydoves 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package com.skydoves.elasticviewsdemo 25 | 26 | import android.graphics.Color 27 | import android.os.Bundle 28 | import android.view.View 29 | import android.widget.Toast 30 | import androidx.appcompat.app.AppCompatActivity 31 | import com.google.android.material.snackbar.Snackbar 32 | import com.skydoves.elasticviews.ElasticCheckButton 33 | import com.skydoves.elasticviewsdemo.databinding.ActivityExample0Binding 34 | 35 | class ExampleActivity0 : AppCompatActivity() { 36 | 37 | override fun onCreate(savedInstanceState: Bundle?) { 38 | super.onCreate(savedInstanceState) 39 | 40 | val binding = ActivityExample0Binding.inflate(layoutInflater) 41 | setContentView(binding.root) 42 | } 43 | 44 | fun checkButtons(v: View) { 45 | val elasticCheckButton = v as ElasticCheckButton 46 | Snackbar.make( 47 | v, 48 | "[Change checked state] " + 49 | elasticCheckButton.text.toString() + 50 | " : " + 51 | elasticCheckButton.isChecked, 52 | 200 53 | ) 54 | .setActionTextColor(Color.WHITE) 55 | .show() 56 | } 57 | 58 | fun layout(v: View) { 59 | Snackbar.make(v, "Pop-up likes 'TimePickerDialog'", 200).setActionTextColor(Color.WHITE).show() 60 | } 61 | 62 | fun imageViews(v: View) { 63 | when (v.id) { 64 | R.id.example0_ibtn_q_timeset01 -> 65 | Snackbar.make( 66 | v, 67 | "Alarm goes off between start-time and end-time", 200 68 | ) 69 | .setActionTextColor(Color.WHITE) 70 | .show() 71 | R.id.example0_ibtn_q_timeset02 -> 72 | Snackbar.make(v, "This is time interval description", 200) 73 | .setActionTextColor(Color.WHITE) 74 | .show() 75 | } 76 | } 77 | 78 | fun addNewAlarm(v: View) { 79 | Toast.makeText(baseContext, "a new Alarm added!", Toast.LENGTH_SHORT).show() 80 | finish() 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /app/src/main/java/com/skydoves/elasticviewsdemo/ExampleActivity1.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2017 skydoves 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package com.skydoves.elasticviewsdemo 25 | 26 | import android.annotation.SuppressLint 27 | import android.content.Context 28 | import android.os.Bundle 29 | import android.view.LayoutInflater 30 | import android.view.View 31 | import android.view.ViewGroup 32 | import android.widget.AdapterView 33 | import android.widget.BaseAdapter 34 | import android.widget.ListView 35 | import android.widget.TextView 36 | import android.widget.Toast 37 | import androidx.appcompat.app.AppCompatActivity 38 | import com.skydoves.elasticviews.ElasticAnimation 39 | import com.skydoves.elasticviewsdemo.databinding.ActivityExample1Binding 40 | import java.util.ArrayList 41 | 42 | class ExampleActivity1 : AppCompatActivity() { 43 | 44 | private val data = ArrayList() 45 | private var adapter: ListViewAdapter? = null 46 | private var listView: ListView? = null 47 | 48 | override fun onCreate(savedInstanceState: Bundle?) { 49 | super.onCreate(savedInstanceState) 50 | 51 | val binding = ActivityExample1Binding.inflate(layoutInflater) 52 | setContentView(binding.root) 53 | 54 | adapter = ListViewAdapter(this, R.layout.item, data) 55 | listView = findViewById(R.id.example1_listView) 56 | listView!!.adapter = adapter 57 | listView!!.onItemClickListener = ListViewItemClickListener() 58 | } 59 | 60 | fun floatingButtons(v: View) { 61 | val listviewitem = ListViewItem(data.size.toString() + "") 62 | data.add(listviewitem) 63 | adapter!!.notifyDataSetChanged() 64 | listView!!.setSelection(data.size - 1) 65 | } 66 | 67 | // ListView Item Touch Event 68 | private inner class ListViewItemClickListener : AdapterView.OnItemClickListener { 69 | override fun onItemClick(adapterView: AdapterView<*>, clickedView: View, pos: Int, id: Long) { 70 | ElasticAnimation(clickedView) 71 | .setScaleX(0.9f) 72 | .setScaleY(0.9f) 73 | .setDuration(400) 74 | .setOnFinishListener { 75 | // Do something after duration time 76 | Toast.makeText(baseContext, "ListViewItem$pos", Toast.LENGTH_SHORT).show() 77 | } 78 | .doAction() 79 | } 80 | } 81 | 82 | private inner class ListViewItem(val content: String) 83 | 84 | private inner class ListViewAdapter( 85 | context: Context, 86 | private val layout: Int, 87 | private val data: ArrayList 88 | ) : BaseAdapter() { 89 | 90 | private val inflater: LayoutInflater = 91 | context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater 92 | 93 | override fun getCount(): Int { 94 | return data.size 95 | } 96 | 97 | override fun getItem(position: Int): String { 98 | return data[position].content 99 | } 100 | 101 | override fun getItemId(position: Int): Long { 102 | return position.toLong() 103 | } 104 | 105 | @SuppressLint("SetTextI18n") 106 | override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { 107 | var view = convertView 108 | 109 | if (view == null) view = inflater.inflate(layout, parent, false) 110 | val listviewitem = data[position] 111 | 112 | val tv_title = view!!.findViewById(R.id.item_tv_title) 113 | tv_title.text = "ListViewItem" + listviewitem.content 114 | 115 | val tv_content = view.findViewById(R.id.item_tv_content) 116 | tv_content.text = "This is ListViewItem" + listviewitem.content + "'s content" 117 | 118 | return view 119 | } 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /app/src/main/java/com/skydoves/elasticviewsdemo/ExampleActivity2.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2017 skydoves 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package com.skydoves.elasticviewsdemo 25 | 26 | import android.graphics.Color 27 | import android.os.Bundle 28 | import android.view.View 29 | import androidx.appcompat.app.AppCompatActivity 30 | import com.google.android.material.snackbar.Snackbar 31 | import com.skydoves.elasticviews.ElasticAnimation 32 | import com.skydoves.elasticviewsdemo.databinding.ActivityExample2Binding 33 | 34 | class ExampleActivity2 : AppCompatActivity() { 35 | 36 | override fun onCreate(savedInstanceState: Bundle?) { 37 | super.onCreate(savedInstanceState) 38 | 39 | val binding = ActivityExample2Binding.inflate(layoutInflater) 40 | setContentView(binding.root) 41 | } 42 | 43 | fun views(v: View) { 44 | when (v.id) { 45 | R.id.example2_view3 -> 46 | ElasticAnimation(v) 47 | .setScaleX(0.85f) 48 | .setScaleY(0.85f) 49 | .setDuration(500) 50 | .setOnFinishListener { 51 | // Do something after duration time 52 | } 53 | .doAction() 54 | R.id.example2_imv -> Snackbar.make(v, "This is ElasticImageView", 200).setActionTextColor( 55 | Color.WHITE 56 | ).show() 57 | R.id.example2_textView0 -> ElasticAnimation(v).setScaleX(0.75f).setScaleY(0.75f).setDuration( 58 | 500 59 | ).doAction() 60 | R.id.example2_fab -> 61 | Snackbar.make(v, "This is ElasticFloatActionButton", 200) 62 | .setActionTextColor(Color.WHITE) 63 | .show() 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /app/src/main/java/com/skydoves/elasticviewsdemo/MainActivity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2017 skydoves 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package com.skydoves.elasticviewsdemo 25 | 26 | import android.content.Intent 27 | import android.os.Bundle 28 | import android.view.View 29 | import androidx.appcompat.app.AppCompatActivity 30 | import com.skydoves.elasticviewsdemo.databinding.ActivityMainBinding 31 | 32 | class MainActivity : AppCompatActivity() { 33 | 34 | override fun onCreate(savedInstanceState: Bundle?) { 35 | super.onCreate(savedInstanceState) 36 | 37 | val binding = ActivityMainBinding.inflate(layoutInflater) 38 | setContentView(binding.root) 39 | } 40 | 41 | fun buttons(v: View) { 42 | when (v.id) { 43 | R.id.elasticbtn0 -> startActivity(Intent(baseContext, ExampleActivity0::class.java)) 44 | R.id.elasticbtn1 -> startActivity(Intent(baseContext, ExampleActivity1::class.java)) 45 | R.id.elasticbtn2 -> startActivity(Intent(baseContext, ExampleActivity2::class.java)) 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skydoves/ElasticViews/752955421fcd12addd59a4e3dd817b2336cebba5/app/src/main/res/drawable/ic_add.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_question.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skydoves/ElasticViews/752955421fcd12addd59a4e3dd817b2336cebba5/app/src/main/res/drawable/ic_question.png -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_example0.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 17 | 18 | 19 | 26 | 27 | 40 | 41 | 47 | 48 | 53 | 54 | 66 | 67 | 79 | 80 | 92 | 93 | 105 | 106 | 118 | 119 | 131 | 132 | 144 | 145 | 146 | 147 | 148 | 149 | 157 | 158 | 161 | 162 | 174 | 175 | 186 | 187 | 188 | 189 | 198 | 199 | 202 | 203 | 215 | 216 | 229 | 230 | 231 | 232 | 242 | 243 | 246 | 247 | 259 | 260 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 288 | 289 | 301 | 302 | 313 | 314 | 324 | 325 | 328 | 329 | 341 | 342 | 355 | 356 | 357 | 358 | 359 | 360 | 365 | 366 | 381 | 382 | 383 | 384 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_example1.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 17 | 18 | 32 | 33 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_example2.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 14 | 15 | 26 | 27 | 34 | 35 | 36 | 37 | 49 | 50 | 63 | 64 | 74 | 75 | 78 | 79 | 90 | 91 | 103 | 104 | 105 | 106 | 113 | 114 | 125 | 126 | 138 | 139 | 140 | 141 | 145 | 146 | 157 | 158 | 168 | 169 | 184 | 185 | 186 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 14 | 15 | 26 | 27 | 39 | 40 | 49 | 50 | 51 | 52 | 66 | 67 | 82 | 83 | 97 | 98 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 15 | 16 | 29 | 30 | 40 | 41 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skydoves/ElasticViews/752955421fcd12addd59a4e3dd817b2336cebba5/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skydoves/ElasticViews/752955421fcd12addd59a4e3dd817b2336cebba5/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skydoves/ElasticViews/752955421fcd12addd59a4e3dd817b2336cebba5/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skydoves/ElasticViews/752955421fcd12addd59a4e3dd817b2336cebba5/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skydoves/ElasticViews/752955421fcd12addd59a4e3dd817b2336cebba5/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skydoves/ElasticViews/752955421fcd12addd59a4e3dd817b2336cebba5/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skydoves/ElasticViews/752955421fcd12addd59a4e3dd817b2336cebba5/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skydoves/ElasticViews/752955421fcd12addd59a4e3dd817b2336cebba5/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skydoves/ElasticViews/752955421fcd12addd59a4e3dd817b2336cebba5/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skydoves/ElasticViews/752955421fcd12addd59a4e3dd817b2336cebba5/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #C51162 4 | #AD1457 5 | #C51162 6 | #2B292B 7 | #424242 8 | #212121 9 | #8effffff 10 | #b2ffffff 11 | #ddffffff 12 | #edf8f8f8 13 | #ffffffff 14 | #57A8D8 15 | #FBC02D 16 | #FFD600 17 | #FBC02D 18 | #FFA000 19 | #FFA726 20 | #FF6D00 21 | #81C784 22 | #388E3C 23 | #81D4fA 24 | #0091EA 25 | #AA00FF 26 | #7200CA 27 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | ElasticViews 3 | ExampleActivity0 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | apply from: './dependencies.gradle' 3 | repositories { 4 | google() 5 | mavenCentral() 6 | } 7 | dependencies { 8 | classpath "com.android.tools.build:gradle:$versions.gradleBuildTool" 9 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$versions.kotlin" 10 | classpath "com.diffplug.spotless:spotless-plugin-gradle:$versions.spotlessGradle" 11 | classpath "com.vanniktech:gradle-maven-publish-plugin:$versions.mavenPublish" 12 | classpath "org.jetbrains.dokka:dokka-gradle-plugin:$versions.dokkaGradle" 13 | classpath "org.jetbrains.kotlinx:binary-compatibility-validator:$versions.binaryValidator" 14 | } 15 | } 16 | 17 | allprojects { 18 | repositories { 19 | google() 20 | mavenCentral() 21 | } 22 | } 23 | 24 | task clean(type: Delete) { 25 | delete rootProject.buildDir 26 | } 27 | -------------------------------------------------------------------------------- /dependencies.gradle: -------------------------------------------------------------------------------- 1 | ext.versions = [ 2 | minSdk : 16, 3 | compileSdk : 30, 4 | versionCode : 24, 5 | versionName : '2.1.0', 6 | 7 | gradleBuildTool: '4.1.3', 8 | spotlessGradle : '5.14.0', 9 | ktlintGradle : '0.41.0', 10 | dokkaGradle : '1.4.32', 11 | binaryValidator : '0.7.1', 12 | mavenPublish : '0.15.1', 13 | 14 | kotlin : '1.4.32', 15 | googleMaterial : '1.3.0-alpha02' 16 | ] 17 | -------------------------------------------------------------------------------- /elasticviews/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /elasticviews/api/elasticviews.api: -------------------------------------------------------------------------------- 1 | public final class com/skydoves/elasticviews/ElasticAnimation { 2 | public field duration I 3 | public field finishListener Lcom/skydoves/elasticviews/ElasticFinishListener; 4 | public field listener Landroidx/core/view/ViewPropertyAnimatorListener; 5 | public field scaleX F 6 | public field scaleY F 7 | public fun (Landroid/view/View;)V 8 | public final fun doAction ()V 9 | public final fun isAnimating ()Z 10 | public final fun setDuration (I)Lcom/skydoves/elasticviews/ElasticAnimation; 11 | public final fun setListener (Landroidx/core/view/ViewPropertyAnimatorListener;)Lcom/skydoves/elasticviews/ElasticAnimation; 12 | public final fun setOnFinishListener (Lcom/skydoves/elasticviews/ElasticFinishListener;)Lcom/skydoves/elasticviews/ElasticAnimation; 13 | public final synthetic fun setOnFinishListener (Lkotlin/jvm/functions/Function0;)Lcom/skydoves/elasticviews/ElasticAnimation; 14 | public final fun setScaleX (F)Lcom/skydoves/elasticviews/ElasticAnimation; 15 | public final fun setScaleY (F)Lcom/skydoves/elasticviews/ElasticAnimation; 16 | } 17 | 18 | public final class com/skydoves/elasticviews/ElasticButton : androidx/appcompat/widget/AppCompatButton, com/skydoves/elasticviews/ElasticInterface { 19 | public fun (Landroid/content/Context;)V 20 | public fun (Landroid/content/Context;Landroid/util/AttributeSet;)V 21 | public fun (Landroid/content/Context;Landroid/util/AttributeSet;I)V 22 | public synthetic fun (Landroid/content/Context;Landroid/util/AttributeSet;IILkotlin/jvm/internal/DefaultConstructorMarker;)V 23 | public final fun getCornerRadius ()F 24 | public final fun getDuration ()I 25 | public final fun getScale ()F 26 | public final fun setCornerRadius (F)V 27 | public final fun setDuration (I)V 28 | public fun setOnClickListener (Landroid/view/View$OnClickListener;)V 29 | public fun setOnClickListener (Lkotlin/jvm/functions/Function1;)V 30 | public fun setOnFinishListener (Lcom/skydoves/elasticviews/ElasticFinishListener;)V 31 | public fun setOnFinishListener (Lkotlin/jvm/functions/Function0;)V 32 | public final fun setScale (F)V 33 | } 34 | 35 | public final class com/skydoves/elasticviews/ElasticButton$Builder { 36 | public fun (Landroid/content/Context;)V 37 | public final fun build ()Lcom/skydoves/elasticviews/ElasticButton; 38 | public final fun setCornerRadius (F)Lcom/skydoves/elasticviews/ElasticButton$Builder; 39 | public final fun setDuration (I)Lcom/skydoves/elasticviews/ElasticButton$Builder; 40 | public final fun setOnClickListener (Landroid/view/View$OnClickListener;)Lcom/skydoves/elasticviews/ElasticButton$Builder; 41 | public final synthetic fun setOnClickListener (Lkotlin/jvm/functions/Function1;)Lcom/skydoves/elasticviews/ElasticButton$Builder; 42 | public final fun setOnFinishListener (Lcom/skydoves/elasticviews/ElasticFinishListener;)Lcom/skydoves/elasticviews/ElasticButton$Builder; 43 | public final synthetic fun setOnFinishListener (Lkotlin/jvm/functions/Function0;)Lcom/skydoves/elasticviews/ElasticButton$Builder; 44 | public final fun setScale (F)Lcom/skydoves/elasticviews/ElasticButton$Builder; 45 | } 46 | 47 | public final class com/skydoves/elasticviews/ElasticButton$sam$i$android_view_View_OnClickListener$0 : android/view/View$OnClickListener { 48 | public fun (Lkotlin/jvm/functions/Function1;)V 49 | public final synthetic fun onClick (Landroid/view/View;)V 50 | } 51 | 52 | public final class com/skydoves/elasticviews/ElasticButton$sam$i$com_skydoves_elasticviews_ElasticFinishListener$0 : com/skydoves/elasticviews/ElasticFinishListener, kotlin/jvm/internal/FunctionAdapter { 53 | public fun (Lkotlin/jvm/functions/Function0;)V 54 | public fun equals (Ljava/lang/Object;)Z 55 | public fun getFunctionDelegate ()Lkotlin/Function; 56 | public fun hashCode ()I 57 | public final synthetic fun onFinished ()V 58 | } 59 | 60 | public final class com/skydoves/elasticviews/ElasticCardView : androidx/cardview/widget/CardView, com/skydoves/elasticviews/ElasticInterface { 61 | public fun (Landroid/content/Context;)V 62 | public fun (Landroid/content/Context;Landroid/util/AttributeSet;)V 63 | public fun (Landroid/content/Context;Landroid/util/AttributeSet;I)V 64 | public synthetic fun (Landroid/content/Context;Landroid/util/AttributeSet;IILkotlin/jvm/internal/DefaultConstructorMarker;)V 65 | public final fun getDuration ()I 66 | public final fun getScale ()F 67 | public final fun setDuration (I)V 68 | public fun setOnClickListener (Landroid/view/View$OnClickListener;)V 69 | public fun setOnClickListener (Lkotlin/jvm/functions/Function1;)V 70 | public fun setOnFinishListener (Lcom/skydoves/elasticviews/ElasticFinishListener;)V 71 | public fun setOnFinishListener (Lkotlin/jvm/functions/Function0;)V 72 | public final fun setScale (F)V 73 | } 74 | 75 | public final class com/skydoves/elasticviews/ElasticCardView$Builder { 76 | public fun (Landroid/content/Context;)V 77 | public final fun build ()Lcom/skydoves/elasticviews/ElasticCardView; 78 | public final fun setDuration (I)Lcom/skydoves/elasticviews/ElasticCardView$Builder; 79 | public final fun setOnClickListener (Landroid/view/View$OnClickListener;)Lcom/skydoves/elasticviews/ElasticCardView$Builder; 80 | public final synthetic fun setOnClickListener (Lkotlin/jvm/functions/Function1;)Lcom/skydoves/elasticviews/ElasticCardView$Builder; 81 | public final fun setOnFinishListener (Lcom/skydoves/elasticviews/ElasticFinishListener;)Lcom/skydoves/elasticviews/ElasticCardView$Builder; 82 | public final synthetic fun setOnFinishListener (Lkotlin/jvm/functions/Function0;)Lcom/skydoves/elasticviews/ElasticCardView$Builder; 83 | public final fun setScale (F)Lcom/skydoves/elasticviews/ElasticCardView$Builder; 84 | } 85 | 86 | public final class com/skydoves/elasticviews/ElasticCardView$sam$i$android_view_View_OnClickListener$0 : android/view/View$OnClickListener { 87 | public fun (Lkotlin/jvm/functions/Function1;)V 88 | public final synthetic fun onClick (Landroid/view/View;)V 89 | } 90 | 91 | public final class com/skydoves/elasticviews/ElasticCardView$sam$i$com_skydoves_elasticviews_ElasticFinishListener$0 : com/skydoves/elasticviews/ElasticFinishListener, kotlin/jvm/internal/FunctionAdapter { 92 | public fun (Lkotlin/jvm/functions/Function0;)V 93 | public fun equals (Ljava/lang/Object;)Z 94 | public fun getFunctionDelegate ()Lkotlin/Function; 95 | public fun hashCode ()I 96 | public final synthetic fun onFinished ()V 97 | } 98 | 99 | public final class com/skydoves/elasticviews/ElasticCheckButton : androidx/appcompat/widget/AppCompatButton, com/skydoves/elasticviews/ElasticInterface { 100 | public fun (Landroid/content/Context;)V 101 | public fun (Landroid/content/Context;Landroid/util/AttributeSet;)V 102 | public fun (Landroid/content/Context;Landroid/util/AttributeSet;I)V 103 | public synthetic fun (Landroid/content/Context;Landroid/util/AttributeSet;IILkotlin/jvm/internal/DefaultConstructorMarker;)V 104 | public final fun getCheckedAlpha ()F 105 | public final fun getCornerRadius ()F 106 | public final fun getDuration ()I 107 | public final fun getScale ()F 108 | public final fun isChecked ()Z 109 | public final fun setChecked (Z)V 110 | public final fun setCheckedAlpha (F)V 111 | public final fun setCornerRadius (F)V 112 | public final fun setDuration (I)V 113 | public fun setOnClickListener (Landroid/view/View$OnClickListener;)V 114 | public fun setOnClickListener (Lkotlin/jvm/functions/Function1;)V 115 | public fun setOnFinishListener (Lcom/skydoves/elasticviews/ElasticFinishListener;)V 116 | public fun setOnFinishListener (Lkotlin/jvm/functions/Function0;)V 117 | public final fun setScale (F)V 118 | } 119 | 120 | public final class com/skydoves/elasticviews/ElasticCheckButton$Builder { 121 | public fun (Landroid/content/Context;)V 122 | public final fun build ()Lcom/skydoves/elasticviews/ElasticCheckButton; 123 | public final fun setCornerRadius (F)Lcom/skydoves/elasticviews/ElasticCheckButton$Builder; 124 | public final fun setDuration (I)Lcom/skydoves/elasticviews/ElasticCheckButton$Builder; 125 | public final fun setOnClickListener (Landroid/view/View$OnClickListener;)Lcom/skydoves/elasticviews/ElasticCheckButton$Builder; 126 | public final synthetic fun setOnClickListener (Lkotlin/jvm/functions/Function1;)Lcom/skydoves/elasticviews/ElasticCheckButton$Builder; 127 | public final fun setOnFinishListener (Lcom/skydoves/elasticviews/ElasticFinishListener;)Lcom/skydoves/elasticviews/ElasticCheckButton$Builder; 128 | public final synthetic fun setOnFinishListener (Lkotlin/jvm/functions/Function0;)Lcom/skydoves/elasticviews/ElasticCheckButton$Builder; 129 | public final fun setScale (F)Lcom/skydoves/elasticviews/ElasticCheckButton$Builder; 130 | } 131 | 132 | public final class com/skydoves/elasticviews/ElasticCheckButton$sam$i$android_view_View_OnClickListener$0 : android/view/View$OnClickListener { 133 | public fun (Lkotlin/jvm/functions/Function1;)V 134 | public final synthetic fun onClick (Landroid/view/View;)V 135 | } 136 | 137 | public final class com/skydoves/elasticviews/ElasticCheckButton$sam$i$com_skydoves_elasticviews_ElasticFinishListener$0 : com/skydoves/elasticviews/ElasticFinishListener, kotlin/jvm/internal/FunctionAdapter { 138 | public fun (Lkotlin/jvm/functions/Function0;)V 139 | public fun equals (Ljava/lang/Object;)Z 140 | public fun getFunctionDelegate ()Lkotlin/Function; 141 | public fun hashCode ()I 142 | public final synthetic fun onFinished ()V 143 | } 144 | 145 | public final class com/skydoves/elasticviews/ElasticExtensions { 146 | public static final fun elasticAnimation (Landroid/view/View;)Lcom/skydoves/elasticviews/ElasticAnimation; 147 | public static final fun elasticAnimation (Landroid/view/View;F)Lcom/skydoves/elasticviews/ElasticAnimation; 148 | public static final fun elasticAnimation (Landroid/view/View;FF)Lcom/skydoves/elasticviews/ElasticAnimation; 149 | public static final fun elasticAnimation (Landroid/view/View;FFI)Lcom/skydoves/elasticviews/ElasticAnimation; 150 | public static final synthetic fun elasticAnimation (Landroid/view/View;FFILcom/skydoves/elasticviews/ElasticFinishListener;)Lcom/skydoves/elasticviews/ElasticAnimation; 151 | public static final synthetic fun elasticAnimation (Landroid/view/View;FFILkotlin/jvm/functions/Function0;)Lcom/skydoves/elasticviews/ElasticAnimation; 152 | public static final fun elasticAnimation (Landroid/view/View;FFLkotlin/jvm/functions/Function0;)Lcom/skydoves/elasticviews/ElasticAnimation; 153 | public static final fun elasticAnimation (Landroid/view/View;FLkotlin/jvm/functions/Function0;)Lcom/skydoves/elasticviews/ElasticAnimation; 154 | public static final fun elasticAnimation (Landroid/view/View;Lkotlin/jvm/functions/Function0;)Lcom/skydoves/elasticviews/ElasticAnimation; 155 | public static final synthetic fun elasticAnimation (Landroid/view/View;Lkotlin/jvm/functions/Function1;)Lcom/skydoves/elasticviews/ElasticAnimation; 156 | public static synthetic fun elasticAnimation$default (Landroid/view/View;FFILcom/skydoves/elasticviews/ElasticFinishListener;ILjava/lang/Object;)Lcom/skydoves/elasticviews/ElasticAnimation; 157 | public static synthetic fun elasticAnimation$default (Landroid/view/View;FFILkotlin/jvm/functions/Function0;ILjava/lang/Object;)Lcom/skydoves/elasticviews/ElasticAnimation; 158 | } 159 | 160 | public abstract interface class com/skydoves/elasticviews/ElasticFinishListener { 161 | public abstract fun onFinished ()V 162 | } 163 | 164 | public final class com/skydoves/elasticviews/ElasticFloatingActionButton : com/google/android/material/floatingactionbutton/FloatingActionButton, com/skydoves/elasticviews/ElasticInterface { 165 | public fun (Landroid/content/Context;)V 166 | public fun (Landroid/content/Context;Landroid/util/AttributeSet;)V 167 | public fun (Landroid/content/Context;Landroid/util/AttributeSet;I)V 168 | public synthetic fun (Landroid/content/Context;Landroid/util/AttributeSet;IILkotlin/jvm/internal/DefaultConstructorMarker;)V 169 | public final fun getDuration ()I 170 | public final fun getScale ()F 171 | public final fun setDuration (I)V 172 | public fun setOnClickListener (Landroid/view/View$OnClickListener;)V 173 | public fun setOnClickListener (Lkotlin/jvm/functions/Function1;)V 174 | public fun setOnFinishListener (Lcom/skydoves/elasticviews/ElasticFinishListener;)V 175 | public fun setOnFinishListener (Lkotlin/jvm/functions/Function0;)V 176 | public final fun setScale (F)V 177 | } 178 | 179 | public final class com/skydoves/elasticviews/ElasticFloatingActionButton$Builder { 180 | public fun (Landroid/content/Context;)V 181 | public final fun build ()Lcom/skydoves/elasticviews/ElasticFloatingActionButton; 182 | public final fun setDuration (I)Lcom/skydoves/elasticviews/ElasticFloatingActionButton$Builder; 183 | public final fun setOnClickListener (Landroid/view/View$OnClickListener;)Lcom/skydoves/elasticviews/ElasticFloatingActionButton$Builder; 184 | public final synthetic fun setOnClickListener (Lkotlin/jvm/functions/Function1;)Lcom/skydoves/elasticviews/ElasticFloatingActionButton$Builder; 185 | public final fun setOnFinishListener (Lcom/skydoves/elasticviews/ElasticFinishListener;)Lcom/skydoves/elasticviews/ElasticFloatingActionButton$Builder; 186 | public final synthetic fun setOnFinishListener (Lkotlin/jvm/functions/Function0;)Lcom/skydoves/elasticviews/ElasticFloatingActionButton$Builder; 187 | public final fun setScale (F)Lcom/skydoves/elasticviews/ElasticFloatingActionButton$Builder; 188 | } 189 | 190 | public final class com/skydoves/elasticviews/ElasticFloatingActionButton$sam$i$android_view_View_OnClickListener$0 : android/view/View$OnClickListener { 191 | public fun (Lkotlin/jvm/functions/Function1;)V 192 | public final synthetic fun onClick (Landroid/view/View;)V 193 | } 194 | 195 | public final class com/skydoves/elasticviews/ElasticFloatingActionButton$sam$i$com_skydoves_elasticviews_ElasticFinishListener$0 : com/skydoves/elasticviews/ElasticFinishListener, kotlin/jvm/internal/FunctionAdapter { 196 | public fun (Lkotlin/jvm/functions/Function0;)V 197 | public fun equals (Ljava/lang/Object;)Z 198 | public fun getFunctionDelegate ()Lkotlin/Function; 199 | public fun hashCode ()I 200 | public final synthetic fun onFinished ()V 201 | } 202 | 203 | public final class com/skydoves/elasticviews/ElasticImageView : androidx/appcompat/widget/AppCompatImageView, com/skydoves/elasticviews/ElasticInterface { 204 | public fun (Landroid/content/Context;)V 205 | public fun (Landroid/content/Context;Landroid/util/AttributeSet;)V 206 | public fun (Landroid/content/Context;Landroid/util/AttributeSet;I)V 207 | public synthetic fun (Landroid/content/Context;Landroid/util/AttributeSet;IILkotlin/jvm/internal/DefaultConstructorMarker;)V 208 | public final fun getDuration ()I 209 | public final fun getScale ()F 210 | public final fun setDuration (I)V 211 | public fun setOnClickListener (Landroid/view/View$OnClickListener;)V 212 | public fun setOnClickListener (Lkotlin/jvm/functions/Function1;)V 213 | public fun setOnFinishListener (Lcom/skydoves/elasticviews/ElasticFinishListener;)V 214 | public fun setOnFinishListener (Lkotlin/jvm/functions/Function0;)V 215 | public final fun setScale (F)V 216 | } 217 | 218 | public final class com/skydoves/elasticviews/ElasticImageView$Builder { 219 | public fun (Landroid/content/Context;)V 220 | public final fun build ()Lcom/skydoves/elasticviews/ElasticImageView; 221 | public final fun setDuration (I)Lcom/skydoves/elasticviews/ElasticImageView$Builder; 222 | public final fun setOnClickListener (Landroid/view/View$OnClickListener;)Lcom/skydoves/elasticviews/ElasticImageView$Builder; 223 | public final synthetic fun setOnClickListener (Lkotlin/jvm/functions/Function1;)Lcom/skydoves/elasticviews/ElasticImageView$Builder; 224 | public final fun setOnFinishListener (Lcom/skydoves/elasticviews/ElasticFinishListener;)Lcom/skydoves/elasticviews/ElasticImageView$Builder; 225 | public final synthetic fun setOnFinishListener (Lkotlin/jvm/functions/Function0;)Lcom/skydoves/elasticviews/ElasticImageView$Builder; 226 | public final fun setScale (F)Lcom/skydoves/elasticviews/ElasticImageView$Builder; 227 | } 228 | 229 | public final class com/skydoves/elasticviews/ElasticImageView$sam$i$android_view_View_OnClickListener$0 : android/view/View$OnClickListener { 230 | public fun (Lkotlin/jvm/functions/Function1;)V 231 | public final synthetic fun onClick (Landroid/view/View;)V 232 | } 233 | 234 | public final class com/skydoves/elasticviews/ElasticImageView$sam$i$com_skydoves_elasticviews_ElasticFinishListener$0 : com/skydoves/elasticviews/ElasticFinishListener, kotlin/jvm/internal/FunctionAdapter { 235 | public fun (Lkotlin/jvm/functions/Function0;)V 236 | public fun equals (Ljava/lang/Object;)Z 237 | public fun getFunctionDelegate ()Lkotlin/Function; 238 | public fun hashCode ()I 239 | public final synthetic fun onFinished ()V 240 | } 241 | 242 | public final class com/skydoves/elasticviews/ElasticLayout : android/widget/FrameLayout, com/skydoves/elasticviews/ElasticInterface { 243 | public fun (Landroid/content/Context;)V 244 | public fun (Landroid/content/Context;Landroid/util/AttributeSet;)V 245 | public fun (Landroid/content/Context;Landroid/util/AttributeSet;I)V 246 | public synthetic fun (Landroid/content/Context;Landroid/util/AttributeSet;IILkotlin/jvm/internal/DefaultConstructorMarker;)V 247 | public final fun getCornerRadius ()F 248 | public final fun getDuration ()I 249 | public final fun getScale ()F 250 | public final fun setCornerRadius (F)V 251 | public final fun setDuration (I)V 252 | public fun setOnClickListener (Landroid/view/View$OnClickListener;)V 253 | public fun setOnClickListener (Lkotlin/jvm/functions/Function1;)V 254 | public fun setOnFinishListener (Lcom/skydoves/elasticviews/ElasticFinishListener;)V 255 | public fun setOnFinishListener (Lkotlin/jvm/functions/Function0;)V 256 | public final fun setScale (F)V 257 | } 258 | 259 | public final class com/skydoves/elasticviews/ElasticLayout$Builder { 260 | public fun (Landroid/content/Context;)V 261 | public final fun build ()Lcom/skydoves/elasticviews/ElasticLayout; 262 | public final fun setCornerRadius (F)Lcom/skydoves/elasticviews/ElasticLayout$Builder; 263 | public final fun setDuration (I)Lcom/skydoves/elasticviews/ElasticLayout$Builder; 264 | public final fun setOnClickListener (Landroid/view/View$OnClickListener;)Lcom/skydoves/elasticviews/ElasticLayout$Builder; 265 | public final synthetic fun setOnClickListener (Lkotlin/jvm/functions/Function1;)Lcom/skydoves/elasticviews/ElasticLayout$Builder; 266 | public final fun setOnFinishListener (Lcom/skydoves/elasticviews/ElasticFinishListener;)Lcom/skydoves/elasticviews/ElasticLayout$Builder; 267 | public final synthetic fun setOnFinishListener (Lkotlin/jvm/functions/Function0;)Lcom/skydoves/elasticviews/ElasticLayout$Builder; 268 | public final fun setScale (F)Lcom/skydoves/elasticviews/ElasticLayout$Builder; 269 | } 270 | 271 | public final class com/skydoves/elasticviews/ElasticLayout$sam$i$android_view_View_OnClickListener$0 : android/view/View$OnClickListener { 272 | public fun (Lkotlin/jvm/functions/Function1;)V 273 | public final synthetic fun onClick (Landroid/view/View;)V 274 | } 275 | 276 | public final class com/skydoves/elasticviews/ElasticLayout$sam$i$com_skydoves_elasticviews_ElasticFinishListener$0 : com/skydoves/elasticviews/ElasticFinishListener, kotlin/jvm/internal/FunctionAdapter { 277 | public fun (Lkotlin/jvm/functions/Function0;)V 278 | public fun equals (Ljava/lang/Object;)Z 279 | public fun getFunctionDelegate ()Lkotlin/Function; 280 | public fun hashCode ()I 281 | public final synthetic fun onFinished ()V 282 | } 283 | 284 | public final class com/skydoves/elasticviews/ElasticView : android/view/View, com/skydoves/elasticviews/ElasticInterface { 285 | public fun (Landroid/content/Context;)V 286 | public fun (Landroid/content/Context;Landroid/util/AttributeSet;)V 287 | public fun (Landroid/content/Context;Landroid/util/AttributeSet;I)V 288 | public synthetic fun (Landroid/content/Context;Landroid/util/AttributeSet;IILkotlin/jvm/internal/DefaultConstructorMarker;)V 289 | public final fun getCornerRadius ()F 290 | public final fun getDuration ()I 291 | public final fun getScale ()F 292 | public final fun setCornerRadius (F)V 293 | public final fun setDuration (I)V 294 | public fun setOnClickListener (Landroid/view/View$OnClickListener;)V 295 | public fun setOnClickListener (Lkotlin/jvm/functions/Function1;)V 296 | public fun setOnFinishListener (Lcom/skydoves/elasticviews/ElasticFinishListener;)V 297 | public fun setOnFinishListener (Lkotlin/jvm/functions/Function0;)V 298 | public final fun setScale (F)V 299 | } 300 | 301 | public final class com/skydoves/elasticviews/ElasticView$Builder { 302 | public fun (Landroid/content/Context;)V 303 | public final fun build ()Lcom/skydoves/elasticviews/ElasticView; 304 | public final fun setCornerRadius (F)Lcom/skydoves/elasticviews/ElasticView$Builder; 305 | public final fun setDuration (I)Lcom/skydoves/elasticviews/ElasticView$Builder; 306 | public final fun setOnClickListener (Landroid/view/View$OnClickListener;)Lcom/skydoves/elasticviews/ElasticView$Builder; 307 | public final synthetic fun setOnClickListener (Lkotlin/jvm/functions/Function1;)Lcom/skydoves/elasticviews/ElasticView$Builder; 308 | public final fun setOnFinishListener (Lcom/skydoves/elasticviews/ElasticFinishListener;)Lcom/skydoves/elasticviews/ElasticView$Builder; 309 | public final synthetic fun setOnFinishListener (Lkotlin/jvm/functions/Function0;)Lcom/skydoves/elasticviews/ElasticView$Builder; 310 | public final fun setScale (F)Lcom/skydoves/elasticviews/ElasticView$Builder; 311 | } 312 | 313 | public final class com/skydoves/elasticviews/ElasticView$sam$i$android_view_View_OnClickListener$0 : android/view/View$OnClickListener { 314 | public fun (Lkotlin/jvm/functions/Function1;)V 315 | public final synthetic fun onClick (Landroid/view/View;)V 316 | } 317 | 318 | public final class com/skydoves/elasticviews/ElasticView$sam$i$com_skydoves_elasticviews_ElasticFinishListener$0 : com/skydoves/elasticviews/ElasticFinishListener, kotlin/jvm/internal/FunctionAdapter { 319 | public fun (Lkotlin/jvm/functions/Function0;)V 320 | public fun equals (Ljava/lang/Object;)Z 321 | public fun getFunctionDelegate ()Lkotlin/Function; 322 | public fun hashCode ()I 323 | public final synthetic fun onFinished ()V 324 | } 325 | 326 | -------------------------------------------------------------------------------- /elasticviews/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'kotlin-android' 3 | apply plugin: 'org.jetbrains.dokka' 4 | apply plugin: 'binary-compatibility-validator' 5 | apply from: '../dependencies.gradle' 6 | 7 | android { 8 | compileSdkVersion versions.compileSdk 9 | defaultConfig { 10 | minSdkVersion versions.minSdk 11 | targetSdkVersion versions.compileSdk 12 | versionCode versions.versionCode 13 | versionName versions.versionName 14 | } 15 | buildFeatures { 16 | buildConfig false 17 | } 18 | } 19 | 20 | kotlin { 21 | explicitApiWarning() 22 | } 23 | 24 | apiValidation { 25 | ignoredPackages += [ 26 | "com/skydoves/elasticviews/databinding", 27 | ] 28 | nonPublicMarkers += [ 29 | "kotlin.PublishedApi", 30 | ] 31 | } 32 | 33 | dependencies { 34 | implementation "com.google.android.material:material:$versions.googleMaterial" 35 | } 36 | 37 | apply plugin: "com.vanniktech.maven.publish" 38 | apply from: '../spotless.gradle' -------------------------------------------------------------------------------- /elasticviews/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /elasticviews/src/main/java/com/skydoves/elasticviews/Definitions.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2017 skydoves 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package com.skydoves.elasticviews 25 | 26 | @PublishedApi 27 | internal object Definitions { 28 | /** The default target elastic scale size of the animation. */ 29 | const val DEFAULT_SCALE: Float = 0.9f 30 | 31 | /** The default target elastic scale-x size of the animation. */ 32 | const val DEFAULT_SCALE_X: Float = 0.85f 33 | 34 | /** The default target elastic scale-y size of the animation. */ 35 | const val DEFAULT_SCALE_Y: Float = 0.85f 36 | 37 | /** The default duration of the animation. */ 38 | const val DEFAULT_DURATION: Int = 400 39 | 40 | /** The default anchor of the elastic animation. */ 41 | const val DEFAULT_ANIMATION_ANCHOR = 0.5f 42 | } 43 | -------------------------------------------------------------------------------- /elasticviews/src/main/java/com/skydoves/elasticviews/ElasticAnimation.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2017 skydoves 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | @file:Suppress("unused") 25 | 26 | package com.skydoves.elasticviews 27 | 28 | import android.view.View 29 | import android.view.ViewGroup 30 | import android.view.animation.CycleInterpolator 31 | import androidx.core.view.ViewCompat 32 | import androidx.core.view.ViewPropertyAnimatorListener 33 | import com.skydoves.elasticviews.Definitions.DEFAULT_ANIMATION_ANCHOR 34 | import com.skydoves.elasticviews.Definitions.DEFAULT_DURATION 35 | import com.skydoves.elasticviews.Definitions.DEFAULT_SCALE_X 36 | import com.skydoves.elasticviews.Definitions.DEFAULT_SCALE_Y 37 | 38 | /** ElasticAnimation implements elastic animations for android views or view groups. */ 39 | class ElasticAnimation(private val view: View) { 40 | 41 | @JvmField 42 | @set:JvmSynthetic 43 | var scaleX = DEFAULT_SCALE_X 44 | 45 | @JvmField 46 | @set:JvmSynthetic 47 | var scaleY = DEFAULT_SCALE_Y 48 | 49 | @JvmField 50 | @set:JvmSynthetic 51 | var duration = DEFAULT_DURATION 52 | 53 | @JvmField 54 | @set:JvmSynthetic 55 | var listener: ViewPropertyAnimatorListener? = null 56 | 57 | @JvmField 58 | @set:JvmSynthetic 59 | var finishListener: ElasticFinishListener? = null 60 | 61 | var isAnimating: Boolean = false 62 | private set 63 | 64 | /** Sets a target elastic scale-x size of the animation. */ 65 | fun setScaleX(scaleX: Float): ElasticAnimation = apply { this.scaleX = scaleX } 66 | 67 | /** Sets a target elastic scale-y size of the animation. */ 68 | fun setScaleY(scaleY: Float): ElasticAnimation = apply { this.scaleY = scaleY } 69 | 70 | /** Sets a duration of the animation. */ 71 | fun setDuration(duration: Int): ElasticAnimation = apply { this.duration = duration } 72 | 73 | /** Sets an animator listener of the animation. */ 74 | fun setListener(listener: ViewPropertyAnimatorListener): ElasticAnimation = apply { 75 | this.listener = listener 76 | } 77 | 78 | /** An animator listener of the animation. */ 79 | fun setOnFinishListener(finishListener: ElasticFinishListener?): ElasticAnimation = apply { 80 | this.finishListener = finishListener 81 | } 82 | 83 | /** An [ElasticFinishListener] listener of the animation. */ 84 | @JvmSynthetic 85 | inline fun setOnFinishListener(crossinline block: () -> Unit): ElasticAnimation = apply { 86 | this.finishListener = ElasticFinishListener { block() } 87 | } 88 | 89 | /** starts elastic animation. */ 90 | fun doAction() { 91 | if (!isAnimating && view.scaleX == 1f) { 92 | val animatorCompat = ViewCompat.animate(view) 93 | .setDuration(duration.toLong()) 94 | .scaleX(scaleX) 95 | .scaleY(scaleY) 96 | .setInterpolator(CycleInterpolator(DEFAULT_ANIMATION_ANCHOR)).apply { 97 | listener?.let { setListener(it) } ?: setListener(object : ViewPropertyAnimatorListener { 98 | override fun onAnimationCancel(view: View?) = Unit 99 | override fun onAnimationStart(view: View?) { 100 | isAnimating = true 101 | } 102 | 103 | override fun onAnimationEnd(view: View?) { 104 | finishListener?.onFinished() 105 | isAnimating = false 106 | } 107 | }) 108 | } 109 | if (view is ViewGroup) { 110 | (0 until view.childCount).map { view.getChildAt(it) }.forEach { child -> 111 | ViewCompat.animate(child) 112 | .setDuration(duration.toLong()) 113 | .scaleX(scaleX) 114 | .scaleY(scaleY) 115 | .setInterpolator(CycleInterpolator(DEFAULT_ANIMATION_ANCHOR)) 116 | .withLayer() 117 | .start() 118 | } 119 | } 120 | animatorCompat.withLayer().start() 121 | } 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /elasticviews/src/main/java/com/skydoves/elasticviews/ElasticButton.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2017 skydoves 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package com.skydoves.elasticviews 25 | 26 | import android.content.Context 27 | import android.content.res.TypedArray 28 | import android.graphics.drawable.ColorDrawable 29 | import android.graphics.drawable.GradientDrawable 30 | import android.util.AttributeSet 31 | import android.view.View 32 | import android.view.View.OnClickListener 33 | import androidx.annotation.Px 34 | import androidx.appcompat.widget.AppCompatButton 35 | import com.skydoves.elasticviews.Definitions.DEFAULT_DURATION 36 | import com.skydoves.elasticviews.Definitions.DEFAULT_SCALE 37 | 38 | @Suppress("unused") 39 | class ElasticButton @JvmOverloads constructor( 40 | context: Context, 41 | attrs: AttributeSet? = null, 42 | defStyle: Int = androidx.appcompat.R.attr.buttonStyle 43 | ) : AppCompatButton(context, attrs, defStyle), ElasticInterface { 44 | 45 | /** The target elastic scale size of the animation. */ 46 | var scale = DEFAULT_SCALE 47 | 48 | /** The default duration of the animation. */ 49 | var duration = DEFAULT_DURATION 50 | 51 | @Px 52 | var cornerRadius = 0f 53 | 54 | private var onClickListener: OnClickListener? = null 55 | private var onFinishListener: ElasticFinishListener? = null 56 | 57 | init { 58 | onCreate() 59 | when { 60 | attrs != null && defStyle != androidx.appcompat.R.attr.buttonStyle -> 61 | getAttrs(attrs, defStyle) 62 | attrs != null -> getAttrs(attrs) 63 | } 64 | } 65 | 66 | private fun onCreate() { 67 | this.isAllCaps = false 68 | super.setOnClickListener { 69 | elasticAnimation(this) { 70 | setDuration(this@ElasticButton.duration) 71 | setScaleX(this@ElasticButton.scale) 72 | setScaleY(this@ElasticButton.scale) 73 | setOnFinishListener { invokeListeners() } 74 | }.doAction() 75 | } 76 | } 77 | 78 | private fun getAttrs(attrs: AttributeSet) { 79 | val typedArray = context.obtainStyledAttributes(attrs, R.styleable.ElasticButton) 80 | try { 81 | setTypeArray(typedArray) 82 | } finally { 83 | typedArray.recycle() 84 | } 85 | } 86 | 87 | private fun getAttrs(attrs: AttributeSet, defStyle: Int) { 88 | val typedArray = context.obtainStyledAttributes(attrs, R.styleable.ElasticButton, defStyle, 0) 89 | try { 90 | setTypeArray(typedArray) 91 | } finally { 92 | typedArray.recycle() 93 | } 94 | } 95 | 96 | private fun setTypeArray(typedArray: TypedArray) { 97 | this.scale = typedArray.getFloat(R.styleable.ElasticButton_button_scale, this.scale) 98 | this.duration = typedArray.getInt(R.styleable.ElasticButton_button_duration, this.duration) 99 | this.cornerRadius = 100 | typedArray.getDimension(R.styleable.ElasticButton_button_cornerRadius, this.cornerRadius) 101 | } 102 | 103 | override fun onFinishInflate() { 104 | super.onFinishInflate() 105 | initializeBackground() 106 | } 107 | 108 | private fun initializeBackground() { 109 | if (background is ColorDrawable) { 110 | background = GradientDrawable().apply { 111 | cornerRadius = this@ElasticButton.cornerRadius 112 | setColor((background as ColorDrawable).color) 113 | }.mutate() 114 | } 115 | } 116 | 117 | override fun setOnClickListener(listener: OnClickListener?) { 118 | this.onClickListener = listener 119 | } 120 | 121 | override fun setOnFinishListener(listener: ElasticFinishListener?) { 122 | this.onFinishListener = listener 123 | } 124 | 125 | override fun setOnClickListener(block: (View) -> Unit) = 126 | setOnClickListener(OnClickListener(block)) 127 | 128 | override fun setOnFinishListener(block: () -> Unit) = 129 | setOnFinishListener(ElasticFinishListener(block)) 130 | 131 | private fun invokeListeners() { 132 | this.onClickListener?.onClick(this) 133 | this.onFinishListener?.onFinished() 134 | } 135 | 136 | /** Builder class for creating [ElasticButton]. */ 137 | class Builder(context: Context) { 138 | private val elasticButton = ElasticButton(context) 139 | 140 | fun setScale(value: Float) = apply { this.elasticButton.scale = value } 141 | fun setDuration(value: Int) = apply { this.elasticButton.duration = value } 142 | fun setCornerRadius(@Px value: Float) = apply { this.elasticButton.cornerRadius = value } 143 | 144 | @JvmSynthetic 145 | fun setOnClickListener(block: (View) -> Unit) = apply { 146 | setOnClickListener(OnClickListener(block)) 147 | } 148 | 149 | fun setOnClickListener(value: OnClickListener) = apply { 150 | this.elasticButton.setOnClickListener(value) 151 | } 152 | 153 | @JvmSynthetic 154 | fun setOnFinishListener(block: () -> Unit) = apply { 155 | setOnFinishListener(ElasticFinishListener(block)) 156 | } 157 | 158 | fun setOnFinishListener(value: ElasticFinishListener) = apply { 159 | this.elasticButton.setOnFinishListener(value) 160 | } 161 | 162 | fun build() = this.elasticButton 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /elasticviews/src/main/java/com/skydoves/elasticviews/ElasticCardView.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2017 skydoves 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package com.skydoves.elasticviews 25 | 26 | import android.content.Context 27 | import android.content.res.TypedArray 28 | import android.util.AttributeSet 29 | import android.view.View 30 | import android.view.View.OnClickListener 31 | import androidx.cardview.widget.CardView 32 | 33 | @Suppress("unused") 34 | class ElasticCardView @JvmOverloads constructor( 35 | context: Context, 36 | attrs: AttributeSet? = null, 37 | defStyle: Int = androidx.cardview.R.attr.cardViewStyle 38 | ) : CardView(context, attrs, defStyle), ElasticInterface { 39 | 40 | /** The target elastic scale size of the animation. */ 41 | var scale = Definitions.DEFAULT_SCALE 42 | 43 | /** The default duration of the animation. */ 44 | var duration = Definitions.DEFAULT_DURATION 45 | 46 | private var onUserClickListener: OnClickListener? = null 47 | private var onFinishListener: ElasticFinishListener? = null 48 | 49 | init { 50 | onCreate() 51 | when { 52 | attrs != null && defStyle != androidx.cardview.R.attr.cardViewStyle -> 53 | getAttrs(attrs, defStyle) 54 | attrs != null -> getAttrs(attrs) 55 | } 56 | } 57 | 58 | private fun onCreate() { 59 | super.setOnClickListener { 60 | elasticAnimation(this) { 61 | setDuration(this@ElasticCardView.duration) 62 | setScaleX(this@ElasticCardView.scale) 63 | setScaleY(this@ElasticCardView.scale) 64 | setOnFinishListener { invokeListeners() } 65 | }.doAction() 66 | } 67 | } 68 | 69 | private fun getAttrs(attrs: AttributeSet) { 70 | val typedArray = context.obtainStyledAttributes(attrs, R.styleable.ElasticCardView) 71 | try { 72 | setTypeArray(typedArray) 73 | } finally { 74 | typedArray.recycle() 75 | } 76 | } 77 | 78 | private fun getAttrs(attrs: AttributeSet, defStyle: Int) { 79 | val typedArray = context.obtainStyledAttributes(attrs, R.styleable.ElasticCardView, defStyle, 0) 80 | try { 81 | setTypeArray(typedArray) 82 | } finally { 83 | typedArray.recycle() 84 | } 85 | } 86 | 87 | private fun setTypeArray(typedArray: TypedArray) { 88 | this.scale = typedArray.getFloat(R.styleable.ElasticCardView_cardView_scale, this.scale) 89 | this.duration = typedArray.getInt(R.styleable.ElasticCardView_cardView_duration, this.duration) 90 | } 91 | 92 | override fun setOnClickListener(listener: OnClickListener?) { 93 | this.onUserClickListener = listener 94 | } 95 | 96 | override fun setOnFinishListener(listener: ElasticFinishListener?) { 97 | this.onFinishListener = listener 98 | } 99 | 100 | override fun setOnClickListener(block: (View) -> Unit) = 101 | setOnClickListener(OnClickListener(block)) 102 | 103 | override fun setOnFinishListener(block: () -> Unit) = 104 | setOnFinishListener(ElasticFinishListener(block)) 105 | 106 | private fun invokeListeners() { 107 | this.onUserClickListener?.onClick(this) 108 | this.onFinishListener?.onFinished() 109 | } 110 | 111 | /** Builder class for creating [ElasticCardView]. */ 112 | class Builder(context: Context) { 113 | private val elasticCardView = ElasticCardView(context) 114 | 115 | fun setScale(value: Float) = apply { this.elasticCardView.scale = value } 116 | fun setDuration(value: Int) = apply { this.elasticCardView.duration = value } 117 | 118 | @JvmSynthetic 119 | fun setOnClickListener(block: (View) -> Unit) = apply { 120 | setOnClickListener(OnClickListener(block)) 121 | } 122 | 123 | fun setOnClickListener(value: OnClickListener) = apply { 124 | this.elasticCardView.setOnClickListener(value) 125 | } 126 | 127 | @JvmSynthetic 128 | fun setOnFinishListener(block: () -> Unit) = apply { 129 | setOnFinishListener(ElasticFinishListener(block)) 130 | } 131 | 132 | fun setOnFinishListener(value: ElasticFinishListener) = apply { 133 | this.elasticCardView.setOnFinishListener(value) 134 | } 135 | 136 | fun build() = this.elasticCardView 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /elasticviews/src/main/java/com/skydoves/elasticviews/ElasticCheckButton.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2017 skydoves 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package com.skydoves.elasticviews 25 | 26 | import android.content.Context 27 | import android.content.res.TypedArray 28 | import android.graphics.drawable.ColorDrawable 29 | import android.graphics.drawable.GradientDrawable 30 | import android.util.AttributeSet 31 | import android.view.View 32 | import android.view.View.OnClickListener 33 | import androidx.annotation.FloatRange 34 | import androidx.annotation.Px 35 | import androidx.appcompat.widget.AppCompatButton 36 | 37 | @Suppress("unused") 38 | class ElasticCheckButton @JvmOverloads constructor( 39 | context: Context, 40 | attrs: AttributeSet? = null, 41 | defStyle: Int = androidx.appcompat.R.attr.buttonStyle 42 | ) : AppCompatButton(context, attrs, defStyle), ElasticInterface { 43 | 44 | /** The target elastic scale size of the animation. */ 45 | var scale = Definitions.DEFAULT_SCALE 46 | 47 | /** The default duration of the animation. */ 48 | var duration = Definitions.DEFAULT_DURATION 49 | 50 | @FloatRange(from = 0.0, to = 1.0) 51 | var checkedAlpha = 0.5f 52 | set(value) { 53 | field = value 54 | updateElasticCheckButton() 55 | } 56 | 57 | @Px 58 | var cornerRadius = 0f 59 | 60 | var isChecked = false 61 | set(value) { 62 | field = value 63 | updateElasticCheckButton() 64 | } 65 | 66 | private var onClickListener: OnClickListener? = null 67 | private var onFinishListener: ElasticFinishListener? = null 68 | 69 | init { 70 | onCreate() 71 | when { 72 | attrs != null && defStyle != androidx.appcompat.R.attr.buttonStyle -> 73 | getAttrs(attrs, defStyle) 74 | attrs != null -> getAttrs(attrs) 75 | } 76 | } 77 | 78 | private fun onCreate() { 79 | this.isAllCaps = false 80 | super.setOnClickListener { 81 | this.isChecked = !this.isChecked 82 | elasticAnimation(this) { 83 | setDuration(this@ElasticCheckButton.duration) 84 | setScaleX(this@ElasticCheckButton.scale) 85 | setScaleY(this@ElasticCheckButton.scale) 86 | setOnFinishListener { invokeListeners() } 87 | }.doAction() 88 | } 89 | } 90 | 91 | private fun getAttrs(attrs: AttributeSet) { 92 | val typedArray = context.obtainStyledAttributes(attrs, R.styleable.ElasticCheckButton) 93 | try { 94 | setTypeArray(typedArray) 95 | } finally { 96 | typedArray.recycle() 97 | } 98 | } 99 | 100 | private fun getAttrs(attrs: AttributeSet, defStyle: Int) { 101 | val typedArray = 102 | context.obtainStyledAttributes(attrs, R.styleable.ElasticCheckButton, defStyle, 0) 103 | try { 104 | setTypeArray(typedArray) 105 | } finally { 106 | typedArray.recycle() 107 | } 108 | } 109 | 110 | private fun setTypeArray(typedArray: TypedArray) { 111 | this.scale = typedArray.getFloat(R.styleable.ElasticCheckButton_checkButton_scale, this.scale) 112 | this.duration = 113 | typedArray.getInt(R.styleable.ElasticCheckButton_checkButton_duration, this.duration) 114 | this.cornerRadius = 115 | typedArray.getDimension( 116 | R.styleable.ElasticCheckButton_checkButton_cornerRadius, 117 | this.cornerRadius 118 | ) 119 | this.checkedAlpha = 120 | typedArray.getFloat(R.styleable.ElasticCheckButton_checkButton_alpha, this.checkedAlpha) 121 | this.isChecked = 122 | typedArray.getBoolean(R.styleable.ElasticCheckButton_checkButton_isChecked, this.isChecked) 123 | } 124 | 125 | override fun onFinishInflate() { 126 | super.onFinishInflate() 127 | initializeBackground() 128 | updateElasticCheckButton() 129 | } 130 | 131 | private fun initializeBackground() { 132 | if (background is ColorDrawable) { 133 | background = GradientDrawable().apply { 134 | cornerRadius = this@ElasticCheckButton.cornerRadius 135 | setColor((background as ColorDrawable).color) 136 | }.mutate() 137 | } 138 | } 139 | 140 | private fun updateElasticCheckButton() { 141 | if (this.isChecked) { 142 | this.alpha = this.checkedAlpha 143 | } 144 | } 145 | 146 | override fun setOnClickListener(listener: OnClickListener?) { 147 | this.onClickListener = listener 148 | } 149 | 150 | override fun setOnFinishListener(listener: ElasticFinishListener?) { 151 | this.onFinishListener = listener 152 | } 153 | 154 | override fun setOnClickListener(block: (View) -> Unit) = 155 | setOnClickListener(OnClickListener(block)) 156 | 157 | override fun setOnFinishListener(block: () -> Unit) = 158 | setOnFinishListener(ElasticFinishListener(block)) 159 | 160 | private fun invokeListeners() { 161 | this.alpha = when (this.isChecked) { 162 | true -> this.checkedAlpha 163 | false -> 1.0f 164 | } 165 | this.onClickListener?.onClick(this) 166 | this.onFinishListener?.onFinished() 167 | } 168 | 169 | /** Builder class for creating [ElasticCheckButton]. */ 170 | class Builder(context: Context) { 171 | private val elasticCheckButton = ElasticCheckButton(context) 172 | 173 | fun setScale(value: Float) = apply { this.elasticCheckButton.scale = value } 174 | fun setDuration(value: Int) = apply { this.elasticCheckButton.duration = value } 175 | fun setCornerRadius(@Px value: Float) = apply { this.elasticCheckButton.cornerRadius = value } 176 | 177 | @JvmSynthetic 178 | fun setOnClickListener(block: (View) -> Unit) = apply { 179 | setOnClickListener(OnClickListener(block)) 180 | } 181 | 182 | fun setOnClickListener(value: OnClickListener) = apply { 183 | this.elasticCheckButton.setOnClickListener(value) 184 | } 185 | 186 | @JvmSynthetic 187 | fun setOnFinishListener(block: () -> Unit) = apply { 188 | setOnFinishListener(ElasticFinishListener(block)) 189 | } 190 | 191 | fun setOnFinishListener(value: ElasticFinishListener) = apply { 192 | this.elasticCheckButton.setOnFinishListener(value) 193 | } 194 | 195 | fun build() = this.elasticCheckButton 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /elasticviews/src/main/java/com/skydoves/elasticviews/ElasticExtensions.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2017 skydoves 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | @file:Suppress("unused") 25 | @file:JvmName("ElasticExtensions") 26 | @file:JvmMultifileClass 27 | 28 | package com.skydoves.elasticviews 29 | 30 | import android.view.View 31 | 32 | @DslMarker 33 | internal annotation class ElasticDsl 34 | 35 | /** 36 | * An extension for operating elastic animation to the target view with custom attributes. 37 | * 38 | * @param scaleX The target elastic scale-x size of the animation. 39 | * @param scaleY The target elastic scale-y size of the animation. 40 | * @param duration The duration of the animation. 41 | * @param listener The [ElasticFinishListener] for being notified when the animation is finished. 42 | */ 43 | @ElasticDsl 44 | @JvmOverloads 45 | @JvmSynthetic 46 | fun View.elasticAnimation( 47 | scaleX: Float = Definitions.DEFAULT_SCALE_X, 48 | scaleY: Float = Definitions.DEFAULT_SCALE_Y, 49 | duration: Int = Definitions.DEFAULT_DURATION, 50 | listener: ElasticFinishListener? = null 51 | ): ElasticAnimation { 52 | return ElasticAnimation(this) 53 | .setScaleX(scaleX) 54 | .setScaleY(scaleY) 55 | .setDuration(duration) 56 | .setOnFinishListener(listener) 57 | } 58 | 59 | /** 60 | * An extension for operating elastic animation to the target view with custom attributes. 61 | * 62 | * @param scaleX The target elastic scale-x size of the animation. 63 | * @param scaleY The target elastic scale-y size of the animation. 64 | * @param duration The duration of the animation. 65 | * @param block The lambda for being notified when the animation is finished. 66 | */ 67 | @ElasticDsl 68 | @JvmOverloads 69 | @JvmSynthetic 70 | inline fun View.elasticAnimation( 71 | scaleX: Float = Definitions.DEFAULT_SCALE_X, 72 | scaleY: Float = Definitions.DEFAULT_SCALE_Y, 73 | duration: Int = Definitions.DEFAULT_DURATION, 74 | crossinline block: () -> Unit 75 | ): ElasticAnimation { 76 | return ElasticAnimation(this) 77 | .setScaleX(scaleX) 78 | .setScaleY(scaleY) 79 | .setDuration(duration) 80 | .setOnFinishListener(ElasticFinishListener { block() }) 81 | } 82 | 83 | /** 84 | * An extension for creating elastic animation with kotlin dsl style. 85 | * 86 | * @param block The dsl block of the [ElasticAnimation]. 87 | * 88 | * @return A new instance of the [ElasticAnimation]. 89 | */ 90 | @ElasticDsl 91 | @JvmSynthetic 92 | inline fun elasticAnimation( 93 | view: View, 94 | crossinline block: ElasticAnimation.() -> Unit 95 | ): ElasticAnimation = ElasticAnimation(view).apply(block) 96 | -------------------------------------------------------------------------------- /elasticviews/src/main/java/com/skydoves/elasticviews/ElasticFinishListener.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2017 skydoves 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package com.skydoves.elasticviews 25 | 26 | /** ElasticFinishListener is for listening elastic animation terminated status. */ 27 | fun interface ElasticFinishListener { 28 | 29 | /** invoked when the elastic animation is terminated. */ 30 | fun onFinished() 31 | } 32 | -------------------------------------------------------------------------------- /elasticviews/src/main/java/com/skydoves/elasticviews/ElasticFloatingActionButton.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2017 skydoves 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package com.skydoves.elasticviews 25 | 26 | import android.content.Context 27 | import android.content.res.TypedArray 28 | import android.util.AttributeSet 29 | import android.view.View 30 | import android.view.View.OnClickListener 31 | import com.google.android.material.floatingactionbutton.FloatingActionButton 32 | 33 | @Suppress("unused") 34 | class ElasticFloatingActionButton @JvmOverloads constructor( 35 | context: Context, 36 | attrs: AttributeSet? = null, 37 | defStyle: Int = com.google.android.material.R.attr.floatingActionButtonStyle 38 | ) : FloatingActionButton(context, attrs, defStyle), ElasticInterface { 39 | 40 | /** The target elastic scale size of the animation. */ 41 | var scale = Definitions.DEFAULT_SCALE 42 | 43 | /** The default duration of the animation. */ 44 | var duration = Definitions.DEFAULT_DURATION 45 | 46 | private var onClickListener: OnClickListener? = null 47 | private var onFinishListener: ElasticFinishListener? = null 48 | 49 | init { 50 | onCreate() 51 | when { 52 | attrs != null && defStyle != com.google.android.material.R.attr.floatingActionButtonStyle -> 53 | getAttrs(attrs, defStyle) 54 | attrs != null -> getAttrs(attrs) 55 | } 56 | } 57 | 58 | private fun onCreate() { 59 | this.isClickable = true 60 | super.setOnClickListener { 61 | elasticAnimation(this) { 62 | setDuration(this@ElasticFloatingActionButton.duration) 63 | setScaleX(this@ElasticFloatingActionButton.scale) 64 | setScaleY(this@ElasticFloatingActionButton.scale) 65 | setOnFinishListener { invokeListeners() } 66 | }.doAction() 67 | } 68 | } 69 | 70 | private fun getAttrs(attrs: AttributeSet) { 71 | val typedArray = context.obtainStyledAttributes(attrs, R.styleable.ElasticFloatingActionButton) 72 | setTypeArray(typedArray) 73 | } 74 | 75 | private fun getAttrs(attrs: AttributeSet, defStyle: Int) { 76 | val typedArray = 77 | context.obtainStyledAttributes(attrs, R.styleable.ElasticFloatingActionButton, defStyle, 0) 78 | setTypeArray(typedArray) 79 | } 80 | 81 | private fun setTypeArray(typedArray: TypedArray) { 82 | this.scale = typedArray.getFloat(R.styleable.ElasticFloatingActionButton_fabutton_scale, scale) 83 | this.duration = 84 | typedArray.getInt(R.styleable.ElasticFloatingActionButton_fabutton_duration, duration) 85 | } 86 | 87 | override fun setOnClickListener(listener: OnClickListener?) { 88 | this.onClickListener = listener 89 | } 90 | 91 | override fun setOnFinishListener(listener: ElasticFinishListener?) { 92 | this.onFinishListener = listener 93 | } 94 | 95 | override fun setOnClickListener(block: (View) -> Unit) = 96 | setOnClickListener(OnClickListener(block)) 97 | 98 | override fun setOnFinishListener(block: () -> Unit) = 99 | setOnFinishListener(ElasticFinishListener(block)) 100 | 101 | private fun invokeListeners() { 102 | this.onClickListener?.onClick(this) 103 | this.onFinishListener?.onFinished() 104 | } 105 | 106 | /** Builder class for creating [ElasticFloatingActionButton]. */ 107 | class Builder(context: Context) { 108 | private val elasticFloatingButton = ElasticFloatingActionButton(context) 109 | 110 | fun setScale(value: Float) = apply { this.elasticFloatingButton.scale = value } 111 | fun setDuration(value: Int) = apply { this.elasticFloatingButton.duration = value } 112 | 113 | @JvmSynthetic 114 | fun setOnClickListener(block: (View) -> Unit) = apply { 115 | setOnClickListener(OnClickListener(block)) 116 | } 117 | 118 | fun setOnClickListener(value: OnClickListener) = apply { 119 | this.elasticFloatingButton.setOnClickListener(value) 120 | } 121 | 122 | @JvmSynthetic 123 | fun setOnFinishListener(block: () -> Unit) = apply { 124 | setOnFinishListener(ElasticFinishListener(block)) 125 | } 126 | 127 | fun setOnFinishListener(value: ElasticFinishListener) = apply { 128 | this.elasticFloatingButton.setOnFinishListener(value) 129 | } 130 | 131 | fun build() = this.elasticFloatingButton 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /elasticviews/src/main/java/com/skydoves/elasticviews/ElasticImageView.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2017 skydoves 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package com.skydoves.elasticviews 25 | 26 | import android.content.Context 27 | import android.content.res.TypedArray 28 | import android.util.AttributeSet 29 | import android.view.View 30 | import android.view.View.OnClickListener 31 | import androidx.appcompat.widget.AppCompatImageView 32 | 33 | @Suppress("unused") 34 | class ElasticImageView @JvmOverloads constructor( 35 | context: Context, 36 | attrs: AttributeSet? = null, 37 | defStyle: Int = 0 38 | ) : AppCompatImageView(context, attrs, defStyle), ElasticInterface { 39 | 40 | /** The target elastic scale size of the animation. */ 41 | var scale = Definitions.DEFAULT_SCALE 42 | 43 | /** The default duration of the animation. */ 44 | var duration = Definitions.DEFAULT_DURATION 45 | 46 | private var onClickListener: OnClickListener? = null 47 | private var onFinishListener: ElasticFinishListener? = null 48 | 49 | init { 50 | onCreate() 51 | when { 52 | attrs != null && defStyle != 0 -> getAttrs(attrs, defStyle) 53 | attrs != null -> getAttrs(attrs) 54 | } 55 | } 56 | 57 | private fun onCreate() { 58 | this.isClickable = true 59 | super.setOnClickListener { 60 | elasticAnimation(this) { 61 | setDuration(this@ElasticImageView.duration) 62 | setScaleX(this@ElasticImageView.scale) 63 | setScaleY(this@ElasticImageView.scale) 64 | setOnFinishListener { invokeListeners() } 65 | }.doAction() 66 | } 67 | } 68 | 69 | private fun getAttrs(attrs: AttributeSet) { 70 | val typedArray = context.obtainStyledAttributes(attrs, R.styleable.ElasticImageView) 71 | try { 72 | setTypeArray(typedArray) 73 | } finally { 74 | typedArray.recycle() 75 | } 76 | } 77 | 78 | private fun getAttrs(attrs: AttributeSet, defStyle: Int) { 79 | val typedArray = 80 | context.obtainStyledAttributes(attrs, R.styleable.ElasticImageView, defStyle, 0) 81 | try { 82 | setTypeArray(typedArray) 83 | } finally { 84 | typedArray.recycle() 85 | } 86 | } 87 | 88 | private fun setTypeArray(typedArray: TypedArray) { 89 | this.scale = typedArray.getFloat(R.styleable.ElasticImageView_imageView_scale, scale) 90 | this.duration = typedArray.getInt(R.styleable.ElasticImageView_imageView_duration, duration) 91 | } 92 | 93 | override fun setOnClickListener(listener: OnClickListener?) { 94 | this.onClickListener = listener 95 | } 96 | 97 | override fun setOnFinishListener(listener: ElasticFinishListener?) { 98 | this.onFinishListener = listener 99 | } 100 | 101 | override fun setOnClickListener(block: (View) -> Unit) = 102 | setOnClickListener(OnClickListener(block)) 103 | 104 | override fun setOnFinishListener(block: () -> Unit) = 105 | setOnFinishListener(ElasticFinishListener(block)) 106 | 107 | private fun invokeListeners() { 108 | this.onClickListener?.onClick(this) 109 | this.onFinishListener?.onFinished() 110 | } 111 | 112 | /** Builder class for creating [ElasticImageView]. */ 113 | class Builder(context: Context) { 114 | private val elasticImageView = ElasticImageView(context) 115 | 116 | fun setScale(value: Float) = apply { this.elasticImageView.scale = value } 117 | fun setDuration(value: Int) = apply { this.elasticImageView.duration = value } 118 | 119 | @JvmSynthetic 120 | fun setOnClickListener(block: (View) -> Unit) = apply { 121 | setOnClickListener(OnClickListener(block)) 122 | } 123 | 124 | fun setOnClickListener(value: OnClickListener) = apply { 125 | this.elasticImageView.setOnClickListener(value) 126 | } 127 | 128 | @JvmSynthetic 129 | fun setOnFinishListener(block: () -> Unit) = apply { 130 | setOnFinishListener(ElasticFinishListener(block)) 131 | } 132 | 133 | fun setOnFinishListener(value: ElasticFinishListener) = apply { 134 | this.elasticImageView.setOnFinishListener(value) 135 | } 136 | 137 | fun build() = this.elasticImageView 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /elasticviews/src/main/java/com/skydoves/elasticviews/ElasticInterface.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2017 skydoves 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package com.skydoves.elasticviews 25 | 26 | import android.view.View 27 | 28 | /** 29 | * ElasticView is an interface for abstracting elastic view's listener. 30 | */ 31 | internal interface ElasticInterface { 32 | 33 | fun setOnClickListener(block: (View) -> Unit) 34 | 35 | fun setOnFinishListener(listener: ElasticFinishListener?) 36 | 37 | fun setOnFinishListener(block: () -> Unit) 38 | } 39 | -------------------------------------------------------------------------------- /elasticviews/src/main/java/com/skydoves/elasticviews/ElasticLayout.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2017 skydoves 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package com.skydoves.elasticviews 25 | 26 | import android.content.Context 27 | import android.content.res.TypedArray 28 | import android.graphics.drawable.ColorDrawable 29 | import android.graphics.drawable.GradientDrawable 30 | import android.util.AttributeSet 31 | import android.view.View 32 | import android.view.View.OnClickListener 33 | import android.widget.FrameLayout 34 | import androidx.annotation.Px 35 | 36 | @Suppress("unused") 37 | class ElasticLayout @JvmOverloads constructor( 38 | context: Context, 39 | attrs: AttributeSet? = null, 40 | defStyle: Int = 0 41 | ) : FrameLayout(context, attrs, defStyle), ElasticInterface { 42 | 43 | /** The target elastic scale size of the animation. */ 44 | var scale = Definitions.DEFAULT_SCALE 45 | 46 | /** The default duration of the animation. */ 47 | var duration = Definitions.DEFAULT_DURATION 48 | 49 | @Px 50 | var cornerRadius = 0f 51 | 52 | private var onClickListener: OnClickListener? = null 53 | private var onFinishListener: ElasticFinishListener? = null 54 | 55 | init { 56 | onCreate() 57 | when { 58 | attrs != null && defStyle != 0 -> getAttrs(attrs, defStyle) 59 | attrs != null -> getAttrs(attrs) 60 | } 61 | } 62 | 63 | private fun onCreate() { 64 | this.isClickable = true 65 | this.isFocusable = true 66 | super.setOnClickListener { 67 | elasticAnimation(this) { 68 | setDuration(this@ElasticLayout.duration) 69 | setScaleX(this@ElasticLayout.scale) 70 | setScaleY(this@ElasticLayout.scale) 71 | setOnFinishListener { invokeListeners() } 72 | }.doAction() 73 | } 74 | } 75 | 76 | private fun getAttrs(attrs: AttributeSet) { 77 | val typedArray = context.obtainStyledAttributes(attrs, R.styleable.ElasticLayout) 78 | try { 79 | setTypeArray(typedArray) 80 | } finally { 81 | typedArray.recycle() 82 | } 83 | } 84 | 85 | private fun getAttrs(attrs: AttributeSet, defStyle: Int) { 86 | val typedArray = context.obtainStyledAttributes(attrs, R.styleable.ElasticLayout, defStyle, 0) 87 | try { 88 | setTypeArray(typedArray) 89 | } finally { 90 | typedArray.recycle() 91 | } 92 | } 93 | 94 | private fun setTypeArray(typedArray: TypedArray) { 95 | this.scale = typedArray.getFloat(R.styleable.ElasticLayout_layout_scale, this.scale) 96 | this.duration = typedArray.getInt(R.styleable.ElasticLayout_layout_duration, this.duration) 97 | this.cornerRadius = 98 | typedArray.getDimension(R.styleable.ElasticLayout_layout_cornerRadius, this.cornerRadius) 99 | } 100 | 101 | override fun onFinishInflate() { 102 | super.onFinishInflate() 103 | initializeBackground() 104 | } 105 | 106 | private fun initializeBackground() { 107 | if (background is ColorDrawable) { 108 | background = GradientDrawable().apply { 109 | cornerRadius = this@ElasticLayout.cornerRadius 110 | setColor((background as ColorDrawable).color) 111 | }.mutate() 112 | } 113 | } 114 | 115 | override fun setOnClickListener(listener: OnClickListener?) { 116 | this.onClickListener = listener 117 | } 118 | 119 | override fun setOnFinishListener(listener: ElasticFinishListener?) { 120 | this.onFinishListener = listener 121 | } 122 | 123 | override fun setOnClickListener(block: (View) -> Unit) = 124 | setOnClickListener(OnClickListener(block)) 125 | 126 | override fun setOnFinishListener(block: () -> Unit) = 127 | setOnFinishListener(ElasticFinishListener(block)) 128 | 129 | private fun invokeListeners() { 130 | this.onClickListener?.onClick(this) 131 | this.onFinishListener?.onFinished() 132 | } 133 | 134 | /** Builder class for creating [ElasticLayout]. */ 135 | class Builder(context: Context) { 136 | private val elasticLayout = ElasticLayout(context) 137 | 138 | fun setScale(value: Float) = apply { this.elasticLayout.scale = value } 139 | fun setDuration(value: Int) = apply { this.elasticLayout.duration = value } 140 | fun setCornerRadius(@Px value: Float) = apply { this.elasticLayout.cornerRadius = value } 141 | 142 | @JvmSynthetic 143 | fun setOnClickListener(block: (View) -> Unit) = apply { 144 | setOnClickListener(OnClickListener(block)) 145 | } 146 | 147 | fun setOnClickListener(value: OnClickListener) = apply { 148 | this.elasticLayout.setOnClickListener(value) 149 | } 150 | 151 | @JvmSynthetic 152 | fun setOnFinishListener(block: () -> Unit) = apply { 153 | setOnFinishListener(ElasticFinishListener(block)) 154 | } 155 | 156 | fun setOnFinishListener(value: ElasticFinishListener) = apply { 157 | this.elasticLayout.setOnFinishListener(value) 158 | } 159 | 160 | fun build() = this.elasticLayout 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /elasticviews/src/main/java/com/skydoves/elasticviews/ElasticView.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2017 skydoves 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package com.skydoves.elasticviews 25 | 26 | import android.content.Context 27 | import android.content.res.TypedArray 28 | import android.graphics.drawable.ColorDrawable 29 | import android.graphics.drawable.GradientDrawable 30 | import android.util.AttributeSet 31 | import android.view.View 32 | import android.view.View.OnClickListener 33 | import androidx.annotation.Px 34 | 35 | @Suppress("unused") 36 | class ElasticView @JvmOverloads constructor( 37 | context: Context, 38 | attrs: AttributeSet? = null, 39 | defStyle: Int = 0 40 | ) : View(context, attrs, defStyle), ElasticInterface { 41 | 42 | /** The target elastic scale size of the animation. */ 43 | var scale = Definitions.DEFAULT_SCALE 44 | 45 | /** The default duration of the animation. */ 46 | var duration = Definitions.DEFAULT_DURATION 47 | 48 | @Px 49 | var cornerRadius = 0f 50 | 51 | private var onUserClickListener: OnClickListener? = null 52 | private var onFinishListener: ElasticFinishListener? = null 53 | 54 | init { 55 | onCreate() 56 | when { 57 | attrs != null && defStyle != 0 -> getAttrs(attrs, defStyle) 58 | attrs != null -> getAttrs(attrs) 59 | } 60 | } 61 | 62 | private fun onCreate() { 63 | super.setOnClickListener { 64 | elasticAnimation(this) { 65 | setDuration(this@ElasticView.duration) 66 | setScaleX(this@ElasticView.scale) 67 | setScaleY(this@ElasticView.scale) 68 | setOnFinishListener { invokeListeners() } 69 | }.doAction() 70 | } 71 | } 72 | 73 | private fun getAttrs(attrs: AttributeSet) { 74 | val typedArray = context.obtainStyledAttributes(attrs, R.styleable.ElasticView) 75 | try { 76 | setTypeArray(typedArray) 77 | } finally { 78 | typedArray.recycle() 79 | } 80 | } 81 | 82 | private fun getAttrs(attrs: AttributeSet, defStyle: Int) { 83 | val typedArray = context.obtainStyledAttributes(attrs, R.styleable.ElasticView, defStyle, 0) 84 | try { 85 | setTypeArray(typedArray) 86 | } finally { 87 | typedArray.recycle() 88 | } 89 | } 90 | 91 | private fun setTypeArray(typedArray: TypedArray) { 92 | this.scale = typedArray.getFloat(R.styleable.ElasticView_view_scale, this.scale) 93 | this.duration = typedArray.getInt(R.styleable.ElasticView_view_duration, this.duration) 94 | this.cornerRadius = 95 | typedArray.getDimension(R.styleable.ElasticView_view_cornerRadius, this.cornerRadius) 96 | } 97 | 98 | override fun onFinishInflate() { 99 | super.onFinishInflate() 100 | initializeBackground() 101 | } 102 | 103 | private fun initializeBackground() { 104 | if (background is ColorDrawable) { 105 | background = GradientDrawable().apply { 106 | cornerRadius = this@ElasticView.cornerRadius 107 | setColor((background as ColorDrawable).color) 108 | }.mutate() 109 | } 110 | } 111 | 112 | override fun setOnClickListener(listener: OnClickListener?) { 113 | this.onUserClickListener = listener 114 | } 115 | 116 | override fun setOnFinishListener(listener: ElasticFinishListener?) { 117 | this.onFinishListener = listener 118 | } 119 | 120 | override fun setOnClickListener(block: (View) -> Unit) = 121 | setOnClickListener(OnClickListener(block)) 122 | 123 | override fun setOnFinishListener(block: () -> Unit) = 124 | setOnFinishListener(ElasticFinishListener(block)) 125 | 126 | private fun invokeListeners() { 127 | this.onUserClickListener?.onClick(this) 128 | this.onFinishListener?.onFinished() 129 | } 130 | 131 | /** Builder class for creating [ElasticView]. */ 132 | class Builder(context: Context) { 133 | private val elasticView = ElasticView(context) 134 | 135 | fun setScale(value: Float) = apply { this.elasticView.scale = value } 136 | fun setDuration(value: Int) = apply { this.elasticView.duration = value } 137 | fun setCornerRadius(@Px value: Float) = apply { this.elasticView.cornerRadius = value } 138 | 139 | @JvmSynthetic 140 | fun setOnClickListener(block: (View) -> Unit) = apply { 141 | setOnClickListener(OnClickListener(block)) 142 | } 143 | 144 | fun setOnClickListener(value: OnClickListener) = apply { 145 | this.elasticView.setOnClickListener(value) 146 | } 147 | 148 | @JvmSynthetic 149 | fun setOnFinishListener(block: () -> Unit) = apply { 150 | setOnFinishListener(ElasticFinishListener(block)) 151 | } 152 | 153 | fun setOnFinishListener(value: ElasticFinishListener) = apply { 154 | this.elasticView.setOnFinishListener(value) 155 | } 156 | 157 | fun build() = this.elasticView 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /elasticviews/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2019 skydoves (Jaewoong Eum) 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | # Jvm environments 18 | org.gradle.jvmargs=-Xmx4g 19 | 20 | # AndroidX 21 | android.useAndroidX=true 22 | 23 | # Required to publish to Nexus 24 | systemProp.org.gradle.internal.publish.checksums.insecure=true 25 | 26 | # Increase timeout when pushing to Sonatype 27 | systemProp.org.gradle.internal.http.connectionTimeout=120000 28 | systemProp.org.gradle.internal.http.socketTimeout=120000 29 | 30 | # Maven 31 | GROUP=com.github.skydoves 32 | POM_PACKAGING=aar 33 | 34 | VERSION_NAME=2.1.1-SNAPSHOT 35 | 36 | POM_ARTIFACT_ID=elasticviews 37 | POM_NAME=elasticviews 38 | POM_DESCRIPTION=An easy way to implement an elastic touch effect for Android. 39 | 40 | POM_URL=https://github.com/skydoves/elasticviews/ 41 | POM_SCM_URL=https://github.com/skydoves/elasticviews/ 42 | POM_SCM_CONNECTION=scm:git:git://github.com/skydoves/elasticviews.git 43 | POM_SCM_DEV_CONNECTION=scm:git:git://github.com/skydoves/elasticviews.git 44 | 45 | POM_LICENCE_NAME=The Apache Software License, Version 2.0 46 | POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt 47 | POM_LICENCE_DIST=repo 48 | 49 | POM_DEVELOPER_ID=skydoves 50 | POM_DEVELOPER_NAME=Jaewoong Eum 51 | POM_DEVELOPER_URL=https://github.com/skydoves/ 52 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skydoves/ElasticViews/752955421fcd12addd59a4e3dd817b2336cebba5/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sat Oct 24 22:39:59 KST 2020 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-all.zip 7 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':elasticviews' 2 | -------------------------------------------------------------------------------- /spotless.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: "com.diffplug.spotless" 2 | apply from: '../dependencies.gradle' 3 | spotless { 4 | kotlin { 5 | target "**/*.kt" 6 | ktlint("$versions.ktlintGradle").userData(['indent_size': '2', 'continuation_indent_size': '2']) 7 | licenseHeaderFile '../spotless.license.kt' 8 | trimTrailingWhitespace() 9 | endWithNewline() 10 | } 11 | } -------------------------------------------------------------------------------- /spotless.license.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2017 skydoves 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ --------------------------------------------------------------------------------