Showing preview only (557K chars total). Download the full file or copy to clipboard to get everything.
Repository: MartinRGB/Animer
Branch: master
Commit: 0feccb729f42
Files: 122
Total size: 510.4 KB
Directory structure:
gitextract_xxgve15n/
├── .gitignore
├── LICENSE
├── README.md
├── README.zh.md
├── animer/
│ ├── .gitignore
│ ├── build.gradle
│ ├── consumer-rules.pro
│ ├── proguard-rules.pro
│ └── src/
│ └── main/
│ ├── AndroidManifest.xml
│ ├── java/
│ │ └── com/
│ │ └── martinrgb/
│ │ └── animer/
│ │ ├── Animer.java
│ │ ├── component/
│ │ │ ├── overscroller/
│ │ │ │ └── launcher3/
│ │ │ │ ├── FlingSpringAnim.java
│ │ │ │ ├── Interpolators.java
│ │ │ │ └── OverScroller.java
│ │ │ ├── overscrolllayout/
│ │ │ │ └── .gitkeep
│ │ │ ├── recyclerview/
│ │ │ │ └── AnRecyclerView.java
│ │ │ └── scrollview/
│ │ │ ├── AnOverScroller.java
│ │ │ └── AnScrollView.java
│ │ ├── core/
│ │ │ ├── interpolator/
│ │ │ │ ├── AnInterpolator.java
│ │ │ │ ├── AndroidNative/
│ │ │ │ │ ├── AccelerateDecelerateInterpolator.java
│ │ │ │ │ ├── AccelerateInterpolator.java
│ │ │ │ │ ├── AnticipateInterpolator.java
│ │ │ │ │ ├── AnticipateOvershootInterpolator.java
│ │ │ │ │ ├── BounceInterpolator.java
│ │ │ │ │ ├── CycleInterpolator.java
│ │ │ │ │ ├── DecelerateInterpolator.java
│ │ │ │ │ ├── FastOutLinearInInterpolator.java
│ │ │ │ │ ├── FastOutSlowInInterpolator.java
│ │ │ │ │ ├── LinearInterpolator.java
│ │ │ │ │ ├── LinearOutSlowInInterpolator.java
│ │ │ │ │ ├── LookupTableInterpolator.java
│ │ │ │ │ ├── OvershootInterpolator.java
│ │ │ │ │ └── PathInterpolator.java
│ │ │ │ ├── AndroidSpringInterpolator.java
│ │ │ │ ├── AndroidSpringInterpolator2.java
│ │ │ │ ├── CustomBounceInterpolator.java
│ │ │ │ ├── CustomDampingInterpolator.java
│ │ │ │ ├── CustomMocosSpringInterpolator.java
│ │ │ │ ├── CustomSpringInterpolator.java
│ │ │ │ └── FlingSpringAnim.java
│ │ │ ├── math/
│ │ │ │ ├── calculator/
│ │ │ │ │ ├── FlingCalculator.java
│ │ │ │ │ └── SpringInterpolatorCalculator.java
│ │ │ │ └── converter/
│ │ │ │ ├── AnSpringConverter.java
│ │ │ │ ├── AndroidSpringConverter.java
│ │ │ │ ├── DHOConverter.java
│ │ │ │ ├── OrigamiPOPConverter.java
│ │ │ │ ├── RK4Converter.java
│ │ │ │ └── UIViewSpringConverter.java
│ │ │ ├── property/
│ │ │ │ └── AnProperty.java
│ │ │ ├── solver/
│ │ │ │ └── AnSolver.java
│ │ │ ├── state/
│ │ │ │ └── PhysicsState.java
│ │ │ └── util/
│ │ │ ├── AnSpringOscillateHelper.java
│ │ │ └── AnUtil.java
│ │ └── monitor/
│ │ ├── AnConfigData.java
│ │ ├── AnConfigMap.java
│ │ ├── AnConfigRegistry.java
│ │ ├── AnConfigView.java
│ │ ├── AnSpinnerAdapter.java
│ │ ├── fps/
│ │ │ ├── Calculation.java
│ │ │ ├── FPSBuilder.java
│ │ │ ├── FPSConfig.java
│ │ │ ├── FPSDetector.java
│ │ │ ├── FPSFrameCallback.java
│ │ │ ├── Foreground.java
│ │ │ └── FrameDataCallback.java
│ │ └── shader/
│ │ ├── ShaderProgram.java
│ │ ├── ShaderRenderer.java
│ │ ├── ShaderSurfaceView.java
│ │ └── util/
│ │ ├── FPSCounter.java
│ │ ├── LoggerConfig.java
│ │ ├── ShaderHelper.java
│ │ └── TextReader.java
│ └── res/
│ ├── drawable/
│ │ ├── background_spinner.xml
│ │ ├── gradient.xml
│ │ ├── ic_button_background.xml
│ │ ├── ic_edit_border.xml
│ │ ├── ic_grid.xml
│ │ ├── ic_nub.xml
│ │ ├── ic_nub2.xml
│ │ ├── ic_spinner.xml
│ │ ├── ic_thumb.xml
│ │ ├── popbackground_spinner.xml
│ │ └── text_cursor.xml
│ ├── layout/
│ │ └── config_view.xml
│ ├── raw/
│ │ ├── simplefrag.glsl
│ │ └── simplevert.glsl
│ └── values/
│ ├── corlors.xml
│ ├── dimension.xml
│ └── styles.xml
├── app/
│ ├── .gitignore
│ ├── build.gradle
│ ├── proguard-rules.pro
│ └── src/
│ ├── androidTest/
│ │ └── java/
│ │ └── com/
│ │ └── martinrgb/
│ │ └── animerexample/
│ │ └── ExampleInstrumentedTest.java
│ ├── main/
│ │ ├── AndroidManifest.xml
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── martinrgb/
│ │ │ └── animerexample/
│ │ │ ├── MainActivity.java
│ │ │ ├── PrototypeActivity.java
│ │ │ ├── ScrollerActivity.java
│ │ │ └── SmoothCornersImage.java
│ │ └── res/
│ │ ├── drawable/
│ │ │ ├── background_elevation.xml
│ │ │ ├── ic_arrow.xml
│ │ │ ├── ic_launcher_background.xml
│ │ │ └── myrect.xml
│ │ ├── drawable-nodpi/
│ │ │ └── mute.xml
│ │ ├── drawable-v24/
│ │ │ └── ic_launcher_foreground.xml
│ │ ├── layout/
│ │ │ ├── activity_main.xml
│ │ │ ├── activity_prototype.xml
│ │ │ ├── activity_scroller.xml
│ │ │ └── custom_cell_view.xml
│ │ ├── mipmap-anydpi-v26/
│ │ │ ├── ic_launcher.xml
│ │ │ └── ic_launcher_round.xml
│ │ └── values/
│ │ ├── attr.xml
│ │ ├── colors.xml
│ │ ├── dimension.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test/
│ └── java/
│ └── com/
│ └── martinrgb/
│ └── animerexample/
│ └── ExampleUnitTest.java
├── build.gradle
├── gradle/
│ └── wrapper/
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
# Built application files
*.apk
*.ap_
*.DS_Store
# Files for the ART/Dalvik VM
*.dex
# Java class files
*.class
# Generated files
bin/
gen/
out/
# Gradle files
.gradle/
build/
# Local configuration file (sdk path, etc)
local.properties
# Proguard folder generated by Eclipse
proguard/
# Log Files
*.log
# Android Studio Navigation editor temp files
.navigation/
# Android Studio captures folder
captures/
# IntelliJ
*.iml
.idea/workspace.xml
.idea/tasks.xml
.idea/gradle.xml
.idea/assetWizardSettings.xml
.idea/dictionaries
.idea/libraries
.idea/caches
.idea
# Keystore files
# Uncomment the following line if you do not want to check your keystore files in.
#*.jks
# External native build folder generated in Android Studio 2.2 and later
.externalNativeBuild
# Google Services (e.g. APIs or Firebase)
google-services.json
# Freeline
freeline.py
freeline/
freeline_project_description.json
# fastlane
fastlane/report.xml
fastlane/Preview.html
fastlane/screenshots
fastlane/test_output
fastlane/readme.md
local.properties
app/.DS_Store
app/.DS_Store
================================================
FILE: LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2019 Qiuyinyan(MartinRGB)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: README.md
================================================
<img src="https://raw.githubusercontent.com/MartinRGB/Animer/master/art/logo.png?token=ABVV6IRDJX54663FGBF3NAC5633SY" alt="" data-canonical-src="https://raw.githubusercontent.com/MartinRGB/Animer/master/art/logo.png?token=ABVV6IRDJX54663FGBF3NAC5633SY" width="264"/>
## About
| MonitorUI Example | Scroller Example | View Prototype |
| ------------- |-------------| ----- |
| <img src="https://raw.githubusercontent.com/MartinRGB/Animer/master/art/gifs.gif" alt="" data-canonical-src="https://raw.githubusercontent.com/MartinRGB/Animer/master/art/gifs.gif"/> | <img src="https://raw.githubusercontent.com/MartinRGB/Animer/master/art/gifs_2.gif" alt="" data-canonical-src="https://raw.githubusercontent.com/MartinRGB/Animer/master/art/gifs.gif_2"/> | <img src="https://raw.githubusercontent.com/MartinRGB/Animer/master/art/gifs_3.gif" alt="" data-canonical-src="https://raw.githubusercontent.com/MartinRGB/Animer/master/art/gifs.gif_3"/>
[中文说明](https://github.com/MartinRGB/Animer/blob/master/README.zh.md)
Animer is a java library which designed for a better Android animation experience.(Currently is more like a view animation controller)
It contains animation curves in `Android` `iOS` `Origami(POP or Rebound in Client)` `Principle` `Protopie` `FramerJS`
Unlike [Rebound](https://github.com/facebook/rebound),Animer didn't use `Choreographer` or self-building `Looper` for
creating an Animator from scratch.
All these animation algorithm will be translated into Android's native implementation like DynamicAnimation & TimingInterpolator,which can improve the performance of animation.
It also provides a real-time controller & graph UI for tweaking parameters.
Web version(Convert Any Animation tools' parameters to Android's) —— [Animer_Web](http://www.martinrgb.com/Animer_Web/#)
AE Script —— [Animer AE](https://github.com/MartinRGB/Animer_AE)
## Download
[  ](https://bintray.com/martinrgb/animer/animer/_latestVersion)
[Simple Demo 1](https://github.com/MartinRGB/Animer/files/3948871/app-debug_2.zip)
[Simple Demo 2](https://github.com/MartinRGB/Animer/files/3948863/app-debug.zip)
## Usage
Animer supports multiple ways of animating:
### Android Native Style
```java
// equal to Android's TimingInterpolator
Animer.AnimerSolver solver = Animer.interpolatorDroid(new AccelerateDecelerateInterpolator(),600)
// similar to ObjectAnimator
Animer animer = new Animer(myView,solver,Animer.TRANSLATION_Y,0,200);
animer.start();
// animer.cancel();
// animer.end();
```
### FramerJS State Machine Style
```java
// equal to Android's SpringAnimation
Animer.AnimerSolver solver = Animer.springDroid(1000,0.5f);
Animer animer = new Animer();
// add a solver to Animer;
animer.setSolver(solver);
// add value to different state;
animer.setStateValue("stateA",300);
animer.setStateValue("stateB",700);
animer.setStateValue("stateC",200);
// add a listener to observe the motion of the Animation
animer.setUpdateListener(new Animer.UpdateListener() {
@Override
public void onUpdate(float value, float velocity, float progress) {
myView1.setTranslationX(value);
myView2.setScaleX(1.f+value/100);
myView2.setScaleY(1.f+value/100);
}
});
// switch immediately
animer.switchToState("stateA");
// or animate to state value
// animer.animateToState("stateB");
```
### Facebook Rebound Style
```java
// equal to Facebook Origami POP Animation
Animer.AnimerSolver solver = Animer.springOrigamiPOP(5,10);
Animer animer = new Animer(myView,solver,Animer.SCALE);
// setup a listener to add everything you want
animer.setUpdateListener(new Animer.UpdateListener() {
@Override
public void onUpdate(float value, float velocity, float progress)
myView.setScaleX(value);
myView.setScaleY(value);
}
});
animer.setCurrentValue(1.f);
boolean isScaled = false;
myView.setOnClickListener(view -> {
if(!isScaled){
animer.setEndValue(0.5);
}
else{
animer.setEndValue(1);
}
isScaled = !isScaled;
});
```
### Add animers to configUI
<img src="https://raw.githubusercontent.com/MartinRGB/Animer/master/art/configui.jpg?token=ABVV6IQRHX6MK3KK4RIFMLS564BKG" alt="" data-canonical-src="https://raw.githubusercontent.com/MartinRGB/Animer/master/art/configui.jpg?token=ABVV6IQRHX6MK3KK4RIFMLS564BKG" width="360" />
init in xml
```xml
<com.martinrgb.animer.monitor.AnConfigView
android:id="@+id/an_configurator"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
```
add animers' config in java
```java
AnConfigView mAnimerConfiguratorView = (AnConfigView) findViewById(R.id.an_configurator);
AnConfigRegistry.getInstance().addAnimer("Card Scale Animation",cardScaleAnimer);
AnConfigRegistry.getInstance().addAnimer("Card TranslationX Animation",cardTransXAnimer);
mAnimerConfiguratorView.refreshAnimerConfigs();
```
### Add custom animation curve presets
<img src="https://raw.githubusercontent.com/MartinRGB/Animer/master/art/preset_reset.jpg" alt="" data-canonical-src="https://raw.githubusercontent.com/MartinRGB/Animer/master/art/preset_reset.jpg" width="360"/>
first you need clean all the solver configs,then add yourselves.
```java
AnConfigRegistry.getInstance().removeAllSolverConfig();
AnConfigRegistry.getInstance().addSolver("Preset1",Animer.springDroid(500.0f,0.96f));
AnConfigRegistry.getInstance().addSolver("Preset2",Animer.flingDroid(400.f,0.95f));
...
mAnimerConfiguratorView.refreshAnimerConfigs();
```
### Supported View Propertys:
```
Animer.TRANSLATION_X
Animer.TRANSLATION_Y
Animer.TRANSLATION_Z
Animer.SCALE // equal to SCALE_X + SCALE_Y
Animer.SCALE_X
Animer.SCALE_Y
Animer.ROTATION
Animer.ROTATION_X
Animer.ROTATION_Y
Animer.X
Animer.Y
Animer.Z
Animer.ALPHA
```
### Supported Animators(as AnimerSolver):
```java
Animer.springDroid(stiffness,dampingratio) // Android Dynamic SpringAnimation
Animer.flingDroid(velocity,friction) // Android Dynamic FlingAnimation
Animer.springiOSUIView(dampingratio,duration) // iOS UIView SPring
Animer.springiOSCoreAnimation(stiffness,damping) // iOS CASpringAnimation
Animer.springOrigamiPOP(bounciness,speed) // Origami POP
Animer.springRK4(tension,friction) // Framer-RK4
Animer.springDHO(stiffness,damping) // Framer-DHO
Animer.springProtopie(tension,friction) // Protopie
Animer.springPrinciple(tension,friction) // Principle
// Custom Bounce Interpolator(Romain Guy's DropInMotion)
Animer.interpolatorDroid(new CustomBounceInterpolator(),duration)
// Custom Damping Interpolator(Romain Guy's DropInMotion)
Animer.interpolatorDroid(new CustomDampingInterpolator(),duration)
// MocosSpring Interpolator (https://github.com/marcioapaiva/mocos-controlator)
Animer.interpolatorDroid(new CustomMocosSpringInterpolator(),duration)
// Custom Spring Interpolator(https://inloop.github.io/interpolator/)
Animer.interpolatorDroid(new CustomSpringInterpolator(),duration)
// Android Native Interpolator Below
Animer.interpolatorDroid(new PathInterpolator(),duration) // Cubic Bezier Interpolator
...
Animer.interpolatorDroid(new DecelerateInterpolator(),duration) // Android Decelerate Interpolator
...
```
## TODO
- A State Machine which can control interface's state(current is only object propertyValue's state)
- Redesign the API
- Rewrite the glsl shader
- Consider scences in activity/fragment transition
- Hook mechanism
- Redesign the ConfigUI,it's difficult to tweak paras in small screen,maybe consider 'adb+electron in desktop client'
## Core concpet:
<img src="https://raw.githubusercontent.com/MartinRGB/Animer/master/art/concept_en.jpg" alt="" data-canonical-src="https://raw.githubusercontent.com/MartinRGB/Animer/master/art/concept_en.jpg" width="900" />
**Data**
- State machine concpet from [FramerJS](https://github.com/koenbok/Framer/tree/master/framer) ✅
- Aniamtion converter from my [Animation Converter](https://github.com/MartinRGB/AndroidInterpolator_AE) ✅
- Support external JSON to edit animation data
**Althogrim**
- Physics animation concept from [Rebound](https://github.com/facebook/rebound) & Android DynamicAnimation ✅
- LookupTable Interpolation Animator + RK4 Solver + DHO Solver ✅
- Physics simulation from [Flutter Physics](https://api.flutter.dev/flutter/physics/physics-library.html) & [UIKit Dyanmic](https://developer.apple.com/documentation/uikit/animation_and_haptics/uikit_dynamics)
- Momentum
- Calculating mass by Elements' area
- Limit SpringAnimation's by time or overshoot counts
**Advanced Animation Setting**
- Addtive animation (compose mulitple animation)
- Chained animation (one by one)
- Parallax animation (same duration but differnt transition)
- Sequencing animation (same transition but different startDelay)
**User-Control**
- Gesture-Driven animation,you can interact with the animation even it is animating(Like iOS's `CADisplayLink` Or Rebound's `SetEndValue`) ✅
- Package a gesture animator for interactive animation,attach gesture's velocity to animation system,make a flawess experience.
- Easy2use animation listener for controlling other element when the object is interacting or animating ✅
**Performance**
- Use android framework native DyanmicAniamtion And TimingInterpolator ✅
- Pre-save animation's data for less calculation
- Hardware Acceleration ✅
**Design Component**
- Scrollview|Scroller|PageViewer Component & Example
- Drag | DND Component & Example
- Button Component & Example
- Transition Component & Example(Maintain different element's property in state machine)
- Scroll-selector Component & Example(Scroll to fixed position)
- Swipe to delete Component & Example
**Dev Tools**
- Data-bind graph to modify and preview animation in application ✅
- Data-bind selctor to change animation-type in application ✅(Still has some bugs)
**Utils**
- AE Plugin for converting curves & revealing codes ✅(Will update GUI later)
## License
See Apache License [here](https://github.com/MartinRGB/Animer/blob/master/LICENSE)
================================================
FILE: README.zh.md
================================================
<img src="https://raw.githubusercontent.com/MartinRGB/Animer/master/art/logo.png?token=ABVV6IRDJX54663FGBF3NAC5633SY" alt="" data-canonical-src="https://raw.githubusercontent.com/MartinRGB/Animer/master/art/logo.png?token=ABVV6IRDJX54663FGBF3NAC5633SY" width="264"/>
## 关于
| MonitorUI Example | Scroller Example | View Prototype |
| ------------- |-------------| ----- |
| <img src="https://raw.githubusercontent.com/MartinRGB/Animer/master/art/gifs.gif" alt="" data-canonical-src="https://raw.githubusercontent.com/MartinRGB/Animer/master/art/gifs.gif"/> | <img src="https://raw.githubusercontent.com/MartinRGB/Animer/master/art/gifs_2.gif" alt="" data-canonical-src="https://raw.githubusercontent.com/MartinRGB/Animer/master/art/gifs.gif_2"/> | <img src="https://raw.githubusercontent.com/MartinRGB/Animer/master/art/gifs_3.gif" alt="" data-canonical-src="https://raw.githubusercontent.com/MartinRGB/Animer/master/art/gifs.gif_3"/>
Launguage:[English](https://github.com/MartinRGB/Animer)
Animer 是一款致力于提升 Android 动画体验的 Java 库
你可以把 Animer 理解为`基于 View 动画` 、`强化动画控制、交互性` 的动画器,并提供了调试UI
Animer 封装了:
* Android 平台的 DynamicAnimation 和 Interpolator 的曲线
* iOS 平台的 CASpringAnimation 和 UIViewSpring 的曲线
* 贝塞尔函数曲线 (iOS Deafult Easing,Web Default CSS Easing,AE 的关键帧间曲线 都可以用此法实现)
* Principle、Origami、Protopie、FramerJS 等动画工具的曲线
Animer 并没有像 [Rebound](https://github.com/facebook/rebound) 那样,通过 Choreographer 或者自构建 Looper ,从头构建一套动画器,而是将上述曲线的算法通过转换器,最终会转换成 Android 原生的 DynamicAnimation 或者 TimingInterpolator,进而提高动画执行性能。
Animer 提供了可实时调节的控制UI和曲线图表,以便设计师和开发者调节参数,节省编译时间。
网页版本(该网页主要功能是可以将其他平台、工具的参数转化为安卓原生动画类的参数) —— [Animer_Web](http://www.martinrgb.com/Animer_Web/#)
AE 脚本 —— [Animer AE](https://github.com/MartinRGB/Animer_AE)
## 下载
## 两个简单的 View 实现的快速原型
[  ](https://bintray.com/martinrgb/animer/animer/_latestVersion)
[View Demo 1](https://github.com/MartinRGB/Animer/files/3948871/app-debug_2.zip)
[View Demo 2](https://github.com/MartinRGB/Animer/files/3948863/app-debug.zip)
## 使用方法
Animer 支持多种风格的动画方法,如果写过 FramerJS、用过 Rebound 库的朋友会非常熟悉,也模拟了安卓原生的动画方法。
### Android 原生风格
```java
// 创建一个 Animer 解算器对象,采用了原生的插值动画类
Animer.AnimerSolver solver = Animer.interpolatorDroid(new AccelerateDecelerateInterpolator(),600)
// 模仿 ObjectAnimator 的构造
Animer animer = new Animer(myView,solver,Animer.TRANSLATION_Y,0,200);
animer.start();
// animer.cancel();
// animer.end();
```
### FramerJS 状态机风格( FramerJS 的状态机动画机制 非常便于组织、整理页面动画)
```java
// 创建一个 Animer 解算器对象,采用了原生的 DynamicAnimation 动画器
Animer.AnimerSolver solver = Animer.springDroid(1000,0.5f);
Animer animer = new Animer();
// 给 Animer 对象添加 solver
animer.setSolver(solver);
// 设置动画的几种可能状态(入场、退场、点击)
animer.setStateValue("stateA",300);
animer.setStateValue("stateB",700);
animer.setStateValue("stateC",200);
// 给动画添加监听,观察数值变化
animer.setUpdateListener(new Animer.UpdateListener() {
@Override
public void onUpdate(float value, float velocity, float progress) {
myView1.setTranslationX(value);
myView2.setScaleX(1.f+value/100);
myView2.setScaleY(1.f+value/100);
}
});
// 立即切换到状态
animer.switchToState("stateA");
// 动画运动到状态
// animer.animateToState("stateB");
```
### Facebook Rebound 风格
```java
// 创建一个 Animer 解算器对象,采用了 Facebook 的 POP 弹性动画器
Animer.AnimerSolver solver = Animer.springOrigamiPOP(5,10);
Animer animer = new Animer(myView,solver,Animer.SCALE);
// 给动画添加监听,观察数值变化,这里将对象 view 的缩放和动画器数值绑定
animer.setUpdateListener(new Animer.UpdateListener() {
@Override
public void onUpdate(float value, float velocity, float progress)
myView.setScaleX(value);
myView.setScaleY(value);
}
});
animer.setCurrentValue(1.f);
boolean isScaled = false;
myView.setOnClickListener(view -> {
if(!isScaled){
animer.setEndValue(0.5);
}
else{
animer.setEndValue(1);
}
isScaled = !isScaled;
});
```
### 将 Animer 对象添加到 config UI 中
<img src="https://raw.githubusercontent.com/MartinRGB/Animer/master/art/configui.jpg?token=ABVV6IQRHX6MK3KK4RIFMLS564BKG" alt="" data-canonical-src="https://raw.githubusercontent.com/MartinRGB/Animer/master/art/configui.jpg?token=ABVV6IQRHX6MK3KK4RIFMLS564BKG" width="360" />
添加 XML
```xml
<com.martinrgb.animer.monitor.AnConfigView
android:id="@+id/an_configurator"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
```
在 Java中, 将 Animer 对象添加到 AnConfigRegistry 实例中,然后刷新 UI
```java
AnConfigView mAnimerConfiguratorView = (AnConfigView) findViewById(R.id.an_configurator);
AnConfigRegistry.getInstance().addAnimer("Card Scale Animation",cardScaleAnimer);
AnConfigRegistry.getInstance().addAnimer("Card TranslationX Animation",cardTransXAnimer);
mAnimerConfiguratorView.refreshAnimerConfigs();
```
### 将自定义曲线预设添加到 config UI 中
<img src="https://raw.githubusercontent.com/MartinRGB/Animer/master/art/preset_reset.jpg" alt="" data-canonical-src="https://raw.githubusercontent.com/MartinRGB/Animer/master/art/preset_reset.jpg" width="360"/>
先需要清空默认的所有预设,然后添加自己的动画预设。
```java
AnConfigRegistry.getInstance().removeAllSolverConfig();
AnConfigRegistry.getInstance().addSolver("Preset1",Animer.springDroid(500.0f,0.96f));
AnConfigRegistry.getInstance().addSolver("Preset2",Animer.flingDroid(400.f,0.95f));
...
mAnimerConfiguratorView.refreshAnimerConfigs();
```
### 支持的 View 属性
```
Animer.TRANSLATION_X
Animer.TRANSLATION_Y
Animer.TRANSLATION_Z
Animer.SCALE // equal to SCALE_X + SCALE_Y
Animer.SCALE_X
Animer.SCALE_Y
Animer.ROTATION
Animer.ROTATION_X
Animer.ROTATION_Y
Animer.X
Animer.Y
Animer.Z
Animer.ALPHA
```
### 支持的动画曲线
```java
Animer.springDroid(stiffness,dampingratio) // Android Dynamic SpringAnimation
Animer.flingDroid(velocity,friction) // Android Dynamic FlingAnimation
Animer.springiOSUIView(dampingratio,duration) // iOS UIView SPring
Animer.springiOSCoreAnimation(stiffness,damping) // iOS CASpringAnimation
Animer.springOrigamiPOP(bounciness,speed) // Origami POP
Animer.springRK4(tension,friction) // Framer-RK4
Animer.springDHO(stiffness,damping) // Framer-DHO
Animer.springProtopie(tension,friction) // Protopie
Animer.springPrinciple(tension,friction) // Principle
// Custom Bounce Interpolator(Romain Guy's DropInMotion)
Animer.interpolatorDroid(new CustomBounceInterpolator(),duration)
// Custom Damping Interpolator(Romain Guy's DropInMotion)
Animer.interpolatorDroid(new CustomDampingInterpolator(),duration)
// MocosSpring Interpolator (https://github.com/marcioapaiva/mocos-controlator)
Animer.interpolatorDroid(new CustomMocosSpringInterpolator(),duration)
// Custom Spring Interpolator(https://inloop.github.io/interpolator/)
Animer.interpolatorDroid(new CustomSpringInterpolator(),duration)
// Android Native Interpolator Below
Animer.interpolatorDroid(new PathInterpolator(),duration) // Cubic Bezier Interpolator
...
Animer.interpolatorDroid(new DecelerateInterpolator(),duration) // Android Decelerate Interpolator
...
```
## TODO
- 以界面整体状态为考量的状态机系统,而不是单个对象的状态
- 重新设计 API,重新编写文档,提高可用性
- 重写绘制图表的 shader,目前使用了太多条件分歧,参考[如何在shader中避免使用if else](https://www.bilibili.com/read/cv1469216/)
- 考虑转场的使用场景
- 考虑 Hook 机制
- 考虑重新设计调试UI,因为不方便连续调试,可能考虑 adb + electron + web桌面客户端的方式
## Animer 设计的核心理念和一些想法
下图是 Animer 大致的原理和设计思路
<img src="https://raw.githubusercontent.com/MartinRGB/Animer/master/art/concept_cn.jpg" alt="" data-canonical-src="https://raw.githubusercontent.com/MartinRGB/Animer/master/art/concept_cn.jpg" width="900" />
**数据**
- FramerJS 的[动画状态机概念](https://github.com/koenbok/Framer/tree/master/framer) ✅
- Animation Converter 中的[多平台、工具动画器转换函数](https://github.com/MartinRGB/AndroidInterpolator_AE) ✅
- 支持读取外部 JSON 编辑动画(???)
**算法**
- Rebound 的[物理动画概念](https://github.com/facebook/rebound) 和 Android 的 DynamicAnimation ✅
- Android 原生的 查找表插值器(LookupTable Interpolator) + RK4 弹性解算器 + DHO 弹性解算器 ✅
- Flutter Physics 的[物理模拟](https://api.flutter.dev/flutter/physics/physics-library.html) & UIKit Dyanmic 的[物理模拟](https://developer.apple.com/documentation/uikit/animation_and_haptics/uikit_dynamics)
- 动量传递与保存(通过状态机实现)
- 通过元素面积计算质量
- 通过振荡次数或时间限制弹性动画运动时长
**高级动画**
- 叠加动画(Addtive animation,将多个动画同时影响到一个对象)
- 链式动画(Chained animation,动画一个接一个开始)
- 视差效果(Parallax animation,相同动画触发,不同动画曲线、时间、延迟)
- 序列动画(Sequencing animation,动画逐次开始)
**交互动画**
- 支持手势驱动的动画,动画可中断,可在动画过程中重新交互(参考 iOS `CADisplayLink` 或 Rebound 的 `SetEndValue`) ✅
- 内置封装一个手势动画器,提供手势速度自动保留,以便手势交互时动画体验更物理、更流畅。(完成一半)
- 提供易用的动画监听,在动画监听中控制多个对象元素 ✅
**性能**
- 所有动画最终被转换为 Android 框架原生的 DyanmicAniamtion 和 TimingInterpolator,可调试完解除依赖然后使用原生写法 ✅
- 可考虑将动画数据转换为预存数组,以便节省实时计算开销
- 硬件加速 ✅
**设计组件**
- Scrollview|Scroller|PageViewer 组件跟案例,提供更好的 Overscroll 和 Fling 效果
- Drag | 拖拽组件跟案例,提供更符合物理直觉的甩手感
- Button 组件和案例
- Transition 组件和案例(考虑如何在不同 Activity 中维护一个元素的属性以便转场)
- Scroll-selector 滑动选择器组件和案例(类似 iOS 的日期选择器,提供平缓的衰减且定位的滚动体验)
- Swipe to delete 滑动删除组件和案例(更自然的滑动删除效果)
**开发工具**
- 提供 GLSL 异步绘制的图表,展示动画曲线本身 ✅
- 提供 GLSL 异步绘制的图表,展示实时属性变化曲线
- 提供数据与 View 属性绑定的控制 UI,实时切换、修改动画 ✅(目前仍有些许 bugs)
**实用工具**
- AE 插件,通过赋予关键帧表达式模拟上述曲线 ✅(目前仅为脚本,后面提供 Extension 级插件,增加 UI)
## 协议
采用了 Apache 许可协议,[详细](https://github.com/MartinRGB/Animer/blob/master/LICENSE)
================================================
FILE: animer/.gitignore
================================================
/build
================================================
FILE: animer/build.gradle
================================================
apply plugin: 'com.android.library'
apply plugin: 'com.github.dcendents.android-maven'
apply plugin: 'com.jfrog.bintray'
//apply plugin: 'com.novoda.bintray-release'
android {
compileSdkVersion 29
defaultConfig {
minSdkVersion 26
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles 'consumer-rules.pro'
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility = "1.8"
targetCompatibility = "1.8"
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.1.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
implementation 'androidx.recyclerview:recyclerview:1.1.0'
implementation 'androidx.dynamicanimation:dynamicanimation:1.1.0-alpha02'
}
//publish {
// userOrg = 'martinrgb'
// groupId = 'com.martinrgb'
// repoName = 'animer'
// artifactId = 'animer'
// publishVersion = '0.1.6.0'
// desc = 'An animation controller for better Android Experience'
// website = "https://github.com/MartinRGB/Animer"
//}
//项目主页
def siteUrl = 'https://github.com/MartinRGB/Animer'
//项目的版本控制地址
def gitUrl = 'https://github.com/MartinRGB/Animer.git'
//发布到组织名称名字,必须填写
group = "com.martinrgb"
//发布到JCenter上的项目名字,必须填写
def libName = "animer"
// 版本号,下次更新是只需要更改版本号即可
version = "0.1.6.3"
/** 上面配置后上传至JCenter后的编译路径是这样的: compile 'group:libName:version' **/
//生成源文件
task sourcesJar(type: Jar) {
from android.sourceSets.main.java.srcDirs
archiveClassifier.set("sources")
}
//生成文档
task javadoc(type: Javadoc) {
source = android.sourceSets.main.java.srcDirs
classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
options.encoding "UTF-8"
options.charSet 'UTF-8'
options.author true
options.version true
options.links "https://github.com/MartinRGB/Animer"
failOnError false
}
//文档打包成jar
task javadocJar(type: Jar, dependsOn: javadoc) {
archiveClassifier.set("javadoc")
from javadoc.destinationDir
}
//拷贝javadoc文件
task copyDoc(type: Copy) {
from "${buildDir}/docs/"
into "docs"
}
//上传到jCenter所需要的源码文件
artifacts {
archives javadocJar
archives sourcesJar
}
// 配置maven库,生成POM.xml文件
install {
repositories.mavenInstaller {
// This generates POM.xml with proper parameters
pom {
project {
packaging 'aar'
name 'baseui'
url siteUrl
licenses {
license {
name 'The Apache Software License, Version 2.0'
url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
}
}
developers {
developer {
id 'MartinRGB'
name 'Martin Tsiu'
email 'qiuyinsen@gmail.com'
}
}
scm {
connection gitUrl
developerConnection gitUrl
url siteUrl
}
}
}
}
}
//上传到JCenter
Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())
bintray {
user = properties.getProperty("bintray.user") //读取 local.properties 文件里面的 bintray.user
key = properties.getProperty("bintray.apikey") //读取 local.properties 文件里面的 bintray.apikey
configurations = ['archives']
pkg {
repo = "animer"
name = libName //发布到JCenter上的项目名字,必须填写
desc = 'Animation Framework' //项目描述
websiteUrl = siteUrl
vcsUrl = gitUrl
licenses = ["Apache-2.0"]
publish = true
}
}
================================================
FILE: animer/consumer-rules.pro
================================================
================================================
FILE: animer/proguard-rules.pro
================================================
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
================================================
FILE: animer/src/main/AndroidManifest.xml
================================================
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.martinrgb.animer" />
================================================
FILE: animer/src/main/java/com/martinrgb/animer/Animer.java
================================================
package com.martinrgb.animer;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.util.Log;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.LinearInterpolator;
import androidx.core.view.ViewCompat;
import androidx.dynamicanimation.animation.DynamicAnimation;
import androidx.dynamicanimation.animation.FlingAnimation;
import androidx.dynamicanimation.animation.FloatValueHolder;
import androidx.dynamicanimation.animation.SpringAnimation;
import androidx.dynamicanimation.animation.SpringForce;
import com.martinrgb.animer.core.interpolator.AnInterpolator;
import com.martinrgb.animer.core.math.converter.AndroidSpringConverter;
import com.martinrgb.animer.core.math.converter.DHOConverter;
import com.martinrgb.animer.core.math.converter.OrigamiPOPConverter;
import com.martinrgb.animer.core.math.converter.RK4Converter;
import com.martinrgb.animer.core.math.converter.UIViewSpringConverter;
import com.martinrgb.animer.core.property.AnProperty;
import com.martinrgb.animer.core.solver.AnSolver;
import com.martinrgb.animer.core.state.PhysicsState;
import com.martinrgb.animer.monitor.AnConfigData;
public class Animer<T> {
// ###########################################
// Property
// ###########################################
private abstract static class AnimerProperty extends AnProperty<View> {
private AnimerProperty(String name) {
super(name);
}
}
public static final AnimerProperty TRANSLATION_X = new AnimerProperty("translationX") {
@Override
public void setValue(View view, float value) {
view.setTranslationX(value);
}
@Override
public float getValue(View view) {
return view.getTranslationX();
}
};
public static final AnimerProperty TRANSLATION_Y = new AnimerProperty("translationY") {
@Override
public void setValue(View view, float value) {
view.setTranslationY(value);
}
@Override
public float getValue(View view) {
return view.getTranslationY();
}
};
public static final AnimerProperty TRANSLATION_Z = new AnimerProperty("translationZ") {
@Override
public void setValue(View view, float value) {
ViewCompat.setTranslationZ(view, value);
}
@Override
public float getValue(View view) {
return ViewCompat.getTranslationZ(view);
}
};
public static final AnimerProperty SCALE = new AnimerProperty("scale") {
@Override
public void setValue(View view, float value) {
view.setScaleX(value);
view.setScaleY(value);
}
@Override
public float getValue(View view) {
return view.getScaleX();
}
};
public static final AnimerProperty SCALE_X = new AnimerProperty("scaleX") {
@Override
public void setValue(View view, float value) {
view.setScaleX(value);
}
@Override
public float getValue(View view) {
return view.getScaleX();
}
};
public static final AnimerProperty SCALE_Y = new AnimerProperty("scaleY") {
@Override
public void setValue(View view, float value) {
view.setScaleY(value);
}
@Override
public float getValue(View view) {
return view.getScaleY();
}
};
public static final AnimerProperty ROTATION = new AnimerProperty("rotation") {
@Override
public void setValue(View view, float value) {
view.setRotation(value);
}
@Override
public float getValue(View view) {
return view.getRotation();
}
};
public static final AnimerProperty ROTATION_X = new AnimerProperty("rotationX") {
@Override
public void setValue(View view, float value) {
view.setRotationX(value);
}
@Override
public float getValue(View view) {
return view.getRotationX();
}
};
public static final AnimerProperty ROTATION_Y = new AnimerProperty("rotationY") {
@Override
public void setValue(View view, float value) {
view.setRotationY(value);
}
@Override
public float getValue(View view) {
return view.getRotationY();
}
};
public static final AnimerProperty X = new AnimerProperty("x") {
@Override
public void setValue(View view, float value) {
view.setX(value);
}
@Override
public float getValue(View view) {
return view.getX();
}
};
public static final AnimerProperty Y = new AnimerProperty("y") {
@Override
public void setValue(View view, float value) {
view.setY(value);
}
@Override
public float getValue(View view) {
return view.getY();
}
};
public static final AnimerProperty Z = new AnimerProperty("z") {
@Override
public void setValue(View view, float value) {
ViewCompat.setZ(view, value);
}
@Override
public float getValue(View view) {
return ViewCompat.getZ(view);
}
};
public static final AnimerProperty ALPHA = new AnimerProperty("alpha") {
@Override
public void setValue(View view, float value) {
view.setAlpha(value);
}
@Override
public float getValue(View view) {
return view.getAlpha();
}
};
// ###########################################
// Arugment
// ###########################################
public Object getArgument1(){
return getCurrentSolver().getArg1();
}
public void setArgument1(Object val){
getCurrentSolver().setArg1(val);
}
public Object getArgument2(){
return getCurrentSolver().getArg2();
}
public void setArgument2(Object val){
getCurrentSolver().setArg2(val);
}
public AnConfigData getCurrentSolverData(){
return getCurrentSolver().getConfigSet();
}
// ###########################################
// Object
// ###########################################
private Object mTarget;
private AnimerProperty mProperty;
private PhysicsState mPhysicsState;
private FlingAnimation mFlingAnimation;
private SpringAnimation mSpringAnimation;
private ObjectAnimator mTimingAnimation;
private static final int FLING_SOLVER_MODE = 0;
private static final int SPRING_SOLVER_MODE = 1;
private static final int INTERPOLATOR_SOLVER_MODE = 2;
private static AnimerSolver defaultSpringSolver = springDroid(50f,0.99f);
private AnimerSolver currentSolver = springDroid(50f,0.99f);
public AnimerSolver getCurrentSolver() {
return currentSolver;
}
public void setCurrentSolver(AnimerSolver solver) {
currentSolver.unBindSolverListener();
currentSolver = solver;
}
private static final int VALUE_ANIMATOR_MODE = 0;
private static final int OBJECT_ANIMAOTR_MODE = 1;
private int ANIMATOR_MODE = -1;
private boolean HARDWAREACCELERATION_IS_ENABLED = false;
private float velocityFactor = 1.0f;
private float minimumVisValue = 0.001f;
// ###########################################
// Solver
// ###########################################
public static class AnimerSolver extends AnSolver {
private AnConfigData anConfigData;
private AnimerSolver(Object val1,Object val2,int mode,AnConfigData data) {
super(val1,val2,mode);
setConfigSet(data);
}
public AnConfigData getConfigSet(){
return anConfigData;
}
private void setConfigSet(AnConfigData data){
anConfigData = data;
}
}
public static AnimerSolver flingDroid(float velocity,float friction){
AnConfigData configData = new AnConfigData(velocity,friction);
configData.setArguments("AndroidFling","velocity",-5000,5000,"friction",0.01,10);
return new AnimerSolver(velocity,friction,0,configData);
}
public static AnimerSolver springDroid(float stiffness,float dampingratio){
AnConfigData configData = new AnConfigData(stiffness,dampingratio);
configData.setArguments("AndroidSpring","stiffness",0.01,3000,"dampingratio",0.01,1);
return new AnimerSolver(stiffness,dampingratio,1,configData);
}
public static AnimerSolver springRK4(float tension,float friction){
AnConfigData configData = new AnConfigData(tension,friction);
configData.setArguments("RK4Spring","tension",0.01,3000,"friction",0.01,100);
RK4Converter rk4Converter = new RK4Converter(tension,friction);
return new AnimerSolver(rk4Converter.getStiffness(),rk4Converter.getDampingRatio(),1,configData);
}
public static AnimerSolver springDHO(float stiffness,float damping){
AnConfigData configData = new AnConfigData(stiffness,damping);
configData.setArguments("DHOSpring","stiffness",0.01,3000,"damping",0.01,100);
DHOConverter dhoConverter = new DHOConverter(stiffness,damping);
return new AnimerSolver(dhoConverter.getStiffness(),dhoConverter.getDampingRatio(),1,configData);
}
public static AnimerSolver springOrigamiPOP(float bounciness,float speed){
AnConfigData configData = new AnConfigData(bounciness,speed);
configData.setArguments("OrigamiPOPSpring","bounciness",0.01,100,"speed",0.01,100);
OrigamiPOPConverter origamiPOPConverter = new OrigamiPOPConverter(bounciness,speed);
return new AnimerSolver(origamiPOPConverter.getStiffness(),origamiPOPConverter.getDampingRatio(),1,configData);
}
public static AnimerSolver springiOSUIView(float dampingratio,float duration){
AnConfigData configData = new AnConfigData(dampingratio,duration);
configData.setArguments("iOSUIViewSpring","dampingratio",0.01,0.99,"duration",0.01,5);
UIViewSpringConverter uiViewSpringConverter = new UIViewSpringConverter(dampingratio,duration);
return new AnimerSolver(uiViewSpringConverter.getStiffness(),uiViewSpringConverter.getDampingRatio(),1,configData);
}
public static AnimerSolver springiOSCoreAnimation(float stiffness,float damping){
AnConfigData configData = new AnConfigData(stiffness,damping);
configData.setArguments("iOSCoreAnimationSpring","stiffness",0.01,3000,"damping",0.01,100);
DHOConverter dhoConverter = new DHOConverter(stiffness,damping);
return new AnimerSolver(dhoConverter.getStiffness(),dhoConverter.getDampingRatio(),1,configData);
}
public static AnimerSolver springProtopie(float tension,float friction){
AnConfigData configData = new AnConfigData(tension,friction);
configData.setArguments("ProtopieSpring","tension",0.01,3000,"friction",0.01,100);
RK4Converter rk4Converter = new RK4Converter(tension,friction);
return new AnimerSolver(rk4Converter.getStiffness(),rk4Converter.getDampingRatio(),1,configData);
}
public static AnimerSolver springPrinciple(float tension,float friction){
AnConfigData configData = new AnConfigData(tension,friction);
configData.setArguments("PrincipleSpring","tension",0.01,3000,"friction",0.01,100);
RK4Converter rk4Converter = new RK4Converter(tension,friction);
return new AnimerSolver(rk4Converter.getStiffness(),rk4Converter.getDampingRatio(),1,configData);
}
public static AnimerSolver interpolatorDroid(AnInterpolator interpolator, long duration){
AnConfigData configData = new AnConfigData(interpolator,duration);
configData.setArguments("AndroidInterpolator","interpolator",0.01,1,"duration",0.01,5000);
return new AnimerSolver(interpolator,duration,2,configData);
}
// ###########################################
// Constructor
// ###########################################
public <K> Animer() {
mTarget = null;
mProperty = null;
mPhysicsState = new PhysicsState();
ANIMATOR_MODE = VALUE_ANIMATOR_MODE;
setupBySolver(currentSolver);
}
public <K> Animer(AnimerSolver solver) {
mTarget = null;
mProperty = null;
mPhysicsState = new PhysicsState();
ANIMATOR_MODE = VALUE_ANIMATOR_MODE;
setupBySolver(solver);
}
public <K> Animer(float value) {
mTarget = null;
mProperty = null;
mPhysicsState = new PhysicsState((float)value);
ANIMATOR_MODE = VALUE_ANIMATOR_MODE;
setupBySolver(currentSolver);
}
public <K> Animer(AnimerSolver solver,float value) {
mTarget = null;
mProperty = null;
mPhysicsState = new PhysicsState((float) value);
ANIMATOR_MODE = VALUE_ANIMATOR_MODE;
setupBySolver(solver);
}
public <K> Animer(K target, AnimerSolver solver, AnimerProperty property) {
mTarget = target;
mProperty = property;
float proertyValue = mProperty.getValue((View) mTarget);
mPhysicsState = new PhysicsState(proertyValue);
ANIMATOR_MODE = OBJECT_ANIMAOTR_MODE;
setupBySolver(solver);
}
public <K> Animer(K target, AnimerSolver solver, AnimerProperty property, float end) {
mTarget = target;
mProperty = property;
float proertyValue = mProperty.getValue((View) mTarget);
mPhysicsState = new PhysicsState(proertyValue,end);
ANIMATOR_MODE = OBJECT_ANIMAOTR_MODE;
setupBySolver(solver);
}
public <K> Animer(K target, AnimerSolver solver, AnimerProperty property, float start, float end) {
mTarget = target;
mProperty = property;
mPhysicsState = new PhysicsState(start,end);
ANIMATOR_MODE = OBJECT_ANIMAOTR_MODE;
setupBySolver(solver);
}
public void setTarget(Object target) {
this.mTarget = target;
}
public void setProperty(AnimerProperty mProperty) {
this.mProperty = mProperty;
}
// ############################################
// Setup Solver
// ############################################
// TODO:MORE Accuracy Setting
public void setSolver(AnimerSolver solver){
cancel();
setupBySolver(solver);
}
// ############################################
// Setup Aniamtor
// ############################################
private void setupBySolver(AnimerSolver solver) {
switch(solver.getSolverMode())
{
case FLING_SOLVER_MODE:
setupFlingAnimator(solver);
break;
case SPRING_SOLVER_MODE:
setupSpringAnimator(solver);
break;
case INTERPOLATOR_SOLVER_MODE:
setupTimingAnimator(solver);
break;
default:
break;
}
}
private void setupFlingAnimator(AnimerSolver solver){
setCurrentSolver(solver);
if(mFlingAnimation == null) {
mFlingAnimation = new FlingAnimation(new FloatValueHolder());
mFlingAnimation.setMinimumVisibleChange(minimumVisValue);
mFlingAnimation.addUpdateListener(new DynamicAnimation.OnAnimationUpdateListener() {
@Override
public void onAnimationUpdate(DynamicAnimation animation, float value, float velocity) {
float progress = (value - getStateValue("Start"))/(getStateValue("End") - getStateValue("Start"));
updateCurrentPhysicsState(value,velocity,progress);
}
});
mFlingAnimation.addEndListener(new DynamicAnimation.OnAnimationEndListener() {
@Override
public void onAnimationEnd(DynamicAnimation animation, boolean canceled, float value, float velocity) {
endCurrentPhysicsState(value,0,true);
if(triggereListener !=null ){
triggereListener.onTrigger(false);
}
}
});
}
attachSolverToFling(solver,mFlingAnimation);
}
private void attachSolverToFling(AnimerSolver solver, FlingAnimation flingAnimation){
final FlingAnimation flingAnim = flingAnimation;
flingAnim.setStartVelocity((float) solver.getArg1());
flingAnim.setFriction((float) solver.getArg2());
solver.bindSolverListener(new AnimerSolver.SolverListener() {
@Override
public void onSolverUpdate(Object arg1, Object arg2) {
flingAnim.setStartVelocity((float) arg1);
flingAnim.setFriction((float) arg2);
}
});
}
private void setupSpringAnimator(AnimerSolver solver){
setCurrentSolver(solver);
if(mSpringAnimation == null) {
mSpringAnimation = new SpringAnimation(new FloatValueHolder());
mSpringAnimation.setSpring(new SpringForce());
mSpringAnimation.setMinimumVisibleChange(minimumVisValue);
mSpringAnimation.addUpdateListener(new DynamicAnimation.OnAnimationUpdateListener() {
@Override
public void onAnimationUpdate(DynamicAnimation animation, float value, float velocity) {
float progress = (value - getStateValue("Start"))/(getStateValue("End") - getStateValue("Start"));
updateCurrentPhysicsState(value,velocity,progress);
}
});
mSpringAnimation.addEndListener(new DynamicAnimation.OnAnimationEndListener() {
@Override
public void onAnimationEnd(DynamicAnimation animation, boolean canceled, float value, float velocity) {
endCurrentPhysicsState(value,0,true);
if(triggereListener !=null ){
triggereListener.onTrigger(false);
}
}
});
}
attachSolverToSpring(solver,mSpringAnimation);
}
private void attachSolverToSpring(AnimerSolver solver, SpringAnimation springAnimation){
final SpringAnimation springAnim = springAnimation;
springAnim.getSpring().setStiffness( (float) solver.getArg1());
springAnim.getSpring().setDampingRatio( (float) solver.getArg2());
solver.bindSolverListener(new AnimerSolver.SolverListener() {
@Override
public void onSolverUpdate(Object arg1, Object arg2) {
springAnim.getSpring().setStiffness((float) arg1);
springAnim.getSpring().setDampingRatio((float) arg2);
}
});
}
private void setupTimingAnimator(AnimerSolver solver){
setCurrentSolver(solver);
if(mTimingAnimation == null) {
mTimingAnimation = new ObjectAnimator();
mTimingAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
float mCurrentVelocity,mPrevVelocity;
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
//#1
mCurrentVelocity = (float) valueAnimator.getAnimatedValue();
float value = mCurrentVelocity;
float velocity = mCurrentVelocity - mPrevVelocity;
float progress = (value - getStateValue("Start"))/(getStateValue("End") - getStateValue("Start"));
updateCurrentPhysicsState(value,velocity,progress);
mPrevVelocity = (float) valueAnimator.getAnimatedValue();
}
});
mTimingAnimation.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
endCurrentPhysicsState(getCurrentPhysicsValue(),0,true);
if(triggereListener !=null ){
triggereListener.onTrigger(false);
}
}
});
}
attachSolverToTiming(solver,mTimingAnimation);
}
private void attachSolverToTiming(AnimerSolver solver, ObjectAnimator timingAnimation){
final ObjectAnimator timingAnim = timingAnimation;
timingAnim.setInterpolator( (AnInterpolator) solver.getArg1());
timingAnim.setDuration( (long) solver.getArg2());
solver.bindSolverListener(new AnimerSolver.SolverListener() {
@Override
public void onSolverUpdate(Object arg1, Object arg2) {
timingAnim.setInterpolator((AnInterpolator) arg1);
timingAnim.setDuration((long) arg2);
}
});
}
// ############################################
// Animation Control Interface
// ############################################
// ## Android Style Animaton Interface,driven by PhysicsState's State Machine
public void setFrom(float start){
setStateValue("Start",start);
//# Then from-to-setVelocity-start can work
getCurrentPhysicsState().updatePhysicsValue(start);
switch(currentSolver.getSolverMode())
{
case FLING_SOLVER_MODE:
mFlingAnimation.setStartValue(getStateValue("Start"));
break;
case SPRING_SOLVER_MODE:
mSpringAnimation.setStartValue(getStateValue("Start"));
break;
case INTERPOLATOR_SOLVER_MODE:
mTimingAnimation.setFloatValues(getStateValue("Start"),getStateValue("End"));
break;
default:
break;
}
}
public void setTo(float end){
setStateValue("End",end);
switch(currentSolver.getSolverMode())
{
case FLING_SOLVER_MODE:
setupSpringAnimator(defaultSpringSolver);
mSpringAnimation.getSpring().setFinalPosition(getStateValue("End"));
break;
case SPRING_SOLVER_MODE:
mSpringAnimation.getSpring().setFinalPosition(getStateValue("End"));
break;
case INTERPOLATOR_SOLVER_MODE:
mTimingAnimation.setFloatValues(getStateValue("Start"),getStateValue("End"));
break;
default:
break;
}
}
public void start(){
if(triggereListener != null){
triggereListener.onTrigger(true);
//triggereListener.onTrigger(false);
}
setHardwareAcceleration(true);
if(currentSolver.getSolverMode() == FLING_SOLVER_MODE) {
mFlingAnimation.cancel();
mFlingAnimation.start();
}
else {
animateToState("End");
}
}
public void cancel(){
if(mFlingAnimation !=null && mFlingAnimation.isRunning()){
mFlingAnimation.cancel();
}
if(mSpringAnimation !=null && mSpringAnimation.isRunning()){
mSpringAnimation.cancel();
}
if(mTimingAnimation !=null && mTimingAnimation.isRunning()){
mTimingAnimation.cancel();
}
}
public boolean isRunning(){
boolean isRunning = false;
switch(currentSolver.getSolverMode())
{
case FLING_SOLVER_MODE:
if(mFlingAnimation !=null)
isRunning = mFlingAnimation.isRunning();
break;
case SPRING_SOLVER_MODE:
if(mSpringAnimation !=null)
isRunning = mSpringAnimation.isRunning();
break;
case INTERPOLATOR_SOLVER_MODE:
if(mTimingAnimation !=null)
isRunning = mTimingAnimation.isRunning();
break;
default:
break;
}
return isRunning;
}
public void end(){
cancel();
switch(currentSolver.getSolverMode())
{
case FLING_SOLVER_MODE:
setupSpringAnimator(defaultSpringSolver);
if(mSpringAnimation.canSkipToEnd()){
mSpringAnimation.skipToEnd();
}
break;
case SPRING_SOLVER_MODE:
if(mSpringAnimation.canSkipToEnd()){
mSpringAnimation.skipToEnd();
}
break;
case INTERPOLATOR_SOLVER_MODE:
mTimingAnimation.end();
break;
default:
break;
}
switchToState("End");
}
public void reverse(){
animateToState("Start");
}
// ## FramerJS Style Animation Interface,driven by PhysicsState's State Machine
public void switchToState(String state){
cancel();
float progress = (getStateValue(state) - getStateValue("Start"))/(getStateValue("End") - getStateValue("Start"));
updateCurrentPhysicsState(getStateValue(state),getCurrentPhysicsVelocity(),progress);
}
public void animateToState(String state){
if(triggereListener != null){
triggereListener.onTrigger(true);
//triggereListener.onTrigger(false);
}
setHardwareAcceleration(true);
switch(currentSolver.getSolverMode())
{
case FLING_SOLVER_MODE:
setupSpringAnimator(defaultSpringSolver);
mSpringAnimation.setStartValue(getCurrentPhysicsValue());
mSpringAnimation.setStartVelocity(getCurrentPhysicsVelocity());
mSpringAnimation.animateToFinalPosition(getStateValue(state));
break;
case SPRING_SOLVER_MODE:
mSpringAnimation.setStartValue(getCurrentPhysicsValue());
mSpringAnimation.setStartVelocity(getCurrentPhysicsVelocity());
mSpringAnimation.animateToFinalPosition(getStateValue(state));
break;
case INTERPOLATOR_SOLVER_MODE:
mTimingAnimation.setFloatValues(getCurrentPhysicsValue(),getStateValue(state));
mTimingAnimation.start();
break;
default:
break;
}
}
// ## Origami-POP-Rebound Style Animation Interface,driven by PhysicsState's Value
// # Equal to [setCurrentValue]
public void setCurrentValue(float value){
float velocity = value - getCurrentPhysicsValue();
float progress = (value - getStateValue("Start"))/(getStateValue("End") - getStateValue("Start"));
updateCurrentPhysicsState(value,velocity*velocityFactor,progress);
}
// # Equal to [setEndValue]
public void setEndValue(float value){
if(triggereListener != null){
triggereListener.onTrigger(true);
//triggereListener.onTrigger(false);
}
setHardwareAcceleration(true);
switch(currentSolver.getSolverMode())
{
case FLING_SOLVER_MODE:
setupSpringAnimator(defaultSpringSolver);
mSpringAnimation.setStartValue(getCurrentPhysicsValue());
mSpringAnimation.setStartVelocity(getCurrentPhysicsVelocity());
mSpringAnimation.animateToFinalPosition(value);
break;
case SPRING_SOLVER_MODE:
mSpringAnimation.setStartValue(getCurrentPhysicsValue());
mSpringAnimation.setStartVelocity(getCurrentPhysicsVelocity());
mSpringAnimation.animateToFinalPosition(value);
break;
case INTERPOLATOR_SOLVER_MODE:
mTimingAnimation.setFloatValues(getCurrentPhysicsValue(),value);
mTimingAnimation.start();
break;
default:
break;
}
}
// ############################################
// Setup Velocity
// ############################################
// ## State
public void setVelocity(float velocity){
setCurrentPhysicsVelocity(velocity);
}
public void setVelocityInfluence(float factor){
velocityFactor = factor;
}
// ############################################
// minVisChange
// ############################################
public void setMinimumVisibleChange(float minimumVisValue) {
this.minimumVisValue = minimumVisValue;
switch(currentSolver.getSolverMode())
{
case FLING_SOLVER_MODE:
mFlingAnimation.setMinimumVisibleChange(minimumVisValue);
break;
case SPRING_SOLVER_MODE:
mSpringAnimation.setMinimumVisibleChange(minimumVisValue);
break;
case INTERPOLATOR_SOLVER_MODE:
break;
default:
break;
}
}
// ############################################
// PhysicsState's Getter & Setter
// ############################################
public void setStateValue(String key,float value){
mPhysicsState.setStateValue(key,value);
}
public float getStateValue(String state){
return mPhysicsState.getStateValue(state);
}
// ## Value
private void setCurrentPhysicsVelocity(float velocity){
mPhysicsState.updatePhysicsVelocity(velocity);
}
private void setCurrenetPhysicsValue(float value){
mPhysicsState.updatePhysicsValue(value);
}
private float getCurrentPhysicsVelocity(){
return mPhysicsState.getPhysicsVelocity();
}
private float getCurrentPhysicsValue(){
return mPhysicsState.getPhysicsValue();
}
private void endCurrentPhysicsState(float value,float velocity,boolean canceled){
setCurrenetPhysicsValue(value);
setCurrentPhysicsVelocity(velocity);
setHardwareAcceleration(false);
if (endListener != null) {
endListener.onEnd(value,velocity,canceled);
}
}
// ## Mainly use this for listener-mode
private void updateCurrentPhysicsState(float value,float velocity,float progress){
setCurrenetPhysicsValue(value);
setCurrentPhysicsVelocity(velocity);
if (ANIMATOR_MODE != VALUE_ANIMATOR_MODE) {
mProperty.setValue((View) mTarget, value);
}
if (updateListener != null) {
updateListener.onUpdate(value,velocity,progress);
}
}
public PhysicsState getCurrentPhysicsState(){
return mPhysicsState;
}
// ############################################
// Hardware Acceleration
// ############################################
private void setHardwareAcceleration(boolean bool){
if(HARDWAREACCELERATION_IS_ENABLED && mTarget !=null){
if(bool){
if(((View)mTarget).getLayerType() == View.LAYER_TYPE_NONE){
((View)mTarget).setLayerType(View.LAYER_TYPE_HARDWARE,null);
}
}
else{
if(((View)mTarget).getLayerType() == View.LAYER_TYPE_HARDWARE){
((View)mTarget).setLayerType(View.LAYER_TYPE_NONE,null);
}
}
}
}
public boolean isHardwareAccelerationEnabled() {
return HARDWAREACCELERATION_IS_ENABLED;
}
public void enableHardwareAcceleration(boolean enable){
HARDWAREACCELERATION_IS_ENABLED = enable;
}
// ############################################
// TODO: Optim Actioner
// ############################################
private boolean ENABLE_ACTIONER_POSTION_VELOCITY = false;
private Object mActioner;
public void enableActionerInfluenceOnVelocity(boolean boo){
ENABLE_ACTIONER_POSTION_VELOCITY = boo;
}
private boolean getActionerInfluenceOnVelocity(){
return ENABLE_ACTIONER_POSTION_VELOCITY;
}
public <K> void setActionerAndListener(K actioner,ActionTouchListener listener){
mActioner = actioner;
setActionTouchListener(listener);
((View)mActioner).setOnTouchListener(new View.OnTouchListener() {
VelocityTracker velocityTracker;
float initX = 0,initY = 0;
float startX,startY,posX = 0,posY = 0,velX = 0,velY = 0;
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
switch (motionEvent.getAction()) {
case MotionEvent.ACTION_DOWN: {
if (velocityTracker == null) {
velocityTracker = VelocityTracker.obtain();
} else {
velocityTracker.clear();
}
velocityTracker.addMovement(motionEvent);
startX = view.getX() - motionEvent.getRawX();
startY = view.getY() - motionEvent.getRawY();
actionListener.onDown(view,motionEvent);
break;
}
case MotionEvent.ACTION_MOVE: {
velocityTracker.addMovement(motionEvent);
velocityTracker.computeCurrentVelocity(1000);
velX = velocityTracker.getXVelocity();
velY = velocityTracker.getYVelocity();
posX = motionEvent.getRawX() + startX;
posY = motionEvent.getRawY() + startY;
actionListener.onMove(view,motionEvent,velX,velY);
break;
}
case MotionEvent.ACTION_UP: {
Log.e("velX",String.valueOf(velX));
if(getActionerInfluenceOnVelocity()){
setVelocity(velX);
}
actionListener.onUp(view,motionEvent);
break;
}
case MotionEvent.ACTION_CANCEL: {
actionListener.onCancel(view,motionEvent);
break;
}
}
return true;
}
});
}
// ############################################
// Animation Listener
// ############################################
private UpdateListener updateListener;
private EndListener endListener;
private ActionTouchListener actionListener;
private TriggeredListener triggereListener;
public void setUpdateListener(UpdateListener listener) {
updateListener = listener;
}
public void setEndListener(EndListener listener) {
endListener = listener;
}
public TriggeredListener getTriggerListener() {
if(triggereListener !=null){
return triggereListener;
}
else{
return null;
}
}
public void setTriggerListener(TriggeredListener listener) {
triggereListener = listener;
}
public void removeTriggerListener() {
triggereListener = null;
}
public void setActionTouchListener(ActionTouchListener listener) {
actionListener = listener;
}
public interface UpdateListener {
void onUpdate(float value, float velocity,float progress);
}
public interface EndListener{
void onEnd(float value, float velocity,boolean canceled);
}
public interface TriggeredListener{
void onTrigger(boolean triggered);
}
public interface ActionTouchListener{
void onDown(View view,MotionEvent event);
void onMove(View view,MotionEvent event,float velocityX,float velocityY);
void onUp(View view,MotionEvent event);
abstract void onCancel(View view,MotionEvent event);
}
}
================================================
FILE: animer/src/main/java/com/martinrgb/animer/component/overscroller/launcher3/FlingSpringAnim.java
================================================
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.martinrgb.animer.component.overscroller.launcher3;
import androidx.dynamicanimation.animation.DynamicAnimation.OnAnimationEndListener;
import androidx.dynamicanimation.animation.FlingAnimation;
import androidx.dynamicanimation.animation.FloatPropertyCompat;
import androidx.dynamicanimation.animation.SpringAnimation;
import androidx.dynamicanimation.animation.SpringForce;
/**
* Given a property to animate and a target value and starting velocity, first apply friction to
* the fling until we pass the target, then apply a spring force to pull towards the target.
*/
public class FlingSpringAnim {
private static final float FLING_FRICTION = 1.5f;
private static final float SPRING_STIFFNESS = 400f;
private static final float SPRING_DAMPING = 0.8f;
private final FlingAnimation mFlingAnim;
private SpringAnimation mSpringAnim;
private float mTargetPosition;
public <K> FlingSpringAnim(K object, FloatPropertyCompat<K> property, float startPosition,
float targetPosition, float startVelocity, float minVisChange, float minValue,
float maxValue, float springVelocityFactor, OnAnimationEndListener onEndListener) {
mFlingAnim = new FlingAnimation(object, property)
.setFriction(FLING_FRICTION)
// Have the spring pull towards the target if we've slowed down too much before
// reaching it.
.setMinimumVisibleChange(minVisChange)
.setStartVelocity(startVelocity)
.setMinValue(minValue)
.setMaxValue(maxValue);
mTargetPosition = targetPosition;
mFlingAnim.addEndListener(((animation, canceled, value, velocity) -> {
mSpringAnim = new SpringAnimation(object, property)
.setStartValue(value)
.setStartVelocity(velocity * springVelocityFactor)
.setSpring(new SpringForce(mTargetPosition)
.setStiffness(SPRING_STIFFNESS)
.setDampingRatio(SPRING_DAMPING));
mSpringAnim.addEndListener(onEndListener);
mSpringAnim.animateToFinalPosition(mTargetPosition);
}));
}
public float getTargetPosition() {
return mTargetPosition;
}
public void updatePosition(float startPosition, float targetPosition) {
mFlingAnim.setMinValue(Math.min(startPosition, targetPosition))
.setMaxValue(Math.max(startPosition, targetPosition));
mTargetPosition = targetPosition;
if (mSpringAnim != null) {
mSpringAnim.animateToFinalPosition(mTargetPosition);
}
}
public void start() {
mFlingAnim.start();
}
public void end() {
mFlingAnim.cancel();
if (mSpringAnim.canSkipToEnd()) {
mSpringAnim.skipToEnd();
}
}
}
================================================
FILE: animer/src/main/java/com/martinrgb/animer/component/overscroller/launcher3/Interpolators.java
================================================
package com.martinrgb.animer.component.overscroller.launcher3;
//import static com.android.launcher3.util.DefaultDisplay.getSingleFrameMs;
import android.content.Context;
import android.graphics.Path;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
import android.view.animation.OvershootInterpolator;
import android.view.animation.PathInterpolator;
/**
* Common interpolators used in Launcher
*/
public class Interpolators {
public static final Interpolator LINEAR = new LinearInterpolator();
public static final Interpolator ACCEL = new AccelerateInterpolator();
public static final Interpolator ACCEL_1_5 = new AccelerateInterpolator(1.5f);
public static final Interpolator ACCEL_2 = new AccelerateInterpolator(2);
public static final Interpolator DEACCEL = new DecelerateInterpolator();
public static final Interpolator DEACCEL_1_5 = new DecelerateInterpolator(1.5f);
public static final Interpolator DEACCEL_1_7 = new DecelerateInterpolator(1.7f);
public static final Interpolator DEACCEL_2 = new DecelerateInterpolator(2);
public static final Interpolator DEACCEL_2_5 = new DecelerateInterpolator(2.5f);
public static final Interpolator DEACCEL_3 = new DecelerateInterpolator(3f);
public static final Interpolator ACCEL_DEACCEL = new AccelerateDecelerateInterpolator();
public static final Interpolator FAST_OUT_SLOW_IN = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
public static final Interpolator AGGRESSIVE_EASE = new PathInterpolator(0.2f, 0f, 0f, 1f);
public static final Interpolator AGGRESSIVE_EASE_IN_OUT = new PathInterpolator(0.6f,0, 0.4f, 1);
public static final Interpolator EXAGGERATED_EASE;
public static final Interpolator INSTANT = t -> 1;
private static final int MIN_SETTLE_DURATION = 200;
private static final float OVERSHOOT_FACTOR = 0.9f;
static {
Path exaggeratedEase = new Path();
exaggeratedEase.moveTo(0, 0);
exaggeratedEase.cubicTo(0.05f, 0f, 0.133333f, 0.08f, 0.166666f, 0.4f);
exaggeratedEase.cubicTo(0.225f, 0.94f, 0.5f, 1f, 1f, 1f);
EXAGGERATED_EASE = new PathInterpolator(exaggeratedEase);
}
public static final Interpolator OVERSHOOT_1_2 = new OvershootInterpolator(1.2f);
public static final Interpolator OVERSHOOT_1_7 = new OvershootInterpolator(1.7f);
public static final Interpolator TOUCH_RESPONSE_INTERPOLATOR =
new PathInterpolator(0.3f, 0f, 0.1f, 1f);
/**
* Inversion of ZOOM_OUT, compounded with an ease-out.
*/
public static final Interpolator ZOOM_IN = new Interpolator() {
@Override
public float getInterpolation(float v) {
return DEACCEL_3.getInterpolation(1 - ZOOM_OUT.getInterpolation(1 - v));
}
};
public static final Interpolator ZOOM_OUT = new Interpolator() {
private static final float FOCAL_LENGTH = 0.35f;
@Override
public float getInterpolation(float v) {
return zInterpolate(v);
}
/**
* This interpolator emulates the rate at which the perceived scale of an object changes
* as its distance from a camera increases. When this interpolator is applied to a scale
* animation on a view, it evokes the sense that the object is shrinking due to moving away
* from the camera.
*/
private float zInterpolate(float input) {
return (1.0f - FOCAL_LENGTH / (FOCAL_LENGTH + input)) /
(1.0f - FOCAL_LENGTH / (FOCAL_LENGTH + 1.0f));
}
};
public static final Interpolator SCROLL = new Interpolator() {
@Override
public float getInterpolation(float t) {
t -= 1.0f;
return t*t*t*t*t + 1;
}
};
public static final Interpolator SCROLL_CUBIC = new Interpolator() {
@Override
public float getInterpolation(float t) {
t -= 1.0f;
return t*t*t + 1;
}
};
private static final float FAST_FLING_PX_MS = 10;
public static Interpolator scrollInterpolatorForVelocity(float velocity) {
return Math.abs(velocity) > FAST_FLING_PX_MS ? SCROLL : SCROLL_CUBIC;
}
/**
* Create an OvershootInterpolator with tension directly related to the velocity (in px/ms).
* @param velocity The start velocity of the animation we want to overshoot.
*/
public static Interpolator overshootInterpolatorForVelocity(float velocity) {
return new OvershootInterpolator(Math.min(Math.abs(velocity), 3f));
}
/**
* Runs the given interpolator such that the entire progress is set between the given bounds.
* That is, we set the interpolation to 0 until lowerBound and reach 1 by upperBound.
*/
public static Interpolator clampToProgress(Interpolator interpolator, float lowerBound,
float upperBound) {
if (upperBound <= lowerBound) {
throw new IllegalArgumentException(String.format(
"lowerBound (%f) must be less than upperBound (%f)", lowerBound, upperBound));
}
return t -> {
if (t < lowerBound) {
return 0;
}
if (t > upperBound) {
return 1;
}
return interpolator.getInterpolation((t - lowerBound) / (upperBound - lowerBound));
};
}
/**
* Runs the given interpolator such that the interpolated value is mapped to the given range.
* This is useful, for example, if we only use this interpolator for part of the animation,
* such as to take over a user-controlled animation when they let go.
*/
public static Interpolator mapToProgress(Interpolator interpolator, float lowerBound,
float upperBound) {
return t -> mapRange(interpolator.getInterpolation(t), lowerBound, upperBound);
}
/**
* Computes parameters necessary for an overshoot effect.
*/
private static int singleFrameMs = 1;
public static class OvershootParams {
public Interpolator interpolator;
public float start;
public float end;
public long duration;
/**
* Given the input params, sets OvershootParams variables to be used by the caller.
* @param startProgress The progress from 0 to 1 that the overshoot starts from.
* @param overshootPastProgress The progress from 0 to 1 where we overshoot past (should
* either be equal to startProgress or endProgress, depending on if we want to
* overshoot immediately or only once we reach the end).
* @param endProgress The final progress from 0 to 1 that we will settle to.
* @param velocityPxPerMs The initial velocity that causes this overshoot.
* @param totalDistancePx The distance against which progress is calculated.
*/
public OvershootParams(float startProgress, float overshootPastProgress,
float endProgress, float velocityPxPerMs, int totalDistancePx, Context context) {
velocityPxPerMs = Math.abs(velocityPxPerMs);
start = startProgress;
int startPx = (int) (start * totalDistancePx);
// Overshoot by about half a frame.
float overshootBy = OVERSHOOT_FACTOR * velocityPxPerMs *
singleFrameMs / totalDistancePx / 2; //getSingleFrameMs(context)
overshootBy = boundToRange(overshootBy, 0.02f, 0.15f);
end = overshootPastProgress + overshootBy;
int endPx = (int) (end * totalDistancePx);
int overshootDistance = endPx - startPx;
// Calculate deceleration necessary to reach overshoot distance.
// Formula: velocityFinal^2 = velocityInitial^2 + 2 * acceleration * distance
// 0 = v^2 + 2ad (velocityFinal == 0)
// a = v^2 / -2d
float decelerationPxPerMs = velocityPxPerMs * velocityPxPerMs / (2 * overshootDistance);
// Calculate time necessary to reach peak of overshoot.
// Formula: acceleration = velocity / time
// time = velocity / acceleration
duration = (long) (velocityPxPerMs / decelerationPxPerMs);
// Now that we're at the top of the overshoot, need to settle back to endProgress.
float settleDistance = end - endProgress;
int settleDistancePx = (int) (settleDistance * totalDistancePx);
// Calculate time necessary for the settle.
// Formula: distance = velocityInitial * time + 1/2 * acceleration * time^2
// d = 1/2at^2 (velocityInitial = 0, since we just stopped at the top)
// t = sqrt(2d/a)
// Above formula assumes constant acceleration. Since we use ACCEL_DEACCEL, we actually
// have acceleration to halfway then deceleration the rest. So the formula becomes:
// t = sqrt(d/a) * 2 (half the distance for accel, half for deaccel)
long settleDuration = (long) Math.sqrt(settleDistancePx / decelerationPxPerMs) * 4;
settleDuration = Math.max(MIN_SETTLE_DURATION, settleDuration);
// How much of the animation to devote to playing the overshoot (the rest is for settle).
float overshootFraction = (float) duration / (duration + settleDuration);
duration += settleDuration;
// Finally, create the interpolator, composed of two interpolators: an overshoot, which
// reaches end > 1, and then a settle to endProgress.
Interpolator overshoot = Interpolators.clampToProgress(DEACCEL, 0, overshootFraction);
// The settle starts at 1, where 1 is the top of the overshoot, and maps to a fraction
// such that final progress is endProgress. For example, if we overshot to 1.1 but want
// to end at 1, we need to map to 1/1.1.
Interpolator settle = Interpolators.clampToProgress(Interpolators.mapToProgress(
ACCEL_DEACCEL, 1, (endProgress - start) / (end - start)), overshootFraction, 1);
interpolator = t -> t <= overshootFraction
? overshoot.getInterpolation(t)
: settle.getInterpolation(t);
}
}
public static float mapRange(float value, float min, float max) {
return min + (value * (max - min));
}
public static float boundToRange(float value, float lowerBound, float upperBound) {
return Math.max(lowerBound, Math.min(value, upperBound));
}
}
================================================
FILE: animer/src/main/java/com/martinrgb/animer/component/overscroller/launcher3/OverScroller.java
================================================
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.martinrgb.animer.component.overscroller.launcher3;
import static com.martinrgb.animer.component.overscroller.launcher3.Interpolators.SCROLL;
import android.animation.TimeInterpolator;
import android.content.Context;
import android.hardware.SensorManager;
import android.util.Log;
import android.view.ViewConfiguration;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import androidx.dynamicanimation.animation.DynamicAnimation;
import androidx.dynamicanimation.animation.FloatPropertyCompat;
import androidx.dynamicanimation.animation.SpringAnimation;
import androidx.dynamicanimation.animation.SpringForce;
/**
* Based on {@link android.widget.OverScroller} supporting only 1-d scrolling and with more
* customization options.
*/
public class OverScroller {
private int mMode;
private final SplineOverScroller mScroller;
private TimeInterpolator mInterpolator;
private final boolean mFlywheel;
private static final int DEFAULT_DURATION = 250;
private static final int SCROLL_MODE = 0;
private static final int FLING_MODE = 1;
/**
* Creates an OverScroller with a viscous fluid scroll interpolator and flywheel.
* @param context
*/
public OverScroller(Context context) {
this(context, null);
}
/**
* Creates an OverScroller with flywheel enabled.
* @param context The context of this application.
* @param interpolator The scroll interpolator. If null, a default (viscous) interpolator will
* be used.
*/
public OverScroller(Context context, Interpolator interpolator) {
this(context, interpolator, true);
}
/**
* Creates an OverScroller.
* @param context The context of this application.
* @param interpolator The scroll interpolator. If null, a default (viscous) interpolator will
* be used.
* @param flywheel If true, successive fling motions will keep on increasing scroll speed.
*/
public OverScroller(Context context, Interpolator interpolator, boolean flywheel) {
if (interpolator == null) {
mInterpolator = SCROLL;
} else {
mInterpolator = interpolator;
}
mFlywheel = flywheel;
mScroller = new SplineOverScroller(context);
}
public void setInterpolator(TimeInterpolator interpolator) {
if (interpolator == null) {
mInterpolator = SCROLL;
} else {
mInterpolator = interpolator;
}
}
/**
* The amount of friction applied to flings. The default value
* is {@link ViewConfiguration#getScrollFriction}.
*
* @param friction A scalar dimension-less value representing the coefficient of
* friction.
*/
public final void setFriction(float friction) {
mScroller.setFriction(friction);
}
/**
*
* Returns whether the scroller has finished scrolling.
*
* @return True if the scroller has finished scrolling, false otherwise.
*/
public final boolean isFinished() {
return mScroller.mFinished;
}
/**
* Force the finished field to a particular value. Contrary to
* {@link #abortAnimation()}, forcing the animation to finished
* does NOT cause the scroller to move to the final x and y
* position.
*
* @param finished The new finished value.
*/
public final void forceFinished(boolean finished) {
mScroller.mFinished = finished;
}
/**
* Returns the current offset in the scroll.
*
* @return The new offset as an absolute distance from the origin.
*/
public final int getCurrPos() {
return mScroller.mCurrentPosition;
}
/**
* Returns the absolute value of the current velocity.
*
* @return The original velocity less the deceleration, norm of the X and Y velocity vector.
*/
public float getCurrVelocity() {
return mScroller.mCurrVelocity;
}
/**
* Returns the start offset in the scroll.
*
* @return The start offset as an absolute distance from the origin.
*/
public final int getStartPos() {
return mScroller.mStart;
}
/**
* Returns where the scroll will end. Valid only for "fling" scrolls.
*
* @return The final offset as an absolute distance from the origin.
*/
public final int getFinalPos() {
return mScroller.mFinal;
}
/**
* Returns how long the scroll event will take, in milliseconds.
*
* @return The duration of the scroll in milliseconds.
*/
public final int getDuration() {
return mScroller.mDuration;
}
/**
* Extend the scroll animation. This allows a running animation to scroll
* further and longer, when used with {@link #setFinalPos(int)}.
*
* @param extend Additional time to scroll in milliseconds.
* @see #setFinalPos(int)
*/
public void extendDuration(int extend) {
mScroller.extendDuration(extend);
}
/**
* Sets the final position for this scroller.
*
* @param newPos The new offset as an absolute distance from the origin.
* @see #extendDuration(int)
*/
public void setFinalPos(int newPos) {
mScroller.setFinalPosition(newPos);
}
/**
* Call this when you want to know the new location. If it returns true, the
* animation is not yet finished.
*/
public boolean computeScrollOffset() {
if (isFinished()) {
return false;
}
switch (mMode) {
case SCROLL_MODE:
if (isSpringing()) {
return true;
}
long time = AnimationUtils.currentAnimationTimeMillis();
// Any scroller can be used for time, since they were started
// together in scroll mode. We use X here.
final long elapsedTime = time - mScroller.mStartTime;
final int duration = mScroller.mDuration;
if (elapsedTime < duration) {
final float q = mInterpolator.getInterpolation(elapsedTime / (float) duration);
mScroller.updateScroll(q);
} else {
abortAnimation();
}
break;
case FLING_MODE:
if (!mScroller.mFinished) {
if (!mScroller.update()) {
if (!mScroller.continueWhenFinished()) {
mScroller.finish();
}
}
}
break;
}
return true;
}
/**
* Start scrolling by providing a starting point and the distance to travel.
* The scroll will use the default value of 250 milliseconds for the
* duration.
*
* @param start Starting horizontal scroll offset in pixels. Positive
* numbers will scroll the content to the left.
* @param delta Distance to travel. Positive numbers will scroll the
* content to the left.
*/
public void startScroll(int start, int delta) {
startScroll(start, delta, DEFAULT_DURATION);
}
/**
* Start scrolling by providing a starting point and the distance to travel.
*
* @param start Starting scroll offset in pixels. Positive
* numbers will scroll the content to the left.
* @param delta Distance to travel. Positive numbers will scroll the
* content to the left.
* @param duration Duration of the scroll in milliseconds.
*/
public void startScroll(int start, int delta, int duration) {
mMode = SCROLL_MODE;
mScroller.startScroll(start, delta, duration);
}
/**
* Start scrolling using a spring by providing a starting point and the distance to travel.
*
* @param start Starting scroll offset in pixels. Positive
* numbers will scroll the content to the left.
* @param delta Distance to travel. Positive numbers will scroll the
* content to the left.
* @param duration Duration of the scroll in milliseconds.
* @param velocity The starting velocity for the spring in px per ms.
*/
public void startScrollSpring(int start, int delta, int duration, float velocity) {
mMode = SCROLL_MODE;
mScroller.mState = mScroller.SPRING;
mScroller.startScroll(start, delta, duration, velocity);
}
/**
* Call this when you want to 'spring back' into a valid coordinate range.
*
* @param start Starting X coordinate
* @param min Minimum valid X value
* @param max Maximum valid X value
* @return true if a springback was initiated, false if startX and startY were
* already within the valid range.
*/
public boolean springBack(int start, int min, int max) {
mMode = FLING_MODE;
return mScroller.springback(start, min, max);
}
public void fling(int start, int velocity, int min, int max) {
fling(start, velocity, min, max, 0);
}
/**
* Start scrolling based on a fling gesture. The distance traveled will
* depend on the initial velocity of the fling.
* @param start Starting point of the scroll (X)
* @param velocity Initial velocity of the fling (X) measured in pixels per
* second.
* @param min Minimum X value. The scroller will not scroll past this point
* unless overX > 0. If overfling is allowed, it will use minX as
* a springback boundary.
* @param max Maximum X value. The scroller will not scroll past this point
* unless overX > 0. If overfling is allowed, it will use maxX as
* a springback boundary.
* @param over Overfling range. If > 0, horizontal overfling in either
* direction will be possible.
*/
public void fling(int start, int velocity, int min, int max, int over) {
// Continue a scroll or fling in progress
if (mFlywheel && !isFinished()) {
float oldVelocityX = mScroller.mCurrVelocity;
if (Math.signum(velocity) == Math.signum(oldVelocityX)) {
velocity += oldVelocityX;
}
}
mMode = FLING_MODE;
mScroller.fling(start, velocity, min, max, over);
}
/**
* Notify the scroller that we've reached a horizontal boundary.
* Normally the information to handle this will already be known
* when the animation is started, such as in a call to one of the
* fling functions. However there are cases where this cannot be known
* in advance. This function will transition the current motion and
* animate from startX to finalX as appropriate.
* @param start Starting/current X position
* @param finalPos Desired final X position
* @param over Magnitude of overscroll allowed. This should be the maximum
*/
public void notifyEdgeReached(int start, int finalPos, int over) {
mScroller.notifyEdgeReached(start, finalPos, over);
}
/**
* Returns whether the current Scroller is currently returning to a valid position.
* Valid bounds were provided by the
* {@link #fling(int, int, int, int, int)} method.
*
* One should check this value before calling
* {@link #startScroll(int, int)} as the interpolation currently in progress
* to restore a valid position will then be stopped. The caller has to take into account
* the fact that the started scroll will start from an overscrolled position.
*
* @return true when the current position is overscrolled and in the process of
* interpolating back to a valid value.
*/
public boolean isOverScrolled() {
return (!mScroller.mFinished && mScroller.mState != SplineOverScroller.SPLINE);
}
/**
* Stops the animation. Contrary to {@link #forceFinished(boolean)},
* aborting the animating causes the scroller to move to the final x and y
* positions.
*
* @see #forceFinished(boolean)
*/
public void abortAnimation() {
mScroller.finish();
}
/**
* Returns the time elapsed since the beginning of the scrolling.
*
* @return The elapsed time in milliseconds.
*
* @hide
*/
public int timePassed() {
final long time = AnimationUtils.currentAnimationTimeMillis();
return (int) (time - mScroller.mStartTime);
}
public boolean isSpringing() {
return mScroller.mState == SplineOverScroller.SPRING && !isFinished();
}
static class SplineOverScroller {
// Initial position
private int mStart;
// Current position
private int mCurrentPosition;
// Final position
private int mFinal;
// Initial velocity
private int mVelocity;
// Current velocity
private float mCurrVelocity;
// Constant current deceleration
private float mDeceleration;
// Animation starting time, in system milliseconds
private long mStartTime;
// Animation duration, in milliseconds
private int mDuration;
// Duration to complete spline component of animation
private int mSplineDuration;
// Distance to travel along spline animation
private int mSplineDistance;
// Whether the animation is currently in progress
private boolean mFinished;
// The allowed overshot distance before boundary is reached.
private int mOver;
// Fling friction
private float mFlingFriction = ViewConfiguration.getScrollFriction();
// Current state of the animation.
private int mState = SPLINE;
private SpringAnimation mSpring;
// Constant gravity value, used in the deceleration phase.
private static final float GRAVITY = 2000.0f;
// A context-specific coefficient adjusted to physical values.
private float mPhysicalCoeff;
private static float DECELERATION_RATE = (float) (Math.log(0.78) / Math.log(0.9));
private static final float INFLEXION = 0.35f; // Tension lines cross at (INFLEXION, 1)
private static final float START_TENSION = 0.5f;
private static final float END_TENSION = 1.0f;
private static final float P1 = START_TENSION * INFLEXION;
private static final float P2 = 1.0f - END_TENSION * (1.0f - INFLEXION);
private static final int NB_SAMPLES = 100;
private static final float[] SPLINE_POSITION = new float[NB_SAMPLES + 1];
private static final float[] SPLINE_TIME = new float[NB_SAMPLES + 1];
private static final int SPLINE = 0;
private static final int CUBIC = 1;
private static final int BALLISTIC = 2;
private static final int SPRING = 3;
private static final FloatPropertyCompat<SplineOverScroller> SPRING_PROPERTY =
new FloatPropertyCompat<SplineOverScroller>("splineOverScrollerSpring") {
@Override
public float getValue(SplineOverScroller scroller) {
return scroller.mCurrentPosition;
}
@Override
public void setValue(SplineOverScroller scroller, float value) {
scroller.mCurrentPosition = (int) value;
}
};
static {
float x_min = 0.0f;
float y_min = 0.0f;
for (int i = 0; i < NB_SAMPLES; i++) {
final float alpha = (float) i / NB_SAMPLES;
float x_max = 1.0f;
float x, tx, coef;
while (true) {
x = x_min + (x_max - x_min) / 2.0f;
coef = 3.0f * x * (1.0f - x);
tx = coef * ((1.0f - x) * P1 + x * P2) + x * x * x;
if (Math.abs(tx - alpha) < 1E-5) break;
if (tx > alpha) x_max = x;
else x_min = x;
}
SPLINE_POSITION[i] = coef * ((1.0f - x) * START_TENSION + x) + x * x * x;
float y_max = 1.0f;
float y, dy;
while (true) {
y = y_min + (y_max - y_min) / 2.0f;
coef = 3.0f * y * (1.0f - y);
dy = coef * ((1.0f - y) * START_TENSION + y) + y * y * y;
if (Math.abs(dy - alpha) < 1E-5) break;
if (dy > alpha) y_max = y;
else y_min = y;
}
SPLINE_TIME[i] = coef * ((1.0f - y) * P1 + y * P2) + y * y * y;
}
SPLINE_POSITION[NB_SAMPLES] = SPLINE_TIME[NB_SAMPLES] = 1.0f;
}
void setFriction(float friction) {
mFlingFriction = friction;
}
SplineOverScroller(Context context) {
mFinished = true;
final float ppi = context.getResources().getDisplayMetrics().density * 160.0f;
mPhysicalCoeff = SensorManager.GRAVITY_EARTH // g (m/s^2)
* 39.37f // inch/meter
* ppi
* 0.84f; // look and feel tuning
}
void updateScroll(float q) {
if (mState == SPRING) {
return;
}
mCurrentPosition = mStart + Math.round(q * (mFinal - mStart));
}
/*
* Get a signed deceleration that will reduce the velocity.
*/
static private float getDeceleration(int velocity) {
return velocity > 0 ? -GRAVITY : GRAVITY;
}
/*
* Modifies mDuration to the duration it takes to get from start to newFinal using the
* spline interpolation. The previous duration was needed to get to oldFinal.
*/
private void adjustDuration(int start, int oldFinal, int newFinal) {
final int oldDistance = oldFinal - start;
final int newDistance = newFinal - start;
final float x = Math.abs((float) newDistance / oldDistance);
final int index = (int) (NB_SAMPLES * x);
if (index < NB_SAMPLES) {
final float x_inf = (float) index / NB_SAMPLES;
final float x_sup = (float) (index + 1) / NB_SAMPLES;
final float t_inf = SPLINE_TIME[index];
final float t_sup = SPLINE_TIME[index + 1];
final float timeCoef = t_inf + (x - x_inf) / (x_sup - x_inf) * (t_sup - t_inf);
mDuration *= timeCoef;
}
}
void startScroll(int start, int distance, int duration) {
startScroll(start, distance, duration, 0);
}
void startScroll(int start, int distance, int duration, float velocity) {
mFinished = false;
mCurrentPosition = mStart = start;
mFinal = start + distance;
mStartTime = AnimationUtils.currentAnimationTimeMillis();
mDuration = duration;
if (mState == SPRING) {
if (mSpring != null) {
mSpring.cancel();
}
mSpring = new SpringAnimation(this, SPRING_PROPERTY);
mSpring.setSpring(new SpringForce(mFinal)
.setStiffness(SpringForce.STIFFNESS_LOW)
.setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY));
mSpring.setStartVelocity(velocity);
mSpring.animateToFinalPosition(mFinal);
mSpring.addEndListener((animation, canceled, value, velocity1) -> {
finish();
mState = SPLINE;
mSpring = null;
});
}
// Unused
mDeceleration = 0.0f;
mVelocity = 0;
}
void finish() {
if (mSpring != null && mSpring.isRunning()) mSpring.cancel();
mCurrentPosition = mFinal;
// Not reset since WebView relies on this value for fast fling.
// TODO: restore when WebView uses the fast fling implemented in this class.
// mCurrVelocity = 0.0f;
mFinished = true;
}
void setFinalPosition(int position) {
mFinal = position;
if (mState == SPRING && mSpring != null) {
mSpring.animateToFinalPosition(mFinal);
}
mSplineDistance = mFinal - mStart;
mFinished = false;
}
void extendDuration(int extend) {
final long time = AnimationUtils.currentAnimationTimeMillis();
final int elapsedTime = (int) (time - mStartTime);
mDuration = mSplineDuration = elapsedTime + extend;
mFinished = false;
}
boolean springback(int start, int min, int max) {
mFinished = true;
mCurrentPosition = mStart = mFinal = start;
mVelocity = 0;
mStartTime = AnimationUtils.currentAnimationTimeMillis();
mDuration = 0;
if (start < min) {
startSpringback(start, min, 0);
} else if (start > max) {
startSpringback(start, max, 0);
}
return !mFinished;
}
private void startSpringback(int start, int end, int velocity) {
// mStartTime has been set
mFinished = false;
mState = CUBIC;
mCurrentPosition = mStart = start;
mFinal = end;
final int delta = start - end;
mDeceleration = getDeceleration(delta);
// TODO take velocity into account
mVelocity = -delta; // only sign is used
mOver = Math.abs(delta);
mDuration = (int) (1000.0 * Math.sqrt(-2.0 * delta / mDeceleration));
}
void fling(int start, int velocity, int min, int max, int over) {
mOver = over;
mFinished = false;
mCurrVelocity = mVelocity = velocity;
mDuration = mSplineDuration = 0;
mStartTime = AnimationUtils.currentAnimationTimeMillis();
mCurrentPosition = mStart = start;
if (start > max || start < min) {
startAfterEdge(start, min, max, velocity);
return;
}
mState = SPLINE;
double totalDistance = 0.0;
if (velocity != 0) {
mDuration = mSplineDuration = getSplineFlingDuration(velocity);
totalDistance = getSplineFlingDistance(velocity);
}
mSplineDistance = (int) (totalDistance * Math.signum(velocity));
mFinal = start + mSplineDistance;
// Clamp to a valid final position
if (mFinal < min) {
adjustDuration(mStart, mFinal, min);
mFinal = min;
}
if (mFinal > max) {
adjustDuration(mStart, mFinal, max);
mFinal = max;
}
}
private double getSplineDeceleration(int velocity) {
return Math.log(INFLEXION * Math.abs(velocity) / (mFlingFriction * mPhysicalCoeff));
}
private double getSplineFlingDistance(int velocity) {
final double l = getSplineDeceleration(velocity);
final double decelMinusOne = DECELERATION_RATE - 1.0;
return mFlingFriction * mPhysicalCoeff * Math.exp(DECELERATION_RATE / decelMinusOne * l);
}
/* Returns the duration, expressed in milliseconds */
private int getSplineFlingDuration(int velocity) {
final double l = getSplineDeceleration(velocity);
final double decelMinusOne = DECELERATION_RATE - 1.0;
return (int) (1000.0 * Math.exp(l / decelMinusOne));
}
private void fitOnBounceCurve(int start, int end, int velocity) {
// Simulate a bounce that started from edge
final float durationToApex = - velocity / mDeceleration;
// The float cast below is necessary to avoid integer overflow.
final float velocitySquared = (float) velocity * velocity;
final float distanceToApex = velocitySquared / 2.0f / Math.abs(mDeceleration);
final float distanceToEdge = Math.abs(end - start);
final float totalDuration = (float) Math.sqrt(
2.0 * (distanceToApex + distanceToEdge) / Math.abs(mDeceleration));
mStartTime -= (int) (1000.0f * (totalDuration - durationToApex));
mCurrentPosition = mStart = end;
mVelocity = (int) (- mDeceleration * totalDuration);
}
private void startBounceAfterEdge(int start, int end, int velocity) {
mDeceleration = getDeceleration(velocity == 0 ? start - end : velocity);
fitOnBounceCurve(start, end, velocity);
onEdgeReached();
}
private void startAfterEdge(int start, int min, int max, int velocity) {
if (start > min && start < max) {
Log.e("OverScroller", "startAfterEdge called from a valid position");
mFinished = true;
return;
}
final boolean positive = start > max;
final int edge = positive ? max : min;
final int overDistance = start - edge;
boolean keepIncreasing = overDistance * velocity >= 0;
if (keepIncreasing) {
// Will result in a bounce or a to_boundary depending on velocity.
startBounceAfterEdge(start, edge, velocity);
} else {
final double totalDistance = getSplineFlingDistance(velocity);
if (totalDistance > Math.abs(overDistance)) {
fling(start, velocity, positive ? min : start, positive ? start : max, mOver);
} else {
startSpringback(start, edge, velocity);
}
}
}
void notifyEdgeReached(int start, int end, int over) {
// mState is used to detect successive notifications
if (mState == SPLINE) {
mOver = over;
mStartTime = AnimationUtils.currentAnimationTimeMillis();
// We were in fling/scroll mode before: current velocity is such that distance to
// edge is increasing. This ensures that startAfterEdge will not start a new fling.
startAfterEdge(start, end, end, (int) mCurrVelocity);
}
}
private void onEdgeReached() {
// mStart, mVelocity and mStartTime were adjusted to their values when edge was reached.
// The float cast below is necessary to avoid integer overflow.
final float velocitySquared = (float) mVelocity * mVelocity;
float distance = velocitySquared / (2.0f * Math.abs(mDeceleration));
final float sign = Math.signum(mVelocity);
if (distance > mOver) {
// Default deceleration is not sufficient to slow us down before boundary
mDeceleration = - sign * velocitySquared / (2.0f * mOver);
distance = mOver;
}
mOver = (int) distance;
mState = BALLISTIC;
mFinal = mStart + (int) (mVelocity > 0 ? distance : -distance);
mDuration = - (int) (1000.0f * mVelocity / mDeceleration);
}
boolean continueWhenFinished() {
switch (mState) {
case SPLINE:
// Duration from start to null velocity
if (mDuration < mSplineDuration) {
// If the animation was clamped, we reached the edge
mCurrentPosition = mStart = mFinal;
// TODO Better compute speed when edge was reached
mVelocity = (int) mCurrVelocity;
mDeceleration = getDeceleration(mVelocity);
mStartTime += mDuration;
onEdgeReached();
} else {
// Normal stop, no need to continue
return false;
}
break;
case BALLISTIC:
mStartTime += mDuration;
startSpringback(mFinal, mStart, 0);
break;
case CUBIC:
return false;
}
update();
return true;
}
/*
* Update the current position and velocity for current time. Returns
* true if update has been done and false if animation duration has been
* reached.
*/
boolean update() {
if (mState == SPRING) {
return mFinished;
}
final long time = AnimationUtils.currentAnimationTimeMillis();
final long currentTime = time - mStartTime;
if (currentTime == 0) {
// Skip work but report that we're still going if we have a nonzero duration.
return mDuration > 0;
}
if (currentTime > mDuration) {
return false;
}
double distance = 0.0;
switch (mState) {
case SPLINE: {
final float t = (float) currentTime / mSplineDuration;
final int index = (int) (NB_SAMPLES * t);
float distanceCoef = 1.f;
float velocityCoef = 0.f;
if (index < NB_SAMPLES) {
final float t_inf = (float) index / NB_SAMPLES;
final float t_sup = (float) (index + 1) / NB_SAMPLES;
final float d_inf = SPLINE_POSITION[index];
final float d_sup = SPLINE_POSITION[index + 1];
velocityCoef = (d_sup - d_inf) / (t_sup - t_inf);
distanceCoef = d_inf + (t - t_inf) * velocityCoef;
}
distance = distanceCoef * mSplineDistance;
mCurrVelocity = velocityCoef * mSplineDistance / mSplineDuration * 1000.0f;
break;
}
case BALLISTIC: {
final float t = currentTime / 1000.0f;
mCurrVelocity = mVelocity + mDeceleration * t;
distance = mVelocity * t + mDeceleration * t * t / 2.0f;
break;
}
case CUBIC: {
final float t = (float) (currentTime) / mDuration;
final float t2 = t * t;
final float sign = Math.signum(mVelocity);
distance = sign * mOver * (3.0f * t2 - 2.0f * t * t2);
mCurrVelocity = sign * mOver * 6.0f * (- t + t2);
break;
}
}
mCurrentPosition = mStart + (int) Math.round(distance);
return true;
}
}
}
================================================
FILE: animer/src/main/java/com/martinrgb/animer/component/overscrolllayout/.gitkeep
================================================
================================================
FILE: animer/src/main/java/com/martinrgb/animer/component/recyclerview/AnRecyclerView.java
================================================
package com.martinrgb.animer.component.recyclerview;
import android.content.Context;
import android.content.res.Resources;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.ViewConfiguration;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.StaggeredGridLayoutManager;
import com.martinrgb.animer.Animer;
public class AnRecyclerView extends RecyclerView {
private Context mContext;
private RecyclerView mRecyclerView;
private RecyclerView.Adapter mAdapter;
private LayoutManager mLayoutManager;
private boolean mIsRootOnTouch = false;
private int mTouchSlop,mMinFlingVelocity;
private Animer mFlingAnimer, mSpringAnimer;
private boolean mShouldFling = true,mShouldSpringBack = true;
private float mRootCurrentTransValue,mDragStartValue,mCurrentVelocity,mPrevFrameValue,mFlingStartVelocity,mFlingCurrentVelocity;
private VelocityTracker mRootVelocityTracker;
public AnRecyclerView(Context context) {
super(context);
init(context, null);
}
public AnRecyclerView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public AnRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context, attrs);
}
@Override
public void setAdapter(RecyclerView.Adapter adapter) {
mAdapter = adapter;
super.setAdapter(adapter);
}
private static final int LINEAR_LAYOUT = 0;
private static final int GRID_LAYOUT = 1;
private static final int STAGGERED_LAYOUT=2;
private int LAYOUT_MODE = 0;
@Override
public void setLayoutManager(LayoutManager layout) {
if(layout instanceof LinearLayoutManager){
LAYOUT_MODE = LINEAR_LAYOUT;
}
if(layout instanceof GridLayoutManager){
LAYOUT_MODE = GRID_LAYOUT;
}
if(layout instanceof StaggeredGridLayoutManager){
LAYOUT_MODE = STAGGERED_LAYOUT;
}
mLayoutManager = layout;
super.setLayoutManager(layout);
}
@Override
public void scrollToPosition(int position) {
super.scrollToPosition(position);
}
@Override
public void smoothScrollToPosition(int position) {
super.smoothScrollToPosition(position);
}
private void init(Context context, AttributeSet attributeSet) {
// Custom Attribute in XML
// if (context != null && attributeSet != null) {
// TypedArray a = context.getTheme().obtainStyledAttributes(
// attributeSet, R.styleable.RecyclerViewBouncy,
// 0, 0
// );
// }
setOverScrollMode(OVER_SCROLL_NEVER);
mContext = context;
mRecyclerView = this;
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
mMinFlingVelocity = ViewConfiguration.get(context).getScaledMinimumFlingVelocity();
scrollToPosition(0);
initOnScrollListener();
initTouchListener();
initAnimer();
}
private void initAnimer(){
mFlingAnimer = new Animer();
mFlingAnimer.setSolver(Animer.flingDroid(0,0.5f));
// velocity is 1000ms velocity/60 is frame velocity;
mFlingAnimer.setMinimumVisibleChange(1f);
mFlingAnimer.setUpdateListener(new Animer.UpdateListener() {
@Override
public void onUpdate(float value, float velocity, float progress) {
if(directionVertical()){
if(mRecyclerView.getTranslationY() < 0){
mRecyclerView.setTranslationY(Math.max(0,mRecyclerView.getTranslationY() - velocity/(1000/16)));
}
else if(mRecyclerView.getTranslationY() > 0){
mRecyclerView.setTranslationY(Math.min(0,mRecyclerView.getTranslationY() - velocity/(1000/16)));
}
else {
mRecyclerView.scrollBy( 0, (int) velocity/(1000/16));
}
}
if(!directionVertical()) {
if(mRecyclerView.getTranslationX() < 0){
mRecyclerView.setTranslationX(Math.max(0,mRecyclerView.getTranslationX() - velocity/(1000/16)));
}
else if(mRecyclerView.getTranslationX() > 0){
mRecyclerView.setTranslationX(Math.min(0,mRecyclerView.getTranslationX() - velocity/(1000/16)));
}
else {
mRecyclerView.scrollBy((int) velocity/(1000/16), 0);
}
}
mFlingCurrentVelocity = velocity;
}
});
mSpringAnimer = new Animer();
mSpringAnimer.setSolver(Animer.springDroid(150,0.99f));
mSpringAnimer.setMinimumVisibleChange(1f);
mSpringAnimer.setUpdateListener(new Animer.UpdateListener() {
@Override
public void onUpdate(float value, float velocity, float progress) {
if(directionVertical()){
mRecyclerView.setTranslationY(value);
}
else {
mRecyclerView.setTranslationX(value);
}
}
});
}
private void initOnScrollListener() {
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
// top springback
if(directionVertical() && !recyclerView.canScrollVertically(-1)){
if(mShouldFling){
mSpringAnimer.setVelocity(-mFlingCurrentVelocity);
mFlingAnimer.cancel();
mSpringAnimer.setEndValue(0);
mShouldFling = false;
}
}
// bottom springBack
if(directionVertical() && !recyclerView.canScrollVertically(1)){
if(mShouldFling){
mSpringAnimer.setVelocity(-mFlingCurrentVelocity);
mFlingAnimer.cancel();
mSpringAnimer.setEndValue(0);
mShouldFling = false;
}
}
// left springBack
if(!directionVertical() && !recyclerView.canScrollHorizontally(-1)){
if(mShouldFling){
mSpringAnimer.setVelocity(-mFlingCurrentVelocity);
mFlingAnimer.cancel();
mSpringAnimer.setEndValue(0);
mShouldFling = false;
}
}
// right springBack
if(!directionVertical() && !recyclerView.canScrollHorizontally(1)){
if(mShouldFling){
mSpringAnimer.setVelocity(-mFlingCurrentVelocity);
mFlingAnimer.cancel();
mSpringAnimer.setEndValue(0);
mShouldFling = false;
}
}
}
});
}
private void initTouchListener() {
mRecyclerView.addOnItemTouchListener(new RecyclerView.SimpleOnItemTouchListener() {
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
switch (e.getAction()) {
case MotionEvent.ACTION_DOWN:
// add vt
if (mRootVelocityTracker == null) { mRootVelocityTracker = VelocityTracker.obtain(); }
else { mRootVelocityTracker.clear();}
mRootVelocityTracker.addMovement(e);
// reset val
mDragStartValue = (directionVertical())?e.getRawY():e.getRawX();
mPrevFrameValue = (directionVertical())?e.getRawY():e.getRawX();
mCurrentVelocity = 0;
mFlingStartVelocity = 0;
mRootCurrentTransValue = (directionVertical())?mRecyclerView.getTranslationY():mRecyclerView.getTranslationX();
rv.stopScroll();
// Method-I ,but when spring is not easy to click,
// detect is interact on root or item
// if(!mFlingAnimer.isRunning() && !mSpringAnimer.isRunning()){
// Log.e("isNotRunning","isNotRunning");
// mIsRootOnTouch = false;
// }
//
// if(mFlingAnimer.isRunning() || mSpringAnimer.isRunning()){
// Log.e("isRunning","is Running");
// mFlingAnimer.cancel();
// mSpringAnimer.cancel();
// mIsRootOnTouch = true;
// }
// Method-II
if(!mFlingAnimer.isRunning()){
mIsRootOnTouch = false;
}
if(mFlingAnimer.isRunning()){
mFlingAnimer.cancel();
mIsRootOnTouch = true;
}
if(mSpringAnimer.isRunning()){
mSpringAnimer.cancel();
// disable this for rapid click when spring is running
//mIsRootOnTouch = true;
}
break;
case MotionEvent.ACTION_MOVE:
float mCurrentVal = ((directionVertical())?e.getRawY():e.getRawX());
float mAbsTransValue = Math.abs( mCurrentVal - mPrevFrameValue );
// if TouchMove bigger than slop,group action
// Method -I - mMinFlingVelocity , Method - II - mTouchSlop
if( mAbsTransValue > mTouchSlop){
mIsRootOnTouch = true;
}
// if TouchMove smaller than slop,group action
else {
mIsRootOnTouch = false;
}
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
// OverRangeScroll -> SpringBack
mSpringAnimer.setFrom((directionVertical())?mRecyclerView.getTranslationY():mRecyclerView.getTranslationX());
mSpringAnimer.setEndValue(0);
break;
}
return mIsRootOnTouch;
}
@Override
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
mIsRootOnTouch = false;
switch (e.getAction()) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_MOVE:
float dragValue = overDragFucntion(((directionVertical())?e.getRawY():e.getRawX()) - mDragStartValue);
float mTransValue = mRootCurrentTransValue + dragValue;
mRootVelocityTracker.addMovement(e);
mRootVelocityTracker.computeCurrentVelocity(1000);
mFlingStartVelocity = (directionVertical())? mRootVelocityTracker.getYVelocity(): mRootVelocityTracker.getXVelocity();
// top overscroll
if(directionVertical() && mTransValue > 0 && !rv.canScrollVertically(-1)){
mRecyclerView.setTranslationY(mTransValue);//3
mShouldSpringBack = (mFlingStartVelocity >= 0)? true:false;
}
// bottom overscroll
else if(directionVertical() && mTransValue < 0 && !rv.canScrollVertically(1)){
mRecyclerView.setTranslationY(mTransValue); //3
mShouldSpringBack = (mFlingStartVelocity <= 0)? true:false;
}
// left overscroll
else if(!directionVertical() && mTransValue > 0 && !rv.canScrollHorizontally(-1)){
mRecyclerView.setTranslationX(mTransValue); //3
mShouldSpringBack = (mFlingStartVelocity >= 0)? true:false;
}
// right overscroll
else if(!directionVertical() && mTransValue < 0 && !rv.canScrollHorizontally(1)){
mRecyclerView.setTranslationX(mTransValue); //3
mShouldSpringBack = (mFlingStartVelocity <= 0)? true:false;
}
// normal scroll
else{
scrollBy((int)-mCurrentVelocity);
mShouldSpringBack = false;
}
mCurrentVelocity = ((directionVertical())?e.getRawY():e.getRawX()) - mPrevFrameValue;
mPrevFrameValue = ((directionVertical())?e.getRawY():e.getRawX());
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
// OverRangeScroll -> SpringBack
if(mShouldSpringBack){
mSpringAnimer.setFrom((directionVertical())?mRecyclerView.getTranslationY():mRecyclerView.getTranslationX());
mSpringAnimer.setEndValue(0);
}
// Scroll -> Fling
else {
// if velocity greter than Min Fling Vel,then Fling
if(Math.abs(mFlingStartVelocity) > mMinFlingVelocity){
// Method-II
if(mSpringAnimer.isRunning()){
mSpringAnimer.cancel();
}
mShouldFling = true;
mFlingAnimer.setArgument1(-mFlingStartVelocity);
mFlingAnimer.start();
}
// otherwise SpringBack
else {
mSpringAnimer.setFrom((directionVertical()) ? mRecyclerView.getTranslationY() : mRecyclerView.getTranslationX());
mSpringAnimer.setEndValue(0);
}
}
break;
}
}
});
}
private float overDragFucntion(float value){
return value/3;
}
private void scrollBy(int dist) {
if (directionVertical()) {
mRecyclerView.scrollBy(0, dist);
} else {
mRecyclerView.scrollBy(dist, 0);
}
}
private boolean directionVertical() {
switch (LAYOUT_MODE){
case LINEAR_LAYOUT:
return ((LinearLayoutManager)mLayoutManager).getOrientation() == RecyclerView.VERTICAL;
case GRID_LAYOUT:
return ((GridLayoutManager)mLayoutManager).getOrientation() == RecyclerView.VERTICAL;
case STAGGERED_LAYOUT:
return ((StaggeredGridLayoutManager)mLayoutManager).getOrientation() == RecyclerView.VERTICAL;
}
return true;
}
private double dpToPx(double dp) {
Resources resources = mContext.getResources();
DisplayMetrics metrics = resources.getDisplayMetrics();
return dp * ((double) metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT);
}
}
================================================
FILE: animer/src/main/java/com/martinrgb/animer/component/scrollview/AnOverScroller.java
================================================
package com.martinrgb.animer.component.scrollview;
import android.content.Context;
import android.util.Log;
import android.view.animation.Interpolator;
import androidx.dynamicanimation.animation.DynamicAnimation;
import androidx.dynamicanimation.animation.FlingAnimation;
import androidx.dynamicanimation.animation.FloatValueHolder;
import androidx.dynamicanimation.animation.SpringAnimation;
import androidx.dynamicanimation.animation.SpringForce;
import com.martinrgb.animer.Animer;
import com.martinrgb.animer.core.math.calculator.FlingCalculator;
public class AnOverScroller {
private FlingAnimation flingAnimation;
private SpringAnimation springAnimation;
private Animer flingAnimer,springAnimer,flingSpringAnimer,scrollAnimer;
private FloatValueHolder scrollValue,scrollSpeed;
private boolean isDyanmicFling = false,isVertScroll = true,isFixedScroll = false;
private float fixedCellWidth = 0;
private final Animer.AnimerSolver defaultSpring = Animer.springDroid(150,0.99f);
private final Animer.AnimerSolver defaultFling = Animer.flingDroid(4000,0.8f);
private final Animer.AnimerSolver springAsFling = Animer.springDroid(50,0.99f);
private boolean isFling = true;
private boolean isSpringBack = true;
private boolean isAnimerDriven = true;
// ############################################
// Constructor
// ############################################
public AnOverScroller(Context context) {
this(context, null);
}
public AnOverScroller(Context context, Interpolator interpolator) {this(context, interpolator, true);}
public AnOverScroller(Context context, Interpolator interpolator,float bounceCoefficientX, float bounceCoefficientY) {this(context, interpolator, true); }
public AnOverScroller(Context context, Interpolator interpolator, float bounceCoefficientX, float bounceCoefficientY, boolean flywheel) { this(context, interpolator, flywheel); }
public AnOverScroller(Context context, Interpolator interpolator, boolean flywheel) {
if(!isAnimerDriven()){
springAnimer = new Animer();
springAnimer.setSolver(defaultSpring);
flingAnimer = new Animer();
flingAnimer.setSolver(defaultFling);
flingSpringAnimer = new Animer();
flingSpringAnimer.setSolver(springAsFling);
scrollValue = new FloatValueHolder();
scrollSpeed = new FloatValueHolder();
scrollValue.setValue(0);
flingAnimation = new FlingAnimation(scrollValue);
flingAnimation.setFriction((float)flingAnimer.getArgument2());
flingAnimation.addUpdateListener(new DynamicAnimation.OnAnimationUpdateListener() {
@Override
public void onAnimationUpdate(DynamicAnimation animation, float value, float velocity) {
scrollSpeed.setValue(velocity);
}
});
springAnimation = new SpringAnimation(scrollValue);
springAnimation.setSpring(new SpringForce());
springAnimation.getSpring().setStiffness((float)springAnimer.getArgument1());
springAnimation.getSpring().setDampingRatio((float)springAnimer.getArgument2());
springAnimation.addUpdateListener(new DynamicAnimation.OnAnimationUpdateListener() {
@Override
public void onAnimationUpdate(DynamicAnimation animation, float value, float velocity) {
if(isSpringBack()){
setSpringBack(false);
}
scrollSpeed.setValue(velocity);
}
});
springAnimation.addEndListener(new DynamicAnimation.OnAnimationEndListener() {
@Override
public void onAnimationEnd(DynamicAnimation animation, boolean canceled, float value, float velocity) {
setSpringBack(true);
scrollSpeed.setValue(0);
}
});
}
if(isAnimerDriven()){
scrollValue = new FloatValueHolder();
scrollSpeed = new FloatValueHolder();
scrollValue.setValue(0);
springAnimer = new Animer();
springAnimer.setSolver(defaultSpring);
flingSpringAnimer = new Animer();
flingSpringAnimer.setSolver(springAsFling);
flingAnimer = new Animer();
flingAnimer.setSolver(defaultFling);
scrollAnimer = new Animer(scrollValue.getValue());
scrollAnimer.setArgument1(springAnimer.getArgument1());
scrollAnimer.setArgument2(springAnimer.getArgument2());
scrollAnimer.setUpdateListener(new Animer.UpdateListener() {
@Override
public void onUpdate(float value, float velocity, float progress) {
if(isSpringBack()){
setSpringBack(false);
}
scrollValue.setValue(value);
scrollSpeed.setValue(velocity);
}
});
scrollAnimer.setEndListener(new Animer.EndListener() {
@Override
public void onEnd(float value, float velocity, boolean canceled) {
setSpringBack(true);
scrollValue.setValue(value);
scrollSpeed.setValue(0);
}
});
}
}
// ############################################
// Value Getter
// ############################################
public final int getCurrX() {
return (isVertScroll())?0:Math.round(scrollValue.getValue());
}
public final int getCurrY() {
return (isVertScroll())?Math.round(scrollValue.getValue()):0;
}
public float getCurrVelocityY() {
return (isVertScroll())?scrollSpeed.getValue():0;
}
public float getCurrVelocityX() {
return (isVertScroll())?0:scrollSpeed.getValue();
}
public void startScroll(int startX, int startY, int dx, int dy) {
scrollValue.setValue((isVertScroll())?startY:startX);
}
public boolean computeScrollOffset() {
return (!isAnimerDriven())?(flingAnimation.isRunning() || springAnimation.isRunning()):scrollAnimer.isRunning();
}
public final boolean isFinished() {
return (!isAnimerDriven())?!(flingAnimation.isRunning() || springAnimation.isRunning()):!scrollAnimer.isRunning();
}
public void abortAnimation() {
if(!isAnimerDriven()){
springAnimation.cancel();
flingAnimation.cancel();
}
if(isAnimerDriven()) {
scrollAnimer.cancel();
}
}
// ############################################
// SpringBack Functions
// ############################################
public boolean springBack(int startX, int startY, int velocityX,int velocityY,int minX, int maxX, int minY, int maxY) {
float start = (isVertScroll())?startY:startX;
float min = (isVertScroll())?minY:minX;
float max = (isVertScroll())?maxY:maxX;
if (start > max || start < min) {
if (!isAnimerDriven() && !isFixedScroll()) {
if (isFling()) {
flingAnimation.cancel();
setFling(false);
}
if (isSpringBack()) {
springFunctions(start, min, max);
}
}
if (!isAnimerDriven() && isFixedScroll()) {
if (isFling()) {
float tempSpeed = scrollSpeed.getValue();
springAnimation.cancel();
scrollSpeed.setValue(tempSpeed);
setFling(false);
}
if (isSpringBack()) {
springFunctions(start, min, max);
}
}
if (isAnimerDriven() && !isFixedScroll()) {
if (isFling()) {
float tempSpeed = scrollSpeed.getValue();
scrollAnimer.cancel();
scrollSpeed.setValue(tempSpeed);
setFling(false);
}
if (isSpringBack()) {
springFunctions(start, min, max);
}
}
if (isAnimerDriven() && isFixedScroll()) {
if (isFling()) {
float tempSpeed = scrollSpeed.getValue();
scrollAnimer.cancel();
scrollSpeed.setValue(tempSpeed);
setFling(false);
}
if (isSpringBack()) {
springFunctions(start, min, max);
}
}
return true;
}
return true;
}
private void springFunctions(float val,float min,float max){
if(!isAnimerDriven()){
scrollValue.setValue(val);
springAnimation.setStartValue(val);
springAnimation.setStartVelocity(scrollSpeed.getValue());
springAnimation.getSpring().setFinalPosition(((val > max))?max:min);
springAnimation.getSpring().setStiffness((float)springAnimer.getArgument1());
springAnimation.getSpring().setDampingRatio((float)springAnimer.getArgument2());
springAnimation.start();
}else {
scrollAnimer.setSolver(springAnimer.getCurrentSolver());
// setFrom - setCurrenetPhysicsValue();
// setVelocity - setCurrenetPhysicsVelocity();
// start() - setStartValue(getCurrentPhysicsValue())|setStartVelocity(getCurrentPhysicsVelocity())
scrollAnimer.setFrom(val);
scrollAnimer.setTo(((val > max))?max:min);
scrollAnimer.setVelocity(scrollSpeed.getValue());
scrollAnimer.start();
}
}
// ############################################
// Fling Functions
// ############################################
public void fling(int startX, int startY, int velocityX, int velocityY,
int minX, int maxX, int minY, int maxY, int overX, int overY) {
setFling(true);
setSpringBack(true);
float startVelocity = (isVertScroll())?velocityY:velocityX;
float startValue = (isVertScroll())?startY:startX;
if (!isAnimerDriven() && !isFixedScroll()) {
scrollValue.setValue(startValue);
flingAnimation.setStartVelocity(startVelocity);
if (isDynamicFlingFriction()) {
float dynamicDamping = (isVertScroll()) ? (float) mapValueFromRangeToRange(Math.abs(velocityY), 0, 24000, 1.35, 0.5) : (float) mapValueFromRangeToRange(Math.abs(velocityX), 0, 24000, 1.35, 0.5);
flingAnimation.setFriction(dynamicDamping);
} else {
flingAnimation.setFriction((float) flingAnimer.getArgument2());
}
flingAnimation.start();
}
if (!isAnimerDriven() && isFixedScroll()) {
FlingCalculator flingCalculator = new FlingCalculator(startVelocity, (float) flingAnimer.getArgument2());
float flingTransition = flingCalculator.getTransiton();
springAnimation.setStartVelocity(startVelocity);
scrollValue.setValue(startValue);
springAnimation.setStartValue(startValue);
float roundValue = Math.round(((startValue + flingTransition) / fixedCellWidth)) * fixedCellWidth;
springAnimation.getSpring().setFinalPosition(roundValue);
springAnimation.getSpring().setStiffness((float) flingSpringAnimer.getArgument1());
springAnimation.getSpring().setDampingRatio((float) flingSpringAnimer.getArgument2());
springAnimation.start();
}
//TODO
if (isAnimerDriven() && !isFixedScroll()) {
scrollAnimer.setSolver(flingAnimer.getCurrentSolver());
scrollAnimer.setFrom(startValue);
scrollAnimer.setVelocity(startVelocity);
scrollAnimer.setArgument1((float)startVelocity);
if(isDynamicFlingFriction()){
float dynamicDamping = (isVertScroll()) ? (float) mapValueFromRangeToRange(Math.abs(velocityY), 0, 24000, 1.35, 0.5) : (float) mapValueFromRangeToRange(Math.abs(velocityX), 0, 24000, 1.35, 0.5);;
scrollAnimer.setArgument2((float)dynamicDamping);
}
else {
//flingAnimation.setFriction((float)flingAnimer.getArgument2());
}
scrollAnimer.start();
}
//TODO
if (isAnimerDriven() && isFixedScroll()) {
scrollAnimer.cancel();
scrollAnimer.setSolver(flingSpringAnimer.getCurrentSolver());
FlingCalculator flingCalculator = new FlingCalculator(startVelocity,(float)flingAnimer.getArgument2());
float flingTransition = flingCalculator.getTransiton();
float roundValue = Math.round(((startValue + flingTransition)/fixedCellWidth))*fixedCellWidth;
scrollAnimer.setFrom(startValue);
scrollAnimer.setTo(roundValue);
scrollAnimer.setVelocity(startVelocity);
scrollAnimer.start();
}
}
// ############################################
// Utils
// ############################################
private boolean isAnimerDriven(){
return isAnimerDriven;
}
private boolean isFling(){
return isFling;
}
private void setFling(boolean boo){ isFling = boo; }
private boolean isSpringBack() { return isSpringBack; }
private void setSpringBack(boolean boo) {
isSpringBack = boo;
}
private static double mapValueFromRangeToRange(double value,double fromLow,
double fromHigh,
double toLow,
double toHigh) {
double fromRangeSize = fromHigh - fromLow;
double toRangeSize = toHigh - toLow;
double valueScale = (value - fromLow) / fromRangeSize;
return toLow + (valueScale * toRangeSize);
}
public void setDynamicFlingFriction(boolean dynamicDampingState){
isDyanmicFling = dynamicDampingState;
}
public boolean isDynamicFlingFriction(){
return isDyanmicFling;
}
public Animer getSpringAnimer(){
return springAnimer;
}
public Animer getFlingAnimer(){
return flingAnimer;
}
public Animer getFakeFlingAnimer(){
return flingSpringAnimer;
}
public void setVertScroll(boolean isVertical) {
isVertScroll = isVertical;
}
public boolean isVertScroll(){
return isVertScroll;
}
public void setFixedScroll(boolean fixedScroll,float cellWidth){
isFixedScroll = fixedScroll;
fixedCellWidth = cellWidth;
}
private boolean isFixedScroll(){
return isFixedScroll;
}
}
================================================
FILE: animer/src/main/java/com/martinrgb/animer/component/scrollview/AnScrollView.java
================================================
package com.martinrgb.animer.component.scrollview;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.os.Build;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.FocusFinder;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewDebug;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.animation.AnimationUtils;
import android.widget.FrameLayout;
import com.martinrgb.animer.Animer;
import java.util.List;
public class AnScrollView extends FrameLayout {
static final int ANIMATED_SCROLL_GAP = 500;
static final float MAX_SCROLL_FACTOR = 0.5f;
// clampedY 回弹 init is 0.25f; // 0.4
static final float FOLLOW_HAND_FACTOR = 0.25f; //0.25f
private static final String TAG = "ScrollView";
private long mLastScroll;
private final Rect mTempRect = new Rect();
public AnOverScroller mScroller;
/**
* Position of the last motion event.
*/
private int mLastMotionY;
private int mLastMotionX;
/**
* True when the layout has changed but the traversal has not come through yet.
* Ideally the view hierarchy would keep track of this for us.
*/
private boolean mIsLayoutDirty = true;
/**
* The child to give focus to in the event that a child has requested focus while the
* layout is dirty. This prevents the scroll from being wrong if the child has not been
* laid out before requesting focus.
*/
private View mChildToScrollTo = null;
/**
* True if the user is currently dragging this ScrollView around. This is
* not the same as 'is being flinged', which can be checked by
* mScroller.isFinished() (flinging begins when the user lifts his finger).
*/
private boolean mIsBeingDragged = false;
/**
* Determines speed during touch scrolling
*/
private VelocityTracker mVelocityTracker;
/**
* When set to true, the scroll view measure its child to make it fill the currently
* visible area.
*/
@ViewDebug.ExportedProperty(category = "layout")
private boolean mFillViewport;
/**
* Whether arrow scrolling is animated.
*/
private boolean mSmoothScrollingEnabled = true;
private int mTouchSlop;
private int mMinimumVelocity;
private int mMaximumVelocity;
private int mOverscrollDistance;
private int mOverflingDistance;
/**
* ID of the active pointer. This is used to retain consistency during
* drags/flings if multiple pointers are used.
*/
private int mActivePointerId = INVALID_POINTER;
/**
* Sentinel value for no current active pointer.
* Used by {@link #mActivePointerId}.
*/
private static final int INVALID_POINTER = -1;
private SavedState mSavedState;
public AnScrollView(Context context) {
this(context, null);
}
public AnScrollView(Context context, AttributeSet attrs) {
this(context, attrs, 0); //TODO: com.android.internal.R.attr.scrollViewStyle);
}
public AnScrollView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initScrollView();
}
@Override
public int getOverScrollMode() {
return OVER_SCROLL_ALWAYS;
}
@Override
public boolean shouldDelayChildPressedState() {
return true;
}
@Override
protected float getTopFadingEdgeStrength() {
return 0;
}
@Override
protected float getBottomFadingEdgeStrength() {
return 0;
}
/**
* @return The maximum amount this scroll view will scroll in response to
* an arrow event.
*/
public int getMaxScrollAmount() {
return (int) (MAX_SCROLL_FACTOR * (getBottom() - getTop()));
}
private void initScrollView() {
mScroller = new AnOverScroller(getContext());
//mScroller.setVertScroll(isVertScroll());
setFocusable(true);
setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
setWillNotDraw(false);
final ViewConfiguration configuration = ViewConfiguration.get(getContext());
mTouchSlop = configuration.getScaledTouchSlop();
mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
mOverscrollDistance = configuration.getScaledOverscrollDistance();
mOverflingDistance = configuration.getScaledOverflingDistance();
}
@Override
public void addView(View child) {
if (getChildCount() > 0) {
throw new IllegalStateException("ScrollView can host only one direct child");
}
super.addView(child);
}
@Override
public void addView(View child, int index) {
if (getChildCount() > 0) {
throw new IllegalStateException("ScrollView can host only one direct child");
}
super.addView(child, index);
}
@Override
public void addView(View child, ViewGroup.LayoutParams params) {
if (getChildCount() > 0) {
throw new IllegalStateException("ScrollView can host only one direct child");
}
super.addView(child, params);
}
@Override
public void addView(View child, int index, ViewGroup.LayoutParams params) {
if (getChildCount() > 0) {
throw new IllegalStateException("ScrollView can host only one direct child");
}
super.addView(child, index, params);
}
/**
* @return Returns true this ScrollView can be scrolled
*/
private boolean canScroll() {
View child = getChildAt(0);
if (child != null) {
if(isVertScroll()){
int childHeight = child.getHeight();
return getHeight() < childHeight + getPaddingTop() + getPaddingBottom();
}
else{
int childWidth = child.getWidth();
return getWidth() < childWidth + getPaddingLeft() + getPaddingRight();
}
}
return false;
}
/**
* Indicates whether this ScrollView's content is stretched to fill the viewport.
*
* @return True if the content fills the viewport, false otherwise.
*
* @attr ref android.R.styleable#ScrollView_fillViewport
*/
public boolean isFillViewport() {
return mFillViewport;
}
/**
* Indicates this ScrollView whether it should stretch its content height to fill
* the viewport or not.
*
* @param fillViewport True to stretch the content's height to the viewport's
* boundaries, false otherwise.
*
* @attr ref android.R.styleable#ScrollView_fillViewport
*/
public void setFillViewport(boolean fillViewport) {
if (fillViewport != mFillViewport) {
mFillViewport = fillViewport;
requestLayout();
}
}
/**
* @return Whether arrow scrolling will animate its transition.
*/
public boolean isSmoothScrollingEnabled() {
return mSmoothScrollingEnabled;
}
/**
* Set whether arrow scrolling will animate its transition.
* @param smoothScrollingEnabled whether arrow scrolling will animate its transition
*/
public void setSmoothScrollingEnabled(boolean smoothScrollingEnabled) {
mSmoothScrollingEnabled = smoothScrollingEnabled;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (!mFillViewport) {
return;
}
final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
if (heightMode == MeasureSpec.UNSPECIFIED) {
return;
}
Log.e("totalHeight",String.valueOf(heightMeasureSpec));
if (getChildCount() > 0) {
final View child = getChildAt(0);
int height = getMeasuredHeight();
int width = getMeasuredWidth();
if(isVertScroll()) {
if (child.getMeasuredHeight() < height) {
final FrameLayout.LayoutParams lp = (LayoutParams) child.getLayoutParams();
int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,
getPaddingLeft() + getPaddingRight(), lp.width);
height -= getPaddingTop();
height -= getPaddingBottom();
int childHeightMeasureSpec =
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}
}else{
if (child.getMeasuredWidth() < width) {
final FrameLayout.LayoutParams lp = (LayoutParams) child.getLayoutParams();
int childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec,
getPaddingTop() + getPaddingBottom(), lp.height);
width -= getPaddingLeft();
width -= getPaddingRight();
int childWidthMeasureSpec =
MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}
}
}
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
// Let the focused view and/or our descendants get the key first
return super.dispatchKeyEvent(event) || executeKeyEvent(event);
}
/**
* You can call this function yourself to have the scroll view perform
* scrolling from a key event, just as if the event had been dispatched to
* it by the view hierarchy.
*
* @param event The key event to execute.
* @return Return true if the event was handled, else false.
*/
public boolean executeKeyEvent(KeyEvent event) {
mTempRect.setEmpty();
if (!canScroll()) {
if (isFocused() && event.getKeyCode() != KeyEvent.KEYCODE_BACK) {
View currentFocused = findFocus();
if (currentFocused == this) currentFocused = null;
View nextFocused = FocusFinder.getInstance().findNextFocus(this,
currentFocused, View.FOCUS_DOWN);
return nextFocused != null
&& nextFocused != this
&& nextFocused.requestFocus(View.FOCUS_DOWN);
}
return false;
}
boolean handled = false;
if (event.getAction() == KeyEvent.ACTION_DOWN) {
switch (event.getKeyCode()) {
case KeyEvent.KEYCODE_DPAD_UP:
if (!event.isAltPressed()) {
handled = arrowScroll(View.FOCUS_UP);
} else {
handled = fullScroll(View.FOCUS_UP);
}
break;
case KeyEvent.KEYCODE_DPAD_DOWN:
if (!event.isAltPressed()) {
handled = arrowScroll(View.FOCUS_DOWN);
} else {
handled = fullScroll(View.FOCUS_DOWN);
}
break;
case KeyEvent.KEYCODE_SPACE:
pageScroll(event.isShiftPressed() ? View.FOCUS_UP : View.FOCUS_DOWN);
break;
}
}
return handled;
}
private boolean inChild(int x, int y) {
if (getChildCount() > 0) {
final int scrollY = getScrollY();
final int scrollX = getScrollX();
final View child = getChildAt(0);
if(isVertScroll()){
return !(y < child.getTop() - scrollY
|| y >= child.getBottom() - scrollY
|| x < child.getLeft()
|| x >= child.getRight());
}
else {
return !(y < child.getTop()
|| y >= child.getBottom()
|| x < child.getLeft() - scrollX
|| x >= child.getRight() - scrollX);
}
}
return false;
}
private void initOrResetVelocityTracker() {
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
} else {
mVelocityTracker.clear();
}
}
private void initVelocityTrackerIfNotExists() {
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
}
}
private void recycleVelocityTracker() {
if (mVelocityTracker != null) {
mVelocityTracker.recycle();
mVelocityTracker = null;
}
}
@Override
public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
if (disallowIntercept) {
recycleVelocityTracker();
}
super.requestDisallowInterceptTouchEvent(disallowIntercept);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
/*
* This method JUST determines whether we want to intercept the motion.
* If we return true, onMotionEvent will be called and we do the actual
* scrolling there.
*/
/*
* Shortcut the most recurring case: the user is in the dragging
* state and he is moving his finger. We want to intercept this
* motion.
*/
final int action = ev.getAction();
if ((action == MotionEvent.ACTION_MOVE) && (mIsBeingDragged)) {
return true;
}
/*
* Don't try to intercept touch if we can't scroll anyway.
*/
if (getScrollY() == 0 && !canScrollVertically(1) && isVertScroll()) {
return false;
}
if (getScrollX() == 0 && !canScrollVertically(1) && !isVertScroll()) {
return false;
}
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_MOVE: {
/*
* mIsBeingDragged == false, otherwise the shortcut would have caught it. Check
* whether the user has moved far enough from his original down touch.
*/
/*
* Locally do absolute value. mLastMotionY is set to the y value
* of the down event.
*/
final int activePointerId = mActivePointerId;
if (activePointerId == INVALID_POINTER) {
// If we don't have a valid id, the touch down wasn't on content.
break;
}
final int pointerIndex = ev.findPointerIndex(activePointerId);
if (pointerIndex == -1) {
Log.e(TAG, "Invalid pointerId=" + activePointerId
+ " in onInterceptTouchEvent");
break;
}
if(isVertScroll()) {
final int y = (int) ev.getY(pointerIndex);
final int yDiff = Math.abs(y - mLastMotionY);
if (yDiff > mTouchSlop) {
mIsBeingDragged = true;
mLastMotionY = y;
initVelocityTrackerIfNotExists();
mVelocityTracker.addMovement(ev);
final ViewParent parent = getParent();
if (parent != null) {
parent.requestDisallowInterceptTouchEvent(true);
}
}
}
else{
final int x = (int) ev.getX(pointerIndex);
final int xDiff = Math.abs(x - mLastMotionX);
if (xDiff > mTouchSlop) {
mIsBeingDragged = true;
mLastMotionX = x;
initVelocityTrackerIfNotExists();
mVelocityTracker.addMovement(ev);
final ViewParent parent = getParent();
if (parent != null) {
parent.requestDisallowInterceptTouchEvent(true);
}
}
}
break;
}
case MotionEvent.ACTION_DOWN: {
if(isVertScroll()) {
final int y = (int) ev.getY();
if (!inChild((int) ev.getX(), (int) y)) {
mIsBeingDragged = false;
recycleVelocityTracker();
break;
}
/*
* Remember location of down touch.
* ACTION_DOWN always refers to pointer index 0.
*/
mLastMotionY = y;
}
else{
final int x = (int) ev.getX();
if (!inChild((int) x, (int) ev.getY())) {
mIsBeingDragged = false;
recycleVelocityTracker();
break;
}
/*
* Remember location of down touch.
* ACTION_DOWN always refers to pointer index 0.
*/
mLastMotionX = x;
}
mActivePointerId = ev.getPointerId(0);
initOrResetVelocityTracker();
mVelocityTracker.addMovement(ev);
/*
* If being flinged and user touches the screen, initiate drag;
* otherwise don't. mScroller.isFinished should be false when
* being flinged.
*/
mIsBeingDragged = !mScroller.isFinished();
break;
}
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
/* Release the drag */
mIsBeingDragged = false;
mActivePointerId = INVALID_POINTER;
recycleVelocityTracker();
if(isVertScroll()){
if (mScroller.springBack(getScrollX(), getScrollY(), 0,0,0, 0, 0, getScrollRange())) {
postInvalidateOnAnimation();
}
}
else {
if (mScroller.springBack(getScrollX(), getScrollY(), 0,0,0, getScrollRange(), 0, 0)) {
postInvalidateOnAnimation();
}
}
break;
case MotionEvent.ACTION_POINTER_UP:
onSecondaryPointerUp(ev);
break;
}
/*
* The only time we want to intercept motion events is if we are in the
* drag mode.
*/
return mIsBeingDragged;
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
initVelocityTrackerIfNotExists();
mVelocityTracker.addMovement(ev);
final int action = ev.getAction();
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: {
if (getChildCount() == 0) {
return false;
}
if ((mIsBeingDragged = !mScroller.isFinished())) {
final ViewParent parent = getParent();
if (parent != null) {
parent.requestDisallowInterceptTouchEvent(true);
}
}
/*
* If being flinged and user touches, stop the fling. isFinished
* will be false if being flinged.
*/
if (!mScroller.isFinished()) {
mScroller.abortAnimation();
}
// Remember where the motion event started
if(isVertScroll()){
mLastMotionY = (int) ev.getY();
}
else {
mLastMotionX = (int) ev.getX();
}
mActivePointerId = ev.getPointerId(0);
break;
}
case MotionEvent.ACTION_MOVE:
final int activePointerIndex = ev.findPointerIndex(mActivePointerId);
if (activePointerIndex == -1) {
Log.e(TAG, "Invalid pointerId=" + mActivePointerId + " in onTouchEvent");
break;
}
if(isVertScroll()) {
final int y = (int) ev.getY(activePointerIndex);
int deltaY = mLastMotionY - y;
if (!mIsBeingDragged && Math.abs(deltaY) > mTouchSlop) {
final ViewParent parent = getParent();
if (parent != null) {
parent.requestDisallowInterceptTouchEvent(true);
}
mIsBeingDragged = true;
if (deltaY > 0) {
deltaY -= mTouchSlop;
} else {
deltaY += mTouchSlop;
}
}
if (mIsBeingDragged) {
// Scroll to follow the motion event
mLastMotionY = y;
final int oldX = getScrollX();
final int oldY = getScrollY();
final int range = getScrollRange();
final int overscrollMode = getOverScrollMode();
final boolean canOverscroll = overscrollMode == OVER_SCROLL_ALWAYS ||
(overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && range > 0);
// Calling overScrollBy will call onOverScrolled, which
// calls onScrollChanged if applicable.
if (overScrollBy(0, deltaY, 0, getScrollY(),
0, range, 0, mOverscrollDistance, true)) {
// Break our velocity if we hit a scroll barrier.
mVelocityTracker.clear();
}
}
}
else{
final int x = (int) ev.getX(activePointerIndex);
int deltaX = mLastMotionX - x;
if (!mIsBeingDragged && Math.abs(deltaX) > mTouchSlop) {
final ViewParent parent = getParent();
if (parent != null) {
parent.requestDisallowInterceptTouchEvent(true);
}
mIsBeingDragged = true;
if (deltaX > 0) {
deltaX -= mTouchSlop;
} else {
deltaX += mTouchSlop;
}
}
if (mIsBeingDragged) {
// Scroll to follow the motion event
mLastMotionX = x;
final int oldX = getScrollX();
final int oldY = getScrollY();
final int range = getScrollRange();
final int overscrollMode = getOverScrollMode();
final boolean canOverscroll = overscrollMode == OVER_SCROLL_ALWAYS ||
(overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && range > 0);
// Calling overScrollBy will call onOverScrolled, which
// calls onScrollChanged if applicable.
if (overScrollBy(deltaX, 0, getScrollX(), 0,
range, 0, mOverscrollDistance, 0, true)) {
// Break our velocity if we hit a scroll barrier.
mVelocityTracker.clear();
}
}
}
break;
case MotionEvent.ACTION_UP:
if (mIsBeingDragged) {
final VelocityTracker velocityTracker = mVelocityTracker;
velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
int initialVelocityY = (int) velocityTracker.getYVelocity(mActivePointerId);
int initialVelocityX = (int) velocityTracker.getXVelocity(mActivePointerId);
if (getChildCount() > 0) {
if(isVertScroll()) {
if ((Math.abs(initialVelocityY) > mMinimumVelocity)) {
fling(-initialVelocityY);
} else {
if (mScroller.springBack(getScrollX(), getScrollY(), 0, 0, 0, 0, 0, getScrollRange())) {
postInvalidateOnAnimation();
}
}
}
else {
if ((Math.abs(initialVelocityX) > mMinimumVelocity)) {
fling(-initialVelocityX);
} else{
if (mScroller.springBack(getScrollX(), getScrollY(),0,0, 0, getScrollRange(), 0, 0)) {
postInvalidateOnAnimation();
}
}
}
}
mActivePointerId = INVALID_POINTER;
endDrag();
}
break;
case MotionEvent.ACTION_CANCEL:
if (mIsBeingDragged && getChildCount() > 0) {
if(isVertScroll()){
if (mScroller.springBack(getScrollX(), getScrollY(),0,0, 0, 0, 0, getScrollRange())) {
postInvalidateOnAnimation();
}
}
else {
if (mScroller.springBack(getScrollX(), getScrollY(),0,0, 0, getScrollRange(), 0, 0)) {
postInvalidateOnAnimation();
}
}
mActivePointerId = INVALID_POINTER;
endDrag();
}
break;
case MotionEvent.ACTION_POINTER_DOWN: {
final int index = ev.getActionIndex();
if(isVertScroll()){
mLastMotionY = (int) ev.getY(index);
}
else {
mLastMotionX = (int) ev.getX(index);
}
mActivePointerId = ev.getPointerId(index);
break;
}
case MotionEvent.ACTION_POINTER_UP:
onSecondaryPointerUp(ev);
if(isVertScroll()){
mLastMotionY = (int) ev.getY(ev.findPointerIndex(mActivePointerId));
}
else {
mLastMotionY = (int) ev.getX(ev.findPointerIndex(mActivePointerId));
}
break;
}
return true;
}
private void onSecondaryPointerUp(MotionEvent ev) {
final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >>
MotionEvent.ACTION_POINTER_INDEX_SHIFT;
final int pointerId = ev.getPointerId(pointerIndex);
if (pointerId == mActivePointerId) {
// This was our active pointer going up. Choose a new
// active pointer and adjust accordingly.
// TODO: Make this decision more intelligent.
final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
if(isVertScroll()){
mLastMotionY = (int) ev.getY(newPointerIndex);
}
else {
mLastMotionX = (int) ev.getX(newPointerIndex);
}
mActivePointerId = ev.getPointerId(newPointerIndex);
if (mVelocityTracker != null) {
mVelocityTracker.clear();
}
}
}
// @Override
// public boolean onGenericMotionEvent(MotionEvent event) {
// if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
// switch (event.getAction()) {
// case MotionEvent.ACTION_SCROLL: {
// if (!mIsBeingDragged) {
// final float vscroll = event.getAxisValue(MotionEvent.AXIS_VSCROLL);
// if (vscroll != 0) {
// final int delta = (int) (vscroll * getVerticalScrollFactor());
// final int range = getScrollRange();
// int oldScrollY = getScrollY();
// int newScrollY = oldScrollY - delta;
// if (newScrollY < 0) {
// newScrollY = 0;
// } else if (newScrollY > range) {
// newScrollY = range;
// }
// if (newScrollY != oldScrollY) {
// super.scrollTo(getScrollX(), newScrollY);
// return true;
// }
// }
// }
// }
// }
// }
// return super.onGenericMotionEvent(event);
// }
// 滑动后的松手
@Override
protected void onOverScrolled(int scrollX, int scrollY,
boolean clampedX, boolean clampedY) {
// Treat animating scrolls differently; see #computeScroll() for why.
if (!mScroller.isFinished()) {
final int oldX = getScrollX();
final int oldY = getScrollY();
setScrollX(scrollX);
setScrollY(scrollY);
invalidateParentIfNeeded();
onScrollChanged(getScrollX(), getScrollY(), oldX, oldY);
if(isVertScroll()){
if (clampedY) {
//松手后 OverScroll 的滑动
mScroller.springBack(getScrollX(), getScrollY(), 0,0,0, 0, 0, getScrollRange());
}
}
else {
if(clampedX){
mScroller.springBack(getScrollX(), getScrollY(), 0,0,0, getScrollRange(), 0, 0);
}
}
} else {
//跟手的滑动(包括 OverScroll)
super.scrollTo(scrollX, scrollY);
}
awakenScrollBars();
}
private void invalidateParentIfNeeded() {
if (isHardwareAccelerated() && getParent() instanceof View) {
((View) getParent()).invalidate();
}
}
@Override
public boolean performAccessibilityAction(int action, Bundle arguments) {
if (super.performAccessibilityAction(action, arguments)) {
return true;
}
if (!isEnabled()) {
return false;
}
switch (action) {
case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: {
if(isVertScroll()){
final int viewportHeight = getHeight() - getPaddingBottom() - getPaddingTop();
final int targetScrollY = Math.min(getScrollY() + viewportHeight, getScrollRange());
if (targetScrollY != getScrollY()) {
smoothScrollTo(0, targetScrollY);
return true;
}
}
else {
final int viewportWidth = getWidth() - getPaddingRight() - getPaddingLeft();
final int targetScrollX = Math.min(getScrollX() + viewportWidth, getScrollRange());
if (targetScrollX != getScrollX()) {
smoothScrollTo(targetScrollX, 0);
return true;
}
}
} return false;
case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: {
if(isVertScroll()){
final int viewportHeight = getHeight() - getPaddingBottom() - getPaddingTop();
final int targetScrollY = Math.max(getScrollY() - viewportHeight, 0);
if (targetScrollY != getScrollY()) {
smoothScrollTo(0, targetScrollY);
return true;
}
}
else {
final int viewportWidth = getWidth() - getPaddingRight() - getPaddingLeft();
final int targetScrollX = Math.max(getScrollX() - viewportWidth, 0);
if (targetScrollX != getScrollX()) {
smoothScrollTo(targetScrollX, 0);
return true;
}
}
} return false;
}
return false;
}
@Override
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
info.setClassName(AnScrollView.class.getName());
if (isEnabled()) {
final int scrollRange = getScrollRange();
if (scrollRange > 0) {
info.setScrollable(true);
if(isVertScroll()){
if (getScrollY() > 0) {
info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
}
if (getScrollY() < scrollRange) {
info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
}
}
else {
if (getScrollX() > 0) {
info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
}
if (getScrollX() < scrollRange) {
info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
}
}
}
}
}
@Override
public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
super.onInitializeAccessibilityEvent(event);
event.setClassName(AnScrollView.class.getName());
final boolean scrollable = getScrollRange() > 0;
event.setScrollable(scrollable);
event.setScrollX(getScrollX());
event.setScrollY(getScrollY());
if(isVertScroll()){
event.setMaxScrollX(getScrollX());
event.setMaxScrollY(getScrollRange());
}
else {
event.setMaxScrollX(getScrollRange());
event.setMaxScrollY(getScrollY());
}
}
private int getScrollRange() {
int scrollRange = 0;
if (getChildCount() > 0) {
View child = getChildAt(0);
if(isVertScroll()){
scrollRange = Math.max(0,child.getHeight() - (getHeight() - getPaddingBottom() - getPaddingTop()));
}
else {
scrollRange = Math.max(0,child.getWidth() - (getWidth() - getPaddingLeft() - getPaddingRight()));
}
}
return scrollRange;
}
/**
* <p>
* Finds the next focusable component that fits in the specified bounds.
* </p>
*
* @param topFocus look for a candidate is the one at the top of the bounds
* if topFocus is true, or at the bottom of the bounds if topFocus is
* false
* @param top the top offset of the bounds in which a focusable must be
* found
* @param bottom the bottom offset of the bounds in which a focusable must
* be found
* @return the next focusable component in the bounds or null if none can
* be found
*/
private View findFocusableViewInBounds(boolean topFocus, int top, int bottom) {
List<View> focusables = getFocusables(View.FOCUS_FORWARD);
View focusCandidate = null;
/*
* A fully contained focusable is one where its top is below the bound's
* top, and its bottom is above the bound's bottom. A partially
* contained focusable is one where some part of it is within the
* bounds, but it also has some part that is not within bounds. A fully contained
* focusable is preferred to a partially contained focusable.
*/
boolean foundFullyContainedFocusable = false;
int count = focusables.size();
if(isVertScroll()){
for (int i = 0; i < count; i++) {
View view = focusables.get(i);
int viewTop = view.getTop();
int viewBottom = view.getBottom();
if (top < viewBottom && viewTop < bottom) {
/*
* the focusable is in the target area, it is a candidate for
* focusing
*/
final boolean viewIsFullyContained = (top < viewTop) &&
(viewBottom < bottom);
if (focusCandidate == null) {
/* No candidate, take this one */
focusCandidate = view;
foundFullyContainedFocusable = viewIsFullyContained;
} else {
final boolean viewIsCloserToBoundary =
(topFocus && viewTop < focusCandidate.getTop()) ||
(!topFocus && viewBottom > focusCandidate
.getBottom());
if (foundFullyContainedFocusable) {
if (viewIsFullyContained && viewIsCloserToBoundary) {
/*
* We're dealing with only fully contained views, so
* it has to be closer to the boundary to beat our
* candidate
*/
focusCandidate = view;
}
} else {
if (viewIsFullyContained) {
/* Any fully contained view beats a partially contained view */
focusCandidate = view;
foundFullyContainedFocusable = true;
} else if (viewIsCloserToBoundary) {
/*
* Partially contained view beats another partially
* contained view if it's closer
*/
focusCandidate = view;
}
}
}
}
}
}
else {
for (int i = 0; i < count; i++) {
View view = focusables.get(i);
int viewLeft = view.getLeft();
int viewRight = view.getRight();
if (top < viewRight && viewLeft < bottom) {
/*
* the focusable is in the target area, it is a candidate for
* focusing
*/
final boolean viewIsFullyContained = (top < viewLeft) &&
(viewRight < bottom);
if (focusCandidate == null) {
/* No candidate, take this one */
focusCandidate = view;
foundFullyContainedFocusable = viewIsFullyContained;
} else {
final boolean viewIsCloserToBoundary =
(topFocus && viewLeft < focusCandidate.getLeft()) ||
(!topFocus && viewRight > focusCandidate.getRight());
if (foundFullyContainedFocusable) {
if (viewIsFullyContained && viewIsCloserToBoundary) {
/*
* We're dealing with only fully contained views, so
* it has to be closer to the boundary to beat our
* candidate
*/
focusCandidate = view;
}
} else {
if (viewIsFullyContained) {
/* Any fully contained view beats a partially contained view */
focusCandidate = view;
foundFullyContainedFocusable = true;
} else if (viewIsCloserToBoundary) {
/*
* Partially contained view beats another partially
* contained view if it's closer
*/
focusCandidate = view;
}
}
}
}
}
}
return focusCandidate;
}
/**
* <p>Handles scrolling in response to a "page up/down" shortcut press. This
* method will scroll the view by one page up or down and give the focus
* to the topmost/bottommost component in the new visible area. If no
* component is a good candidate for focus, this scrollview reclaims the
* focus.</p>
*
* @param direction the scroll direction: {@link android.view.View#FOCUS_UP}
* to go one page up or
* {@link android.view.View#FOCUS_DOWN} to go one page down
* @return true if the key event is consumed by this method, false otherwise
*/
public boolean pageScroll(int direction) {
boolean down = direction == View.FOCUS_DOWN;
if(isVertScroll()) {
int height = getHeight();
if (down) {
mTempRect.top = getScrollY() + height;
int count = getChildCount();
if (count > 0) {
View view = getChildAt(count - 1);
if (mTempRect.top + height > view.getBottom()) {
mTempRect.top = view.getBottom() - height;
}
}
} else {
mTempRect.top = getScrollY() - height;
if (mTempRect.top < 0) {
mTempRect.top = 0;
}
}
mTempRect.bottom = mTempRect.top + height;
return scrollAndFocus(direction, mTempRect.top, mTempRect.bottom);
}
else{
int width = getWidth();
if (down) {
mTempRect.left = getScrollX() + width;
int count = getChildCount();
if (count > 0) {
View view = getChildAt(count - 1);
if (mTempRect.left + width > view.getRight()) {
mTempRect.left = view.getRight() - width;
}
}
} else {
mTempRect.left = getScrollX() - width;
if (mTempRect.left < 0) {
mTempRect.left = 0;
}
}
mTempRect.right = mTempRect.left + width;
return scrollAndFocus(direction, mTempRect.left,mTempRect.right);
}
}
/**
* <p>Handles scrolling in response to a "home/end" shortcut press. This
* method will scroll the view to the top or bottom and give the focus
* to the topmost/bottommost component in the new visible area. If no
* component is a good candidate for focus, this scrollview reclaims the
* focus.</p>
*
* @param direction the scroll direction: {@link android.view.View#FOCUS_UP}
* to go the top of the view or
* {@link android.view.View#FOCUS_DOWN} to go the bottom
* @return true if the key event is consumed by this method, false otherwise
*/
public boolean fullScroll(int direction) {
boolean down = directi
gitextract_xxgve15n/ ├── .gitignore ├── LICENSE ├── README.md ├── README.zh.md ├── animer/ │ ├── .gitignore │ ├── build.gradle │ ├── consumer-rules.pro │ ├── proguard-rules.pro │ └── src/ │ └── main/ │ ├── AndroidManifest.xml │ ├── java/ │ │ └── com/ │ │ └── martinrgb/ │ │ └── animer/ │ │ ├── Animer.java │ │ ├── component/ │ │ │ ├── overscroller/ │ │ │ │ └── launcher3/ │ │ │ │ ├── FlingSpringAnim.java │ │ │ │ ├── Interpolators.java │ │ │ │ └── OverScroller.java │ │ │ ├── overscrolllayout/ │ │ │ │ └── .gitkeep │ │ │ ├── recyclerview/ │ │ │ │ └── AnRecyclerView.java │ │ │ └── scrollview/ │ │ │ ├── AnOverScroller.java │ │ │ └── AnScrollView.java │ │ ├── core/ │ │ │ ├── interpolator/ │ │ │ │ ├── AnInterpolator.java │ │ │ │ ├── AndroidNative/ │ │ │ │ │ ├── AccelerateDecelerateInterpolator.java │ │ │ │ │ ├── AccelerateInterpolator.java │ │ │ │ │ ├── AnticipateInterpolator.java │ │ │ │ │ ├── AnticipateOvershootInterpolator.java │ │ │ │ │ ├── BounceInterpolator.java │ │ │ │ │ ├── CycleInterpolator.java │ │ │ │ │ ├── DecelerateInterpolator.java │ │ │ │ │ ├── FastOutLinearInInterpolator.java │ │ │ │ │ ├── FastOutSlowInInterpolator.java │ │ │ │ │ ├── LinearInterpolator.java │ │ │ │ │ ├── LinearOutSlowInInterpolator.java │ │ │ │ │ ├── LookupTableInterpolator.java │ │ │ │ │ ├── OvershootInterpolator.java │ │ │ │ │ └── PathInterpolator.java │ │ │ │ ├── AndroidSpringInterpolator.java │ │ │ │ ├── AndroidSpringInterpolator2.java │ │ │ │ ├── CustomBounceInterpolator.java │ │ │ │ ├── CustomDampingInterpolator.java │ │ │ │ ├── CustomMocosSpringInterpolator.java │ │ │ │ ├── CustomSpringInterpolator.java │ │ │ │ └── FlingSpringAnim.java │ │ │ ├── math/ │ │ │ │ ├── calculator/ │ │ │ │ │ ├── FlingCalculator.java │ │ │ │ │ └── SpringInterpolatorCalculator.java │ │ │ │ └── converter/ │ │ │ │ ├── AnSpringConverter.java │ │ │ │ ├── AndroidSpringConverter.java │ │ │ │ ├── DHOConverter.java │ │ │ │ ├── OrigamiPOPConverter.java │ │ │ │ ├── RK4Converter.java │ │ │ │ └── UIViewSpringConverter.java │ │ │ ├── property/ │ │ │ │ └── AnProperty.java │ │ │ ├── solver/ │ │ │ │ └── AnSolver.java │ │ │ ├── state/ │ │ │ │ └── PhysicsState.java │ │ │ └── util/ │ │ │ ├── AnSpringOscillateHelper.java │ │ │ └── AnUtil.java │ │ └── monitor/ │ │ ├── AnConfigData.java │ │ ├── AnConfigMap.java │ │ ├── AnConfigRegistry.java │ │ ├── AnConfigView.java │ │ ├── AnSpinnerAdapter.java │ │ ├── fps/ │ │ │ ├── Calculation.java │ │ │ ├── FPSBuilder.java │ │ │ ├── FPSConfig.java │ │ │ ├── FPSDetector.java │ │ │ ├── FPSFrameCallback.java │ │ │ ├── Foreground.java │ │ │ └── FrameDataCallback.java │ │ └── shader/ │ │ ├── ShaderProgram.java │ │ ├── ShaderRenderer.java │ │ ├── ShaderSurfaceView.java │ │ └── util/ │ │ ├── FPSCounter.java │ │ ├── LoggerConfig.java │ │ ├── ShaderHelper.java │ │ └── TextReader.java │ └── res/ │ ├── drawable/ │ │ ├── background_spinner.xml │ │ ├── gradient.xml │ │ ├── ic_button_background.xml │ │ ├── ic_edit_border.xml │ │ ├── ic_grid.xml │ │ ├── ic_nub.xml │ │ ├── ic_nub2.xml │ │ ├── ic_spinner.xml │ │ ├── ic_thumb.xml │ │ ├── popbackground_spinner.xml │ │ └── text_cursor.xml │ ├── layout/ │ │ └── config_view.xml │ ├── raw/ │ │ ├── simplefrag.glsl │ │ └── simplevert.glsl │ └── values/ │ ├── corlors.xml │ ├── dimension.xml │ └── styles.xml ├── app/ │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src/ │ ├── androidTest/ │ │ └── java/ │ │ └── com/ │ │ └── martinrgb/ │ │ └── animerexample/ │ │ └── ExampleInstrumentedTest.java │ ├── main/ │ │ ├── AndroidManifest.xml │ │ ├── java/ │ │ │ └── com/ │ │ │ └── martinrgb/ │ │ │ └── animerexample/ │ │ │ ├── MainActivity.java │ │ │ ├── PrototypeActivity.java │ │ │ ├── ScrollerActivity.java │ │ │ └── SmoothCornersImage.java │ │ └── res/ │ │ ├── drawable/ │ │ │ ├── background_elevation.xml │ │ │ ├── ic_arrow.xml │ │ │ ├── ic_launcher_background.xml │ │ │ └── myrect.xml │ │ ├── drawable-nodpi/ │ │ │ └── mute.xml │ │ ├── drawable-v24/ │ │ │ └── ic_launcher_foreground.xml │ │ ├── layout/ │ │ │ ├── activity_main.xml │ │ │ ├── activity_prototype.xml │ │ │ ├── activity_scroller.xml │ │ │ └── custom_cell_view.xml │ │ ├── mipmap-anydpi-v26/ │ │ │ ├── ic_launcher.xml │ │ │ └── ic_launcher_round.xml │ │ └── values/ │ │ ├── attr.xml │ │ ├── colors.xml │ │ ├── dimension.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test/ │ └── java/ │ └── com/ │ └── martinrgb/ │ └── animerexample/ │ └── ExampleUnitTest.java ├── build.gradle ├── gradle/ │ └── wrapper/ │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradle.properties ├── gradlew ├── gradlew.bat └── settings.gradle
SYMBOL INDEX (749 symbols across 67 files)
FILE: animer/src/main/java/com/martinrgb/animer/Animer.java
class Animer (line 35) | public class Animer<T> {
class AnimerProperty (line 41) | private abstract static class AnimerProperty extends AnProperty<View> {
method AnimerProperty (line 42) | private AnimerProperty(String name) {
method setValue (line 48) | @Override
method getValue (line 53) | @Override
method setValue (line 60) | @Override
method getValue (line 65) | @Override
method setValue (line 72) | @Override
method getValue (line 77) | @Override
method setValue (line 84) | @Override
method getValue (line 90) | @Override
method setValue (line 97) | @Override
method getValue (line 102) | @Override
method setValue (line 109) | @Override
method getValue (line 114) | @Override
method setValue (line 121) | @Override
method getValue (line 126) | @Override
method setValue (line 133) | @Override
method getValue (line 138) | @Override
method setValue (line 145) | @Override
method getValue (line 150) | @Override
method setValue (line 157) | @Override
method getValue (line 162) | @Override
method setValue (line 169) | @Override
method getValue (line 174) | @Override
method setValue (line 181) | @Override
method getValue (line 186) | @Override
method setValue (line 193) | @Override
method getValue (line 198) | @Override
method getArgument1 (line 208) | public Object getArgument1(){
method setArgument1 (line 212) | public void setArgument1(Object val){
method getArgument2 (line 216) | public Object getArgument2(){
method setArgument2 (line 220) | public void setArgument2(Object val){
method getCurrentSolverData (line 224) | public AnConfigData getCurrentSolverData(){
method getCurrentSolver (line 246) | public AnimerSolver getCurrentSolver() {
method setCurrentSolver (line 249) | public void setCurrentSolver(AnimerSolver solver) {
class AnimerSolver (line 268) | public static class AnimerSolver extends AnSolver {
method AnimerSolver (line 272) | private AnimerSolver(Object val1,Object val2,int mode,AnConfigData d...
method getConfigSet (line 277) | public AnConfigData getConfigSet(){
method setConfigSet (line 281) | private void setConfigSet(AnConfigData data){
method flingDroid (line 287) | public static AnimerSolver flingDroid(float velocity,float friction){
method springDroid (line 293) | public static AnimerSolver springDroid(float stiffness,float dampingra...
method springRK4 (line 299) | public static AnimerSolver springRK4(float tension,float friction){
method springDHO (line 306) | public static AnimerSolver springDHO(float stiffness,float damping){
method springOrigamiPOP (line 313) | public static AnimerSolver springOrigamiPOP(float bounciness,float spe...
method springiOSUIView (line 320) | public static AnimerSolver springiOSUIView(float dampingratio,float du...
method springiOSCoreAnimation (line 327) | public static AnimerSolver springiOSCoreAnimation(float stiffness,floa...
method springProtopie (line 334) | public static AnimerSolver springProtopie(float tension,float friction){
method springPrinciple (line 341) | public static AnimerSolver springPrinciple(float tension,float friction){
method interpolatorDroid (line 348) | public static AnimerSolver interpolatorDroid(AnInterpolator interpolat...
method Animer (line 358) | public <K> Animer() {
method Animer (line 366) | public <K> Animer(AnimerSolver solver) {
method Animer (line 374) | public <K> Animer(float value) {
method Animer (line 382) | public <K> Animer(AnimerSolver solver,float value) {
method Animer (line 390) | public <K> Animer(K target, AnimerSolver solver, AnimerProperty proper...
method Animer (line 399) | public <K> Animer(K target, AnimerSolver solver, AnimerProperty proper...
method Animer (line 408) | public <K> Animer(K target, AnimerSolver solver, AnimerProperty proper...
method setTarget (line 417) | public void setTarget(Object target) {
method setProperty (line 421) | public void setProperty(AnimerProperty mProperty) {
method setSolver (line 430) | public void setSolver(AnimerSolver solver){
method setupBySolver (line 439) | private void setupBySolver(AnimerSolver solver) {
method setupFlingAnimator (line 456) | private void setupFlingAnimator(AnimerSolver solver){
method attachSolverToFling (line 481) | private void attachSolverToFling(AnimerSolver solver, FlingAnimation f...
method setupSpringAnimator (line 495) | private void setupSpringAnimator(AnimerSolver solver){
method attachSolverToSpring (line 521) | private void attachSolverToSpring(AnimerSolver solver, SpringAnimation...
method setupTimingAnimator (line 534) | private void setupTimingAnimator(AnimerSolver solver){
method attachSolverToTiming (line 572) | private void attachSolverToTiming(AnimerSolver solver, ObjectAnimator ...
method setFrom (line 591) | public void setFrom(float start){
method setTo (line 610) | public void setTo(float end){
method start (line 629) | public void start(){
method cancel (line 644) | public void cancel(){
method isRunning (line 659) | public boolean isRunning(){
method end (line 681) | public void end(){
method reverse (line 704) | public void reverse(){
method switchToState (line 710) | public void switchToState(String state){
method animateToState (line 716) | public void animateToState(String state){
method setCurrentValue (line 748) | public void setCurrentValue(float value){
method setEndValue (line 757) | public void setEndValue(float value){
method setVelocity (line 790) | public void setVelocity(float velocity){
method setVelocityInfluence (line 794) | public void setVelocityInfluence(float factor){
method setMinimumVisibleChange (line 804) | public void setMinimumVisibleChange(float minimumVisValue) {
method setStateValue (line 826) | public void setStateValue(String key,float value){
method getStateValue (line 829) | public float getStateValue(String state){
method setCurrentPhysicsVelocity (line 834) | private void setCurrentPhysicsVelocity(float velocity){
method setCurrenetPhysicsValue (line 837) | private void setCurrenetPhysicsValue(float value){
method getCurrentPhysicsVelocity (line 841) | private float getCurrentPhysicsVelocity(){
method getCurrentPhysicsValue (line 844) | private float getCurrentPhysicsValue(){
method endCurrentPhysicsState (line 848) | private void endCurrentPhysicsState(float value,float velocity,boolean...
method updateCurrentPhysicsState (line 858) | private void updateCurrentPhysicsState(float value,float velocity,floa...
method getCurrentPhysicsState (line 871) | public PhysicsState getCurrentPhysicsState(){
method setHardwareAcceleration (line 879) | private void setHardwareAcceleration(boolean bool){
method isHardwareAccelerationEnabled (line 895) | public boolean isHardwareAccelerationEnabled() {
method enableHardwareAcceleration (line 899) | public void enableHardwareAcceleration(boolean enable){
method enableActionerInfluenceOnVelocity (line 910) | public void enableActionerInfluenceOnVelocity(boolean boo){
method getActionerInfluenceOnVelocity (line 914) | private boolean getActionerInfluenceOnVelocity(){
method setActionerAndListener (line 918) | public <K> void setActionerAndListener(K actioner,ActionTouchListener ...
method setUpdateListener (line 984) | public void setUpdateListener(UpdateListener listener) {
method setEndListener (line 988) | public void setEndListener(EndListener listener) {
method getTriggerListener (line 992) | public TriggeredListener getTriggerListener() {
method setTriggerListener (line 1002) | public void setTriggerListener(TriggeredListener listener) {
method removeTriggerListener (line 1006) | public void removeTriggerListener() {
method setActionTouchListener (line 1010) | public void setActionTouchListener(ActionTouchListener listener) {
type UpdateListener (line 1014) | public interface UpdateListener {
method onUpdate (line 1015) | void onUpdate(float value, float velocity,float progress);
type EndListener (line 1017) | public interface EndListener{
method onEnd (line 1018) | void onEnd(float value, float velocity,boolean canceled);
type TriggeredListener (line 1021) | public interface TriggeredListener{
method onTrigger (line 1022) | void onTrigger(boolean triggered);
type ActionTouchListener (line 1025) | public interface ActionTouchListener{
method onDown (line 1026) | void onDown(View view,MotionEvent event);
method onMove (line 1027) | void onMove(View view,MotionEvent event,float velocityX,float veloci...
method onUp (line 1028) | void onUp(View view,MotionEvent event);
method onCancel (line 1029) | abstract void onCancel(View view,MotionEvent event);
FILE: animer/src/main/java/com/martinrgb/animer/component/overscroller/launcher3/FlingSpringAnim.java
class FlingSpringAnim (line 28) | public class FlingSpringAnim {
method FlingSpringAnim (line 39) | public <K> FlingSpringAnim(K object, FloatPropertyCompat<K> property, ...
method getTargetPosition (line 64) | public float getTargetPosition() {
method updatePosition (line 68) | public void updatePosition(float startPosition, float targetPosition) {
method start (line 77) | public void start() {
method end (line 81) | public void end() {
FILE: animer/src/main/java/com/martinrgb/animer/component/overscroller/launcher3/Interpolators.java
class Interpolators (line 18) | public class Interpolators {
method getInterpolation (line 53) | @Override
method getInterpolation (line 60) | @Override
method zInterpolate (line 70) | private float zInterpolate(float input) {
method getInterpolation (line 76) | @Override
method getInterpolation (line 83) | @Override
method scrollInterpolatorForVelocity (line 90) | public static Interpolator scrollInterpolatorForVelocity(float velocit...
method overshootInterpolatorForVelocity (line 97) | public static Interpolator overshootInterpolatorForVelocity(float velo...
method clampToProgress (line 104) | public static Interpolator clampToProgress(Interpolator interpolator, ...
method mapToProgress (line 125) | public static Interpolator mapToProgress(Interpolator interpolator, fl...
class OvershootParams (line 134) | public static class OvershootParams {
method OvershootParams (line 149) | public OvershootParams(float startProgress, float overshootPastProgr...
method mapRange (line 199) | public static float mapRange(float value, float min, float max) {
method boundToRange (line 203) | public static float boundToRange(float value, float lowerBound, float ...
FILE: animer/src/main/java/com/martinrgb/animer/component/overscroller/launcher3/OverScroller.java
class OverScroller (line 38) | public class OverScroller {
method OverScroller (line 55) | public OverScroller(Context context) {
method OverScroller (line 65) | public OverScroller(Context context, Interpolator interpolator) {
method OverScroller (line 76) | public OverScroller(Context context, Interpolator interpolator, boolea...
method setInterpolator (line 86) | public void setInterpolator(TimeInterpolator interpolator) {
method setFriction (line 101) | public final void setFriction(float friction) {
method isFinished (line 111) | public final boolean isFinished() {
method forceFinished (line 123) | public final void forceFinished(boolean finished) {
method getCurrPos (line 132) | public final int getCurrPos() {
method getCurrVelocity (line 141) | public float getCurrVelocity() {
method getStartPos (line 150) | public final int getStartPos() {
method getFinalPos (line 159) | public final int getFinalPos() {
method getDuration (line 168) | public final int getDuration() {
method extendDuration (line 179) | public void extendDuration(int extend) {
method setFinalPos (line 189) | public void setFinalPos(int newPos) {
method computeScrollOffset (line 197) | public boolean computeScrollOffset() {
method startScroll (line 246) | public void startScroll(int start, int delta) {
method startScroll (line 259) | public void startScroll(int start, int delta, int duration) {
method startScrollSpring (line 274) | public void startScrollSpring(int start, int delta, int duration, floa...
method springBack (line 289) | public boolean springBack(int start, int min, int max) {
method fling (line 294) | public void fling(int start, int velocity, int min, int max) {
method fling (line 313) | public void fling(int start, int velocity, int min, int max, int over) {
method notifyEdgeReached (line 337) | public void notifyEdgeReached(int start, int finalPos, int over) {
method isOverScrolled (line 354) | public boolean isOverScrolled() {
method abortAnimation (line 365) | public void abortAnimation() {
method timePassed (line 376) | public int timePassed() {
method isSpringing (line 381) | public boolean isSpringing() {
class SplineOverScroller (line 385) | static class SplineOverScroller {
method getValue (line 454) | @Override
method setValue (line 459) | @Override
method setFriction (line 498) | void setFriction(float friction) {
method SplineOverScroller (line 502) | SplineOverScroller(Context context) {
method updateScroll (line 511) | void updateScroll(float q) {
method getDeceleration (line 521) | static private float getDeceleration(int velocity) {
method adjustDuration (line 529) | private void adjustDuration(int start, int oldFinal, int newFinal) {
method startScroll (line 544) | void startScroll(int start, int distance, int duration) {
method startScroll (line 548) | void startScroll(int start, int distance, int duration, float veloci...
method finish (line 579) | void finish() {
method setFinalPosition (line 589) | void setFinalPosition(int position) {
method extendDuration (line 598) | void extendDuration(int extend) {
method springback (line 605) | boolean springback(int start, int min, int max) {
method startSpringback (line 623) | private void startSpringback(int start, int end, int velocity) {
method fling (line 637) | void fling(int start, int velocity, int min, int max, int over) {
method getSplineDeceleration (line 673) | private double getSplineDeceleration(int velocity) {
method getSplineFlingDistance (line 677) | private double getSplineFlingDistance(int velocity) {
method getSplineFlingDuration (line 684) | private int getSplineFlingDuration(int velocity) {
method fitOnBounceCurve (line 690) | private void fitOnBounceCurve(int start, int end, int velocity) {
method startBounceAfterEdge (line 704) | private void startBounceAfterEdge(int start, int end, int velocity) {
method startAfterEdge (line 710) | private void startAfterEdge(int start, int min, int max, int velocit...
method notifyEdgeReached (line 733) | void notifyEdgeReached(int start, int end, int over) {
method onEdgeReached (line 744) | private void onEdgeReached() {
method continueWhenFinished (line 763) | boolean continueWhenFinished() {
method update (line 797) | boolean update() {
FILE: animer/src/main/java/com/martinrgb/animer/component/recyclerview/AnRecyclerView.java
class AnRecyclerView (line 19) | public class AnRecyclerView extends RecyclerView {
method AnRecyclerView (line 35) | public AnRecyclerView(Context context) {
method AnRecyclerView (line 40) | public AnRecyclerView(Context context, @Nullable AttributeSet attrs) {
method AnRecyclerView (line 45) | public AnRecyclerView(Context context, @Nullable AttributeSet attrs, i...
method setAdapter (line 50) | @Override
method setLayoutManager (line 61) | @Override
method scrollToPosition (line 80) | @Override
method smoothScrollToPosition (line 85) | @Override
method init (line 90) | private void init(Context context, AttributeSet attributeSet) {
method initAnimer (line 111) | private void initAnimer(){
method initOnScrollListener (line 168) | private void initOnScrollListener() {
method initTouchListener (line 218) | private void initTouchListener() {
method overDragFucntion (line 382) | private float overDragFucntion(float value){
method scrollBy (line 387) | private void scrollBy(int dist) {
method directionVertical (line 395) | private boolean directionVertical() {
method dpToPx (line 407) | private double dpToPx(double dp) {
FILE: animer/src/main/java/com/martinrgb/animer/component/scrollview/AnOverScroller.java
class AnOverScroller (line 16) | public class AnOverScroller {
method AnOverScroller (line 36) | public AnOverScroller(Context context) {
method AnOverScroller (line 40) | public AnOverScroller(Context context, Interpolator interpolator) {thi...
method AnOverScroller (line 42) | public AnOverScroller(Context context, Interpolator interpolator,float...
method AnOverScroller (line 44) | public AnOverScroller(Context context, Interpolator interpolator, floa...
method AnOverScroller (line 46) | public AnOverScroller(Context context, Interpolator interpolator, bool...
method getCurrX (line 137) | public final int getCurrX() {
method getCurrY (line 141) | public final int getCurrY() {
method getCurrVelocityY (line 145) | public float getCurrVelocityY() {
method getCurrVelocityX (line 149) | public float getCurrVelocityX() {
method startScroll (line 153) | public void startScroll(int startX, int startY, int dx, int dy) {
method computeScrollOffset (line 157) | public boolean computeScrollOffset() {
method isFinished (line 161) | public final boolean isFinished() {
method abortAnimation (line 165) | public void abortAnimation() {
method springBack (line 179) | public boolean springBack(int startX, int startY, int velocityX,int ve...
method springFunctions (line 241) | private void springFunctions(float val,float min,float max){
method fling (line 271) | public void fling(int startX, int startY, int velocityX, int velocityY,
method isAnimerDriven (line 347) | private boolean isAnimerDriven(){
method isFling (line 351) | private boolean isFling(){
method setFling (line 355) | private void setFling(boolean boo){ isFling = boo; }
method isSpringBack (line 357) | private boolean isSpringBack() { return isSpringBack; }
method setSpringBack (line 359) | private void setSpringBack(boolean boo) {
method mapValueFromRangeToRange (line 363) | private static double mapValueFromRangeToRange(double value,double fro...
method setDynamicFlingFriction (line 373) | public void setDynamicFlingFriction(boolean dynamicDampingState){
method isDynamicFlingFriction (line 376) | public boolean isDynamicFlingFriction(){
method getSpringAnimer (line 380) | public Animer getSpringAnimer(){
method getFlingAnimer (line 383) | public Animer getFlingAnimer(){
method getFakeFlingAnimer (line 386) | public Animer getFakeFlingAnimer(){
method setVertScroll (line 391) | public void setVertScroll(boolean isVertical) {
method isVertScroll (line 394) | public boolean isVertScroll(){
method setFixedScroll (line 398) | public void setFixedScroll(boolean fixedScroll,float cellWidth){
method isFixedScroll (line 402) | private boolean isFixedScroll(){
FILE: animer/src/main/java/com/martinrgb/animer/component/scrollview/AnScrollView.java
class AnScrollView (line 30) | public class AnScrollView extends FrameLayout {
method AnScrollView (line 109) | public AnScrollView(Context context) {
method AnScrollView (line 113) | public AnScrollView(Context context, AttributeSet attrs) {
method AnScrollView (line 117) | public AnScrollView(Context context, AttributeSet attrs, int defStyle) {
method getOverScrollMode (line 122) | @Override
method shouldDelayChildPressedState (line 127) | @Override
method getTopFadingEdgeStrength (line 132) | @Override
method getBottomFadingEdgeStrength (line 137) | @Override
method getMaxScrollAmount (line 146) | public int getMaxScrollAmount() {
method initScrollView (line 151) | private void initScrollView() {
method addView (line 165) | @Override
method addView (line 174) | @Override
method addView (line 182) | @Override
method addView (line 190) | @Override
method canScroll (line 202) | private boolean canScroll() {
method isFillViewport (line 225) | public boolean isFillViewport() {
method setFillViewport (line 238) | public void setFillViewport(boolean fillViewport) {
method isSmoothScrollingEnabled (line 248) | public boolean isSmoothScrollingEnabled() {
method setSmoothScrollingEnabled (line 256) | public void setSmoothScrollingEnabled(boolean smoothScrollingEnabled) {
method onMeasure (line 260) | @Override
method dispatchKeyEvent (line 309) | @Override
method executeKeyEvent (line 323) | public boolean executeKeyEvent(KeyEvent event) {
method inChild (line 365) | private boolean inChild(int x, int y) {
method initOrResetVelocityTracker (line 387) | private void initOrResetVelocityTracker() {
method initVelocityTrackerIfNotExists (line 395) | private void initVelocityTrackerIfNotExists() {
method recycleVelocityTracker (line 401) | private void recycleVelocityTracker() {
method requestDisallowInterceptTouchEvent (line 408) | @Override
method onInterceptTouchEvent (line 417) | @Override
method onTouchEvent (line 576) | @Override
method onSecondaryPointerUp (line 766) | private void onSecondaryPointerUp(MotionEvent ev) {
method onOverScrolled (line 819) | @Override
method invalidateParentIfNeeded (line 853) | private void invalidateParentIfNeeded() {
method performAccessibilityAction (line 860) | @Override
method onInitializeAccessibilityNodeInfo (line 911) | @Override
method onInitializeAccessibilityEvent (line 940) | @Override
method getScrollRange (line 959) | private int getScrollRange() {
method findFocusableViewInBounds (line 988) | private View findFocusableViewInBounds(boolean topFocus, int top, int ...
method pageScroll (line 1121) | public boolean pageScroll(int direction) {
method fullScroll (line 1181) | public boolean fullScroll(int direction) {
method scrollAndFocus (line 1212) | private boolean scrollAndFocus(int direction, int top, int bottom) {
method arrowScroll (line 1267) | public boolean arrowScroll(int direction) {
method isOffScreen (line 1353) | private boolean isOffScreen(View descendant) {
method isWithinDeltaOfScreen (line 1367) | private boolean isWithinDeltaOfScreen(View descendant, int delta, int ...
method doScrollY (line 1384) | private void doScrollY(int delta) {
method doScrollX (line 1394) | private void doScrollX(int delta) {
method smoothScrollBy (line 1410) | public final void smoothScrollBy(int dx, int dy) {
method smoothScrollTo (line 1451) | public final void smoothScrollTo(int x, int y) {
method computeVerticalScrollRange (line 1459) | @Override
method computeVerticalScrollOffset (line 1502) | @Override
method computeHorizontalScrollOffset (line 1507) | @Override
method measureChild (line 1512) | @Override
method measureChildWithMargins (line 1536) | @Override
method computeScroll (line 1562) | @Override
method scrollToChild (line 1617) | private void scrollToChild(View child) {
method scrollToChildRect (line 1643) | private boolean scrollToChildRect(Rect rect, boolean immediate) {
method computeScrollDeltaToGetChildRectOnScreen (line 1674) | protected int computeScrollDeltaToGetChildRectOnScreen(Rect rect) {
method requestChildFocus (line 1789) | @Override
method onRequestFocusInDescendants (line 1808) | @Override
method requestChildRectangleOnScreen (line 1836) | @Override
method requestLayout (line 1844) | @Override
method onDetachedFromWindow (line 1850) | @Override
method onLayout (line 1855) | @Override
method onSizeChanged (line 1906) | @Override
method isViewDescendantOf (line 1939) | private static boolean isViewDescendantOf(View child, View parent) {
method fling (line 1955) | public void fling(int velocity) {
method endDrag (line 1974) | private void endDrag() {
method scrollTo (line 1984) | @Override
method setOverScrollMode (line 1994) | @Override
method draw (line 1998) | @Override
method onRestoreInstanceState (line 2003) | @Override
method onSaveInstanceState (line 2017) | @Override
class SavedState (line 2030) | static class SavedState extends BaseSavedState {
method SavedState (line 2033) | SavedState(Parcelable superState) {
method SavedState (line 2037) | public SavedState(Parcel source) {
method writeToParcel (line 2042) | @Override
method toString (line 2048) | @Override
method createFromParcel (line 2057) | public SavedState createFromParcel(Parcel in) {
method newArray (line 2061) | public SavedState[] newArray(int size) {
method overScrollBy (line 2068) | protected boolean overScrollBy(int deltaX, int deltaY,
method isVertScroll (line 2131) | private boolean isVertScroll(){
method getScroller (line 2134) | public AnOverScroller getScroller(){ return mScroller; }
FILE: animer/src/main/java/com/martinrgb/animer/core/interpolator/AnInterpolator.java
class AnInterpolator (line 11) | public abstract class AnInterpolator implements TimeInterpolator {
method initArgData (line 23) | public void initArgData(int i, float val, String name, float min, floa...
method resetArgValue (line 52) | public void resetArgValue(int i, float value){
method setArgValue (line 56) | public void setArgValue(int i,float val){
method getArgNum (line 71) | public int getArgNum(){
method getArgValue (line 75) | public float getArgValue(int i) {
method getArgString (line 103) | public String getArgString(int i) {
method getArgMin (line 131) | public float getArgMin(int i) {
method getArgMax (line 159) | public float getArgMax(int i) {
FILE: animer/src/main/java/com/martinrgb/animer/core/interpolator/AndroidNative/AccelerateDecelerateInterpolator.java
class AccelerateDecelerateInterpolator (line 10) | public class AccelerateDecelerateInterpolator extends AnInterpolator {
method AccelerateDecelerateInterpolator (line 12) | public AccelerateDecelerateInterpolator() {
method AccelerateDecelerateInterpolator (line 15) | @SuppressWarnings({"UnusedDeclaration"})
method getInterpolation (line 19) | public float getInterpolation(float input) {
FILE: animer/src/main/java/com/martinrgb/animer/core/interpolator/AndroidNative/AccelerateInterpolator.java
class AccelerateInterpolator (line 5) | public class AccelerateInterpolator extends AnInterpolator {
method AccelerateInterpolator (line 9) | public AccelerateInterpolator() {
method AccelerateInterpolator (line 15) | public AccelerateInterpolator(float factor) {
method getInterpolation (line 21) | public float getInterpolation(float input) {
method resetArgValue (line 29) | @Override
FILE: animer/src/main/java/com/martinrgb/animer/core/interpolator/AndroidNative/AnticipateInterpolator.java
class AnticipateInterpolator (line 5) | public class AnticipateInterpolator extends AnInterpolator {
method AnticipateInterpolator (line 9) | public AnticipateInterpolator() {
method AnticipateInterpolator (line 19) | public AnticipateInterpolator(float tension) {
method getInterpolation (line 24) | public float getInterpolation(float t) {
method resetArgValue (line 29) | @Override
FILE: animer/src/main/java/com/martinrgb/animer/core/interpolator/AndroidNative/AnticipateOvershootInterpolator.java
class AnticipateOvershootInterpolator (line 5) | public class AnticipateOvershootInterpolator extends AnInterpolator {
method AnticipateOvershootInterpolator (line 8) | public AnticipateOvershootInterpolator() {
method AnticipateOvershootInterpolator (line 13) | public AnticipateOvershootInterpolator(float tension) {
method AnticipateOvershootInterpolator (line 18) | public AnticipateOvershootInterpolator(float tension, float extraTensi...
method a (line 23) | private static float a(float t, float s) {
method o (line 27) | private static float o(float t, float s) {
method getInterpolation (line 31) | public float getInterpolation(float t) {
method resetArgValue (line 40) | @Override
FILE: animer/src/main/java/com/martinrgb/animer/core/interpolator/AndroidNative/BounceInterpolator.java
class BounceInterpolator (line 10) | public class BounceInterpolator extends AnInterpolator {
method BounceInterpolator (line 11) | public BounceInterpolator() {
method bounce (line 14) | private static float bounce(float t) {
method getInterpolation (line 18) | public float getInterpolation(float t) {
FILE: animer/src/main/java/com/martinrgb/animer/core/interpolator/AndroidNative/CycleInterpolator.java
class CycleInterpolator (line 5) | public class CycleInterpolator extends AnInterpolator {
method CycleInterpolator (line 7) | public CycleInterpolator(float cycles) {
method getInterpolation (line 12) | public float getInterpolation(float input) {
method resetArgValue (line 18) | @Override
FILE: animer/src/main/java/com/martinrgb/animer/core/interpolator/AndroidNative/DecelerateInterpolator.java
class DecelerateInterpolator (line 5) | public class DecelerateInterpolator extends AnInterpolator {
method DecelerateInterpolator (line 10) | public DecelerateInterpolator() {
method DecelerateInterpolator (line 14) | public DecelerateInterpolator(float factor) {
method getInterpolation (line 20) | public float getInterpolation(float input) {
method resetArgValue (line 30) | @Override
FILE: animer/src/main/java/com/martinrgb/animer/core/interpolator/AndroidNative/FastOutLinearInInterpolator.java
class FastOutLinearInInterpolator (line 10) | public class FastOutLinearInInterpolator extends LookupTableInterpolator {
method FastOutLinearInInterpolator (line 43) | public FastOutLinearInInterpolator() {
FILE: animer/src/main/java/com/martinrgb/animer/core/interpolator/AndroidNative/FastOutSlowInInterpolator.java
class FastOutSlowInInterpolator (line 10) | public class FastOutSlowInInterpolator extends LookupTableInterpolator {
method FastOutSlowInInterpolator (line 43) | public FastOutSlowInInterpolator() {
FILE: animer/src/main/java/com/martinrgb/animer/core/interpolator/AndroidNative/LinearInterpolator.java
class LinearInterpolator (line 10) | public class LinearInterpolator extends AnInterpolator {
method LinearInterpolator (line 11) | public LinearInterpolator() {
method LinearInterpolator (line 14) | public LinearInterpolator(Context context, AttributeSet attrs) {
method getInterpolation (line 17) | public float getInterpolation(float input) {
FILE: animer/src/main/java/com/martinrgb/animer/core/interpolator/AndroidNative/LinearOutSlowInInterpolator.java
class LinearOutSlowInInterpolator (line 10) | public class LinearOutSlowInInterpolator extends LookupTableInterpolator {
method LinearOutSlowInInterpolator (line 43) | public LinearOutSlowInInterpolator() {
FILE: animer/src/main/java/com/martinrgb/animer/core/interpolator/AndroidNative/LookupTableInterpolator.java
class LookupTableInterpolator (line 10) | public class LookupTableInterpolator extends AnInterpolator {
method LookupTableInterpolator (line 14) | protected LookupTableInterpolator(float[] values) {
method getInterpolation (line 19) | @Override
FILE: animer/src/main/java/com/martinrgb/animer/core/interpolator/AndroidNative/OvershootInterpolator.java
class OvershootInterpolator (line 5) | public class OvershootInterpolator extends AnInterpolator {
method OvershootInterpolator (line 11) | public OvershootInterpolator() {
method OvershootInterpolator (line 16) | public OvershootInterpolator(float tension) {
method getInterpolation (line 22) | public float getInterpolation(float t) {
method resetArgValue (line 29) | @Override
FILE: animer/src/main/java/com/martinrgb/animer/core/interpolator/AndroidNative/PathInterpolator.java
class PathInterpolator (line 7) | public class PathInterpolator extends AnInterpolator {
method PathInterpolator (line 16) | public PathInterpolator(float controlX1, float controlY1, float contro...
method resetArgValue (line 29) | @Override
method initCubic (line 48) | private void initCubic(float x1, float y1, float x2, float y2) {
method initPath (line 55) | private void initPath(Path path) {
method getInterpolation (line 88) | @Override
FILE: animer/src/main/java/com/martinrgb/animer/core/interpolator/AndroidSpringInterpolator.java
class AndroidSpringInterpolator (line 9) | public class AndroidSpringInterpolator extends AnInterpolator{
method AndroidSpringInterpolator (line 20) | public AndroidSpringInterpolator(float stiffness, float dampingratio,f...
method AndroidSpringInterpolator (line 34) | public AndroidSpringInterpolator(float stiffness, float dampingratio,f...
method resetArgValue (line 47) | @Override
method getInterpolation (line 65) | @Override
FILE: animer/src/main/java/com/martinrgb/animer/core/interpolator/AndroidSpringInterpolator2.java
class AndroidSpringInterpolator2 (line 7) | public class AndroidSpringInterpolator2 implements TimeInterpolator {
method AndroidSpringInterpolator2 (line 16) | public AndroidSpringInterpolator2(float stiffness, float dampingratio,...
method getInterpolation (line 22) | @Override
method setVelocityInSeconds (line 51) | public void setVelocityInSeconds(float velocity){
method setDampingRatio (line 55) | public void setDampingRatio(float dampingRatio){
method getDuration (line 59) | private void getDuration(float ratio){
FILE: animer/src/main/java/com/martinrgb/animer/core/interpolator/CustomBounceInterpolator.java
class CustomBounceInterpolator (line 3) | public class CustomBounceInterpolator extends AnInterpolator{
method computePulsation (line 24) | private void computePulsation() {
method computeFriction (line 28) | private void computeFriction() {
method computeInternalParameters (line 32) | private void computeInternalParameters() {
method CustomBounceInterpolator (line 39) | public CustomBounceInterpolator( float tension, float friction) {
method resetArgValue (line 50) | @Override
method CustomBounceInterpolator (line 62) | public CustomBounceInterpolator() {
method getInterpolation (line 66) | @Override
FILE: animer/src/main/java/com/martinrgb/animer/core/interpolator/CustomDampingInterpolator.java
class CustomDampingInterpolator (line 3) | public class CustomDampingInterpolator extends AnInterpolator{
method computePulsation (line 24) | private void computePulsation() {
method computeFriction (line 28) | private void computeFriction() {
method computeInternalParameters (line 32) | private void computeInternalParameters() {
method CustomDampingInterpolator (line 39) | public CustomDampingInterpolator( float tension, float friction) {
method resetArgValue (line 52) | @Override
method CustomDampingInterpolator (line 64) | public CustomDampingInterpolator() {
method getInterpolation (line 68) | @Override
FILE: animer/src/main/java/com/martinrgb/animer/core/interpolator/CustomMocosSpringInterpolator.java
class CustomMocosSpringInterpolator (line 3) | public class CustomMocosSpringInterpolator extends AnInterpolator{
method CustomMocosSpringInterpolator (line 13) | public CustomMocosSpringInterpolator(double tension, double damping) {
method CustomMocosSpringInterpolator (line 22) | public CustomMocosSpringInterpolator(double tension, double damping, d...
method init (line 35) | private void init(){
method resetArgValue (line 48) | @Override
method setInitialVelocity (line 65) | public void setInitialVelocity(double v0) {
method getDesiredDuration (line 77) | public double getDesiredDuration() {
method getInterpolation (line 81) | @Override
FILE: animer/src/main/java/com/martinrgb/animer/core/interpolator/CustomSpringInterpolator.java
class CustomSpringInterpolator (line 3) | public class CustomSpringInterpolator extends AnInterpolator{
method CustomSpringInterpolator (line 7) | public CustomSpringInterpolator(float factor) {
method CustomSpringInterpolator (line 12) | public CustomSpringInterpolator() {
method getInterpolation (line 16) | @Override
method resetArgValue (line 27) | @Override
FILE: animer/src/main/java/com/martinrgb/animer/core/interpolator/FlingSpringAnim.java
class FlingSpringAnim (line 28) | public class FlingSpringAnim {
method FlingSpringAnim (line 39) | public <K> FlingSpringAnim(K object, FloatPropertyCompat<K> property, ...
method getTargetPosition (line 64) | public float getTargetPosition() {
method updatePosition (line 68) | public void updatePosition(float startPosition, float targetPosition) {
method start (line 77) | public void start() {
method end (line 81) | public void end() {
FILE: animer/src/main/java/com/martinrgb/animer/core/math/calculator/FlingCalculator.java
class FlingCalculator (line 3) | public class FlingCalculator {
method FlingCalculator (line 10) | public FlingCalculator(float velocity,float friction) {
method calculate (line 17) | private float[] calculate() {
method getDuration (line 44) | public float getDuration() {
method getTransiton (line 48) | public float getTransiton() {
FILE: animer/src/main/java/com/martinrgb/animer/core/math/calculator/SpringInterpolatorCalculator.java
class SpringInterpolatorCalculator (line 4) | public class SpringInterpolatorCalculator{
method SpringInterpolatorCalculator (line 9) | public SpringInterpolatorCalculator(double stiffness,double dampingrat...
method computeDamping (line 18) | public double computeDamping(double stiffness,double dampingRatio,doub...
method computeMaxValue (line 23) | private double computeMaxValue() {
method computeSpringMax (line 49) | private double computeSpringMax(double factor) {
method findCloseNum (line 64) | private double findCloseNum(double num) {
method getFactor (line 86) | public float getFactor(){
method getDuration (line 90) | public float getDuration(){
FILE: animer/src/main/java/com/martinrgb/animer/core/math/converter/AnSpringConverter.java
class AnSpringConverter (line 3) | abstract class AnSpringConverter {
method AnSpringConverter (line 20) | public AnSpringConverter() {
method computeDamping (line 25) | public double computeDamping(double stiffness,double dampingRatio,doub...
method computeDampingRatio (line 30) | public double computeDampingRatio(double tension,double friction,doubl...
method computeDuration (line 35) | public double computeDuration(double tension, double friction,double m...
method computeTension (line 55) | public double computeTension(double dampingratio,double duration,doubl...
method computeFriction (line 63) | public double computeFriction(double dampingratio,double tension,doubl...
method tensionConversion (line 70) | public double tensionConversion(double oValue) {
method frictionConversion (line 74) | public double frictionConversion(double oValue) {
method bouncyTesnionConversion (line 78) | public double bouncyTesnionConversion(double tension){
method bouncyFrictionConversion (line 82) | public double bouncyFrictionConversion(double friction){
method getParaS (line 86) | public double getParaS(double n,double start,double end){
method getParaB (line 90) | public double getParaB(double finalVal, double start,double end) {
method computeSpeed (line 109) | public double computeSpeed(double value,double startValue,double endVa...
method normalize (line 113) | public double normalize(double value, double startValue, double endVal...
method projectNormal (line 117) | public double projectNormal(double n, double start, double end) {
method linearInterpolation (line 121) | public double linearInterpolation(double t, double start, double end) {
method quadraticOutInterpolation (line 125) | public double quadraticOutInterpolation(double t, double start, double...
method b3Friction1 (line 131) | public double b3Friction1(double x) {
method b3Friction2 (line 136) | public double b3Friction2(double x) {
method b3Friction3 (line 141) | public double b3Friction3(double x) {
method b3Nobounce (line 146) | public double b3Nobounce(double tension) {
method computeDuration (line 158) | public double computeDuration(double stiffness, double dampingratio) {
method getStiffness (line 178) | public float getStiffness() {
method getDampingRatio (line 182) | public float getDampingRatio() {
method getDuration (line 186) | public float getDuration(){
method getArg (line 190) | public float getArg(int i) {
FILE: animer/src/main/java/com/martinrgb/animer/core/math/converter/AndroidSpringConverter.java
class AndroidSpringConverter (line 3) | public class AndroidSpringConverter extends AnSpringConverter {
method AndroidSpringConverter (line 7) | public AndroidSpringConverter(double stiffness,double dampingratio) {
method AndroidSpringConverter (line 12) | public AndroidSpringConverter(double stiffness,double dampingratio,dou...
method calculate (line 17) | private void calculate(double s,double d,double m,double v){
FILE: animer/src/main/java/com/martinrgb/animer/core/math/converter/DHOConverter.java
class DHOConverter (line 3) | public class DHOConverter extends AnSpringConverter {
method DHOConverter (line 7) | public DHOConverter(double stiffness,double damping) {
method DHOConverter (line 12) | public DHOConverter(double stiffness,double damping,double mass,double...
method calculate (line 17) | private void calculate(double s,double d,double m,double v){
FILE: animer/src/main/java/com/martinrgb/animer/core/math/converter/OrigamiPOPConverter.java
class OrigamiPOPConverter (line 3) | public class OrigamiPOPConverter extends AnSpringConverter {
method OrigamiPOPConverter (line 7) | public OrigamiPOPConverter(double bounciness,double speed) {
method OrigamiPOPConverter (line 12) | public OrigamiPOPConverter(double bounciness,double speed,double mass,...
method calculate (line 17) | private void calculate(double b,double s,double m,double v){
FILE: animer/src/main/java/com/martinrgb/animer/core/math/converter/RK4Converter.java
class RK4Converter (line 3) | public class RK4Converter extends AnSpringConverter {
method RK4Converter (line 7) | public RK4Converter(double tension,double friction) {
method RK4Converter (line 12) | public RK4Converter(double tension,double friction,double mass,double ...
method calculate (line 17) | private void calculate(double t,double f,double m,double v){
FILE: animer/src/main/java/com/martinrgb/animer/core/math/converter/UIViewSpringConverter.java
class UIViewSpringConverter (line 3) | public class UIViewSpringConverter extends AnSpringConverter {
method UIViewSpringConverter (line 7) | public UIViewSpringConverter(double dampingratio,double duration) {
method UIViewSpringConverter (line 12) | public UIViewSpringConverter(double dampingratio,double duration,doubl...
method calculate (line 17) | private void calculate(double dampingRatio,double duration,double m,do...
FILE: animer/src/main/java/com/martinrgb/animer/core/property/AnProperty.java
class AnProperty (line 3) | public abstract class AnProperty<T> {
method AnProperty (line 5) | public AnProperty(String name) {
method getValue (line 9) | public abstract float getValue(T object);
method setValue (line 10) | public abstract void setValue(T object, float value);
FILE: animer/src/main/java/com/martinrgb/animer/core/solver/AnSolver.java
class AnSolver (line 8) | public class AnSolver extends Object{
method AnSolver (line 18) | public AnSolver(Object val1,Object val2,int mode){
type SolverListener (line 25) | public interface SolverListener {
method onSolverUpdate (line 26) | void onSolverUpdate(Object arg1, Object arg2);
method bindSolverListener (line 28) | public void bindSolverListener(SolverListener listener) {
method unBindSolverListener (line 31) | public void unBindSolverListener(){
method setArg1 (line 37) | public void setArg1(Object val){
method getArg1 (line 44) | public Object getArg1(){
method setArg2 (line 48) | public void setArg2(Object val){
method getArg2 (line 55) | public Object getArg2(){
method getSolverMode (line 59) | public int getSolverMode() {
method setSolverMode (line 63) | public void setSolverMode(int solverMode) {
FILE: animer/src/main/java/com/martinrgb/animer/core/state/PhysicsState.java
class PhysicsState (line 7) | public class PhysicsState {
method PhysicsState (line 15) | public PhysicsState() {
method PhysicsState (line 20) | public PhysicsState(float start) {
method PhysicsState (line 26) | public PhysicsState(float start,float end) {
method updatePhysics (line 36) | public void updatePhysics(float val,float vel){
method updatePhysicsVelocity (line 41) | public void updatePhysicsVelocity(float vel){
method updatePhysicsValue (line 45) | public void updatePhysicsValue(float val){
method getPhysicsValue (line 49) | public float getPhysicsValue() {
method getPhysicsVelocity (line 53) | public float getPhysicsVelocity() {
method setStateValue (line 61) | public void setStateValue(String key,float value){
method getStateValue (line 65) | public float getStateValue(String key){
FILE: animer/src/main/java/com/martinrgb/animer/core/util/AnSpringOscillateHelper.java
class AnSpringOscillateHelper (line 26) | public class AnSpringOscillateHelper {
class OscillateLimitedMode (line 28) | public abstract static class OscillateLimitedMode{ }
method AnSpringOscillateHelper (line 45) | public AnSpringOscillateHelper(OscillateLimitedMode oscillateLimitedMo...
method observe (line 56) | public void observe(SpringAnimation springAnimation,float currentVeloc...
method reset (line 110) | public void reset(){
method resetAccelerationAnimation (line 115) | private void resetAccelerationAnimation(SpringAnimation springAnimation){
method setLimitedCounts (line 132) | public void setLimitedCounts(int counts) {
method getLimitedCounts (line 136) | public float getLimitedCounts(){return this.mLimitedCounts; }
method setLimitedTime (line 138) | public void setLimitedTime(long time) {
method getLimitedTime (line 142) | public long getLimitedTime(){return this.mLimitedTime; }
method setLimitedMode (line 144) | private void setLimitedMode(OscillateLimitedMode oscillateLimitMode) {
method getLimitedMode (line 147) | private OscillateLimitedMode getLimitedMode() {
FILE: animer/src/main/java/com/martinrgb/animer/core/util/AnUtil.java
class AnUtil (line 4) | public class AnUtil {
method mapValueFromRangeToRange (line 15) | public static float mapValueFromRangeToRange(
method mapClampedValueFromRangeToRange (line 27) | public static float mapClampedValueFromRangeToRange(
method clamp (line 46) | public static double clamp(double value, double low, double high) {
FILE: animer/src/main/java/com/martinrgb/animer/monitor/AnConfigData.java
class AnConfigData (line 7) | public class AnConfigData {
method AnConfigData (line 13) | public AnConfigData(Object o1,Object o2,int mode) {
method AnConfigData (line 19) | public AnConfigData(Object o1,Object o2) {
method setArguments (line 24) | public void setArguments(String type,String arg1,Object arg1_min,Objec...
method addConfig (line 40) | public void addConfig(String key, Object value){
method getConfigs (line 44) | public LinkedHashMap getConfigs(){
method clearConfigs (line 48) | public void clearConfigs(){
method cloneConfigFrom (line 52) | public void cloneConfigFrom(LinkedHashMap<String,Object> targetMap){
method getKeyByString (line 61) | public Object getKeyByString(String key){
method getConfigByIndex (line 74) | public Object[] getConfigByIndex(int index){
method getMode (line 84) | public int getMode() {
method setMode (line 88) | public void setMode(int mode) {
FILE: animer/src/main/java/com/martinrgb/animer/monitor/AnConfigMap.java
class AnConfigMap (line 5) | public class AnConfigMap<K,V> extends LinkedHashMap {
method AnConfigMap (line 9) | public AnConfigMap() {
method getValue (line 13) | public Object getValue(int index){
method getKey (line 18) | public Object getKey(int index){
method resetIndex (line 23) | public void resetIndex(int index,Object value){
method getIndexByString (line 30) | public int getIndexByString(String string){
FILE: animer/src/main/java/com/martinrgb/animer/monitor/AnConfigRegistry.java
class AnConfigRegistry (line 23) | public class AnConfigRegistry {
method getInstance (line 27) | public static AnConfigRegistry getInstance() {
method AnConfigRegistry (line 34) | AnConfigRegistry() {
method initSolverConfig (line 39) | private void initSolverConfig(){
method removeAllSolverConfig (line 70) | public void removeAllSolverConfig(){
method addSolver (line 74) | public boolean addSolver(String configName, Animer.AnimerSolver animer...
method addAnimer (line 88) | public boolean addAnimer(String configName,Animer animer) {
method removeAnimerConfig (line 102) | public boolean removeAnimerConfig(Animer animer) {
method removeAllAnimerConfig (line 109) | public void removeAllAnimerConfig() {
method getAllAnimer (line 113) | public AnConfigMap<String,Animer> getAllAnimer() {
method getAllSolverTypes (line 117) | public AnConfigMap<String,Animer.AnimerSolver> getAllSolverTypes(){
FILE: animer/src/main/java/com/martinrgb/animer/monitor/AnConfigView.java
class AnConfigView (line 44) | public class AnConfigView extends FrameLayout {
method AnConfigView (line 101) | public AnConfigView(Context context) {
method AnConfigView (line 105) | public AnConfigView(Context context, AttributeSet attrs) {
method AnConfigView (line 109) | public AnConfigView(Context context, AttributeSet attrs, int defStyle) {
method initView (line 115) | private void initView(Context context) {
method refreshAnimerConfigs (line 233) | public void refreshAnimerConfigs() {
method initTypeConfigs (line 280) | private void initTypeConfigs() {
method recreateList (line 312) | private void recreateList(){
class SolverSelectedListener (line 399) | private class SolverSelectedListener implements AdapterView.OnItemSele...
method onItemSelected (line 401) | @Override
method onNothingSelected (line 465) | @Override
method redefineMinMax (line 470) | private void redefineMinMax(Animer.AnimerSolver animerSolver){
method updateSeekBars (line 494) | private void updateSeekBars(Animer.AnimerSolver animerSolver) {
class EditTextListener (line 534) | private class EditTextListener implements TextWatcher{
method EditTextListener (line 537) | public EditTextListener(EditText editText,int index) {
method beforeTextChanged (line 542) | @Override
method onTextChanged (line 546) | @Override
method afterTextChanged (line 550) | @Override
method isNumeric (line 587) | public static boolean isNumeric(String strNum) {
class SeekbarListener (line 599) | private class SeekbarListener implements SeekBar.OnSeekBarChangeListen...
method onProgressChanged (line 601) | @Override
method onStartTrackingTouch (line 696) | @Override
method onStopTrackingTouch (line 702) | @Override
method getCurveModeByString (line 717) | private void getCurveModeByString(){
method getConvertValueByIndexAndType (line 727) | private Object getConvertValueByIndexAndType(int i,String type){
method setRevealed (line 766) | public void setRevealed(boolean boo){
class OnNubTouchListener (line 770) | private class OnNubTouchListener implements View.OnTouchListener {
method onTouch (line 771) | @Override
class OnFPSTouchListener (line 810) | private class OnFPSTouchListener implements View.OnTouchListener {
method onTouch (line 811) | @Override
method dpToPx (line 872) | public static int dpToPx(float dp, Resources res) {
method createLayoutParams (line 876) | public static FrameLayout.LayoutParams createLayoutParams(int width, i...
FILE: animer/src/main/java/com/martinrgb/animer/monitor/AnSpinnerAdapter.java
class AnSpinnerAdapter (line 23) | public class AnSpinnerAdapter extends BaseAdapter {
method AnSpinnerAdapter (line 33) | public AnSpinnerAdapter(Context context,Resources resources) {
method getCount (line 41) | @Override
method getItem (line 46) | @Override
method getItemId (line 51) | @Override
method add (line 56) | public void add(String string) {
method clear (line 61) | public void clear() {
method getView (line 66) | @Override
method getDropDownView (line 91) | @Override
method setSelectedItemIndex (line 107) | public void setSelectedItemIndex(int i){
method dpToPx (line 111) | public static int dpToPx(float dp, Resources res) {
FILE: animer/src/main/java/com/martinrgb/animer/monitor/fps/Calculation.java
class Calculation (line 8) | public class Calculation
type Metric (line 10) | public enum Metric {GOOD, BAD, MEDIUM}
method getDroppedSet (line 12) | public static List<Integer> getDroppedSet(FPSConfig fpsConfig, List<Lo...
method droppedCount (line 32) | public static int droppedCount(long start, long end, float devRefreshR...
method calculateMetric (line 46) | public static AbstractMap.SimpleEntry<Metric, Long> calculateMetric(FP...
method getNumberOfFramesInSet (line 81) | protected static long getNumberOfFramesInSet(long realSampleLengthNs, ...
FILE: animer/src/main/java/com/martinrgb/animer/monitor/fps/FPSBuilder.java
class FPSBuilder (line 17) | public class FPSBuilder
method onBecameForeground (line 23) | @Override
method onBecameBackground (line 28) | @Override
method FPSBuilder (line 34) | protected FPSBuilder(){
method setFrameRate (line 43) | private void setFrameRate(Context context){
method hide (line 55) | protected static void hide(Context context) {
method show (line 76) | public void show(Context context) {
method addFrameDataCallback (line 110) | public FPSBuilder addFrameDataCallback(FrameDataCallback callback) {
method redFlagPercentage (line 121) | public FPSBuilder redFlagPercentage(float percentage) {
method yellowFlagPercentage (line 131) | public FPSBuilder yellowFlagPercentage(float percentage) {
method startingXPosition (line 141) | public FPSBuilder startingXPosition(int xPosition) {
method startingYPosition (line 152) | public FPSBuilder startingYPosition(int yPosition) {
method startingGravity (line 163) | public FPSBuilder startingGravity(int gravity) {
method overlayPermRequest (line 174) | private boolean overlayPermRequest(Context context) {
FILE: animer/src/main/java/com/martinrgb/animer/monitor/fps/FPSConfig.java
class FPSConfig (line 12) | public class FPSConfig implements Serializable
method FPSConfig (line 35) | protected FPSConfig()
method getSampleTimeInNs (line 38) | public long getSampleTimeInNs()
method getDeviceRefreshRateInNs (line 43) | public long getDeviceRefreshRateInNs()
FILE: animer/src/main/java/com/martinrgb/animer/monitor/fps/FPSDetector.java
class FPSDetector (line 9) | public class FPSDetector
method create (line 11) | public static FPSBuilder create(){
method hide (line 15) | public static void hide(Context context) {
FILE: animer/src/main/java/com/martinrgb/animer/monitor/fps/FPSFrameCallback.java
class FPSFrameCallback (line 14) | public class FPSFrameCallback implements Choreographer.FrameCallback
method FPSFrameCallback (line 22) | public FPSFrameCallback(FPSConfig fpsConfig) {
method setEnabled (line 28) | public void setEnabled(boolean enabled) {
method doFrame (line 32) | @Override
method collectSampleAndSend (line 71) | private void collectSampleAndSend(long frameTimeNanos)
method isFinishedWithSample (line 98) | private boolean isFinishedWithSample(long frameTimeNanos)
method destroy (line 103) | private void destroy()
FILE: animer/src/main/java/com/martinrgb/animer/monitor/fps/Foreground.java
class Foreground (line 51) | public class Foreground implements Application.ActivityLifecycleCallbacks {
type Listener (line 56) | public interface Listener {
method onBecameForeground (line 58) | public void onBecameForeground();
method onBecameBackground (line 60) | public void onBecameBackground();
method init (line 80) | public static Foreground init(Application application){
method get (line 88) | public static Foreground get(Application application){
method get (line 95) | public static Foreground get(Context ctx){
method get (line 108) | public static Foreground get(){
method isForeground (line 117) | public boolean isForeground(){
method isBackground (line 121) | public boolean isBackground(){
method addListener (line 125) | public void addListener(Listener listener){
method removeListener (line 129) | public void removeListener(Listener listener){
method onActivityResumed (line 133) | @Override
method onActivityPaused (line 156) | @Override
method onActivityCreated (line 183) | @Override
method onActivityStarted (line 186) | @Override
method onActivityStopped (line 189) | @Override
method onActivitySaveInstanceState (line 192) | @Override
method onActivityDestroyed (line 195) | @Override
FILE: animer/src/main/java/com/martinrgb/animer/monitor/fps/FrameDataCallback.java
type FrameDataCallback (line 7) | public interface FrameDataCallback
method doFrame (line 17) | void doFrame(long previousFrameNS, long currentFrameNS, int droppedFra...
FILE: animer/src/main/java/com/martinrgb/animer/monitor/shader/ShaderProgram.java
class ShaderProgram (line 17) | public class ShaderProgram {
method ShaderProgram (line 51) | public ShaderProgram(Context context) {
method setOnCreate (line 58) | public void setOnCreate(){
method setOnChange (line 93) | public void setOnChange(int width, int height){
method setOnDrawFrame (line 104) | public void setOnDrawFrame(float[] resolution,float time,float[] facto...
FILE: animer/src/main/java/com/martinrgb/animer/monitor/shader/ShaderRenderer.java
class ShaderRenderer (line 15) | public class ShaderRenderer implements GLSurfaceView.Renderer {
method ShaderRenderer (line 27) | public ShaderRenderer(Context context) {
method onSurfaceCreated (line 31) | @Override
method onSurfaceChanged (line 43) | @Override
method onDrawFrame (line 51) | @Override
method setFactorInput (line 67) | public void setFactorInput(float factor,int i){
method setMainColor (line 71) | public void setMainColor(float r,float g,float b){
method setSecondaryColor (line 77) | public void setSecondaryColor(float r,float g,float b){
method setCurveMode (line 83) | public void setCurveMode(float i){
method setDuration (line 87) | public void setDuration(float i){
method resetTime (line 93) | public void resetTime(){
FILE: animer/src/main/java/com/martinrgb/animer/monitor/shader/ShaderSurfaceView.java
class ShaderSurfaceView (line 10) | public class ShaderSurfaceView extends GLSurfaceView {
method ShaderSurfaceView (line 13) | public ShaderSurfaceView(Context context) {
method ShaderSurfaceView (line 18) | public ShaderSurfaceView(Context context, AttributeSet attrs) {
method setRenderer (line 22) | private void setRenderer(Context context) {
method getRenderer (line 34) | public ShaderRenderer getRenderer() {
method onTouchEvent (line 38) | @Override
method setFactorInput (line 43) | public void setFactorInput(float factor,int i){
method setMainColor (line 47) | public void setMainColor(float r,float g,float b){
method setSecondaryColor (line 51) | public void setSecondaryColor(float r,float g,float b){
method setCurveMode (line 55) | public void setCurveMode(float i){
method setDuration (line 59) | public void setDuration(float i){
method resetTime (line 63) | public void resetTime(){renderer.resetTime();}
FILE: animer/src/main/java/com/martinrgb/animer/monitor/shader/util/FPSCounter.java
class FPSCounter (line 6) | public class FPSCounter {
method logFrameRate (line 11) | public static void logFrameRate(){
method getFPS (line 23) | public static int getFPS() {
FILE: animer/src/main/java/com/martinrgb/animer/monitor/shader/util/LoggerConfig.java
class LoggerConfig (line 3) | public class LoggerConfig {
FILE: animer/src/main/java/com/martinrgb/animer/monitor/shader/util/ShaderHelper.java
class ShaderHelper (line 18) | public class ShaderHelper {
method complieVertexShader (line 22) | public static int complieVertexShader(String shaderCode){
method complieFragmentShader (line 27) | public static int complieFragmentShader(String shaderCode){
method compileShader (line 32) | private static int compileShader(int type,String shaderCode){
method linkProgram (line 73) | public static int linkProgram(int vertexShaderId,int fragmentShaderId){
method validateProgram (line 117) | public static boolean validateProgram(int programObjectId){
method buildProgram (line 129) | public static int buildProgram(String vertexShaderSource,String fragme...
FILE: animer/src/main/java/com/martinrgb/animer/monitor/shader/util/TextReader.java
class TextReader (line 11) | public class TextReader {
method readTextFileFromResource (line 13) | public static String readTextFileFromResource(Context context, int res...
FILE: app/src/androidTest/java/com/martinrgb/animerexample/ExampleInstrumentedTest.java
class ExampleInstrumentedTest (line 18) | @RunWith(AndroidJUnit4.class)
method useAppContext (line 20) | @Test
FILE: app/src/main/java/com/martinrgb/animerexample/MainActivity.java
class MainActivity (line 21) | public class MainActivity extends AppCompatActivity {
method onCreate (line 30) | @Override
method deleteBars (line 165) | private void deleteBars() {
FILE: app/src/main/java/com/martinrgb/animerexample/PrototypeActivity.java
class PrototypeActivity (line 21) | public class PrototypeActivity extends AppCompatActivity {
method onCreate (line 40) | @Override
method setAnimerSystem (line 138) | private void setAnimerSystem() {
method getDisplayPoint (line 254) | private void getDisplayPoint() {
method deleteBars (line 261) | private void deleteBars() {
FILE: app/src/main/java/com/martinrgb/animerexample/ScrollerActivity.java
class ScrollerActivity (line 28) | public class ScrollerActivity extends AppCompatActivity {
method onCreate (line 38) | @Override
method createLayout (line 48) | private void createLayout(){
method addAnimerConfig (line 119) | private void addAnimerConfig(){
class ExampleRowView (line 131) | private class ExampleRowView extends LinearLayout {
method ExampleRowView (line 137) | public ExampleRowView(Context context) {
method setHeader (line 149) | public void setHeader(String text) {
method setSub (line 152) | public void setSub(String text) {
method setImage (line 155) | public void setImage(int id) {
method getRootLayout (line 159) | public LinearLayout getRootLayout(){
method deleteBars (line 164) | private void deleteBars() {
method measureDisplay (line 171) | private void measureDisplay() {
method dpToPx (line 183) | public static int dpToPx(float dp, Resources res) {
FILE: app/src/main/java/com/martinrgb/animerexample/SmoothCornersImage.java
class SmoothCornersImage (line 25) | public class SmoothCornersImage extends AppCompatImageView {
method SmoothCornersImage (line 43) | public SmoothCornersImage(Context context) {
method SmoothCornersImage (line 48) | public SmoothCornersImage(Context context, AttributeSet attrs) {
method SmoothCornersImage (line 53) | public SmoothCornersImage(Context context, AttributeSet attrs, int def...
method getAttributes (line 58) | private void getAttributes(AttributeSet attr) {
method onSizeChanged (line 81) | @Override
method setImageBitmap (line 114) | @Override
method setImageDrawable (line 120) | @Override
method onDraw (line 147) | @Override
method SketchRealSmoothRect (line 207) | public Path SketchRealSmoothRect(
method drawAndroidRoundRect (line 294) | public void drawAndroidRoundRect(
method getRoundRadius (line 342) | public float getRoundRadius() {
method setRoundRadius (line 346) | public void setRoundRadius(float radius){
method getMAXRadius (line 351) | public float getMAXRadius(float width,float height){
method getRadiusInMaxRange (line 361) | private float getRadiusInMaxRange(float width,float height,float radiu...
method getRectSize (line 366) | public PointF getRectSize(){
method setRectSize (line 370) | public void setRectSize(float width,float height){
method getRectWidth (line 377) | private float getRectWidth() {
method setRectWidth (line 381) | private void setRectWidth(float WIDTH) {
method getRectHeight (line 386) | private float getRectHeight() {
method setRectHeight (line 390) | private void setRectHeight(float HEIGHT) {
method isSquare (line 396) | public boolean isSquare() {
method setIsSquare (line 400) | public void setIsSquare(boolean square) {
method setRectRoundEnable (line 405) | public void setRectRoundEnable(boolean tl,boolean tr,boolean bl,boolea...
FILE: app/src/test/java/com/martinrgb/animerexample/ExampleUnitTest.java
class ExampleUnitTest (line 12) | public class ExampleUnitTest {
method addition_isCorrect (line 13) | @Test
Condensed preview — 122 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (556K chars).
[
{
"path": ".gitignore",
"chars": 1065,
"preview": "# Built application files\n*.apk\n*.ap_\n\n*.DS_Store\n\n# Files for the ART/Dalvik VM\n*.dex\n\n# Java class files\n*.class\n\n# Ge"
},
{
"path": "LICENSE",
"chars": 11350,
"preview": " Apache License\n Version 2.0, January 2004\n "
},
{
"path": "README.md",
"chars": 10384,
"preview": "<img src=\"https://raw.githubusercontent.com/MartinRGB/Animer/master/art/logo.png?token=ABVV6IRDJX54663FGBF3NAC5633SY\" al"
},
{
"path": "README.zh.md",
"chars": 9471,
"preview": "<img src=\"https://raw.githubusercontent.com/MartinRGB/Animer/master/art/logo.png?token=ABVV6IRDJX54663FGBF3NAC5633SY\" al"
},
{
"path": "animer/.gitignore",
"chars": 7,
"preview": "/build\n"
},
{
"path": "animer/build.gradle",
"chars": 4141,
"preview": "apply plugin: 'com.android.library'\napply plugin: 'com.github.dcendents.android-maven'\napply plugin: 'com.jfrog.bintray'"
},
{
"path": "animer/consumer-rules.pro",
"chars": 0,
"preview": ""
},
{
"path": "animer/proguard-rules.pro",
"chars": 751,
"preview": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguar"
},
{
"path": "animer/src/main/AndroidManifest.xml",
"chars": 107,
"preview": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n package=\"com.martinrgb.animer\" />\n"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/Animer.java",
"chars": 36364,
"preview": "package com.martinrgb.animer;\n\n\nimport android.animation.Animator;\nimport android.animation.AnimatorListenerAdapter;\nimp"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/component/overscroller/launcher3/FlingSpringAnim.java",
"chars": 3602,
"preview": "/*\r\n * Copyright (C) 2019 The Android Open Source Project\r\n *\r\n * Licensed under the Apache License, Version 2.0 (the \"L"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/component/overscroller/launcher3/Interpolators.java",
"chars": 11111,
"preview": "package com.martinrgb.animer.component.overscroller.launcher3;\r\n//import static com.android.launcher3.util.DefaultDispla"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/component/overscroller/launcher3/OverScroller.java",
"chars": 32820,
"preview": "/*\r\n * Copyright (C) 2010 The Android Open Source Project\r\n *\r\n * Licensed under the Apache License, Version 2.0 (the \"L"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/component/overscrolllayout/.gitkeep",
"chars": 1,
"preview": "\n"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/component/recyclerview/AnRecyclerView.java",
"chars": 16401,
"preview": "package com.martinrgb.animer.component.recyclerview;\n\nimport android.content.Context;\nimport android.content.res.Resourc"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/component/scrollview/AnOverScroller.java",
"chars": 15115,
"preview": "package com.martinrgb.animer.component.scrollview;\n\nimport android.content.Context;\nimport android.util.Log;\nimport andr"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/component/scrollview/AnScrollView.java",
"chars": 79934,
"preview": "package com.martinrgb.animer.component.scrollview;\n\nimport android.content.Context;\nimport android.graphics.Canvas;\nimpo"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/core/interpolator/AnInterpolator.java",
"chars": 4496,
"preview": "package com.martinrgb.animer.core.interpolator;\n\n\nimport android.animation.TimeInterpolator;\n\n/**\n * An interpolator def"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/core/interpolator/AndroidNative/AccelerateDecelerateInterpolator.java",
"chars": 662,
"preview": "package com.martinrgb.animer.core.interpolator.AndroidNative;\n\nimport android.content.Context;\nimport android.content.re"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/core/interpolator/AndroidNative/AccelerateInterpolator.java",
"chars": 921,
"preview": "package com.martinrgb.animer.core.interpolator.AndroidNative;\n\nimport com.martinrgb.animer.core.interpolator.AnInterpola"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/core/interpolator/AndroidNative/AnticipateInterpolator.java",
"chars": 1009,
"preview": "package com.martinrgb.animer.core.interpolator.AndroidNative;\n\nimport com.martinrgb.animer.core.interpolator.AnInterpola"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/core/interpolator/AndroidNative/AnticipateOvershootInterpolator.java",
"chars": 1455,
"preview": "package com.martinrgb.animer.core.interpolator.AndroidNative;\n\nimport com.martinrgb.animer.core.interpolator.AnInterpola"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/core/interpolator/AndroidNative/BounceInterpolator.java",
"chars": 1012,
"preview": "package com.martinrgb.animer.core.interpolator.AndroidNative;\n\nimport android.content.Context;\nimport android.content.re"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/core/interpolator/AndroidNative/CycleInterpolator.java",
"chars": 618,
"preview": "package com.martinrgb.animer.core.interpolator.AndroidNative;\n\nimport com.martinrgb.animer.core.interpolator.AnInterpola"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/core/interpolator/AndroidNative/DecelerateInterpolator.java",
"chars": 906,
"preview": "package com.martinrgb.animer.core.interpolator.AndroidNative;\n\nimport com.martinrgb.animer.core.interpolator.AnInterpola"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/core/interpolator/AndroidNative/FastOutLinearInInterpolator.java",
"chars": 2639,
"preview": "package com.martinrgb.animer.core.interpolator.AndroidNative;\n\nimport android.content.Context;\nimport android.content.re"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/core/interpolator/AndroidNative/FastOutSlowInInterpolator.java",
"chars": 2635,
"preview": "package com.martinrgb.animer.core.interpolator.AndroidNative;\n\nimport android.content.Context;\nimport android.content.re"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/core/interpolator/AndroidNative/LinearInterpolator.java",
"chars": 524,
"preview": "package com.martinrgb.animer.core.interpolator.AndroidNative;\n\nimport android.content.Context;\nimport android.content.re"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/core/interpolator/AndroidNative/LinearOutSlowInInterpolator.java",
"chars": 2639,
"preview": "package com.martinrgb.animer.core.interpolator.AndroidNative;\n\nimport android.content.Context;\nimport android.content.re"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/core/interpolator/AndroidNative/LookupTableInterpolator.java",
"chars": 1362,
"preview": "package com.martinrgb.animer.core.interpolator.AndroidNative;\n\nimport android.content.Context;\nimport android.content.re"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/core/interpolator/AndroidNative/OvershootInterpolator.java",
"chars": 846,
"preview": "package com.martinrgb.animer.core.interpolator.AndroidNative;\n\nimport com.martinrgb.animer.core.interpolator.AnInterpola"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/core/interpolator/AndroidNative/PathInterpolator.java",
"chars": 3589,
"preview": "package com.martinrgb.animer.core.interpolator.AndroidNative;\n\nimport android.graphics.Path;\n\nimport com.martinrgb.anime"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/core/interpolator/AndroidSpringInterpolator.java",
"chars": 3248,
"preview": "package com.martinrgb.animer.core.interpolator;\n\n// Interpolator Version of Android's SpringAnimation\n\nimport android.ut"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/core/interpolator/AndroidSpringInterpolator2.java",
"chars": 2281,
"preview": "package com.martinrgb.animer.core.interpolator;\n\nimport android.animation.TimeInterpolator;\nimport android.util.Log;\n\n\np"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/core/interpolator/CustomBounceInterpolator.java",
"chars": 2496,
"preview": "package com.martinrgb.animer.core.interpolator;\n\npublic class CustomBounceInterpolator extends AnInterpolator{\n\n //Pa"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/core/interpolator/CustomDampingInterpolator.java",
"chars": 2559,
"preview": "package com.martinrgb.animer.core.interpolator;\n\npublic class CustomDampingInterpolator extends AnInterpolator{\n\n //P"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/core/interpolator/CustomMocosSpringInterpolator.java",
"chars": 2781,
"preview": "package com.martinrgb.animer.core.interpolator;\n\npublic class CustomMocosSpringInterpolator extends AnInterpolator{\n\n "
},
{
"path": "animer/src/main/java/com/martinrgb/animer/core/interpolator/CustomSpringInterpolator.java",
"chars": 869,
"preview": "package com.martinrgb.animer.core.interpolator;\n\npublic class CustomSpringInterpolator extends AnInterpolator{\n\n priv"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/core/interpolator/FlingSpringAnim.java",
"chars": 3575,
"preview": "/*\r\n * Copyright (C) 2019 The Android Open Source Project\r\n *\r\n * Licensed under the Apache License, Version 2.0 (the \"L"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/core/math/calculator/FlingCalculator.java",
"chars": 1289,
"preview": "package com.martinrgb.animer.core.math.calculator;\n\npublic class FlingCalculator {\n\n private float mFriction;\n pri"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/core/math/calculator/SpringInterpolatorCalculator.java",
"chars": 2677,
"preview": "package com.martinrgb.animer.core.math.calculator;\n\n\npublic class SpringInterpolatorCalculator{\n\n private double mSti"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/core/math/converter/AnSpringConverter.java",
"chars": 5967,
"preview": "package com.martinrgb.animer.core.math.converter;\n\nabstract class AnSpringConverter {\n\n public double mMass = 1;\n "
},
{
"path": "animer/src/main/java/com/martinrgb/animer/core/math/converter/AndroidSpringConverter.java",
"chars": 1331,
"preview": "package com.martinrgb.animer.core.math.converter;\n\npublic class AndroidSpringConverter extends AnSpringConverter {\n\n "
},
{
"path": "animer/src/main/java/com/martinrgb/animer/core/math/converter/DHOConverter.java",
"chars": 1279,
"preview": "package com.martinrgb.animer.core.math.converter;\n\npublic class DHOConverter extends AnSpringConverter {\n\n private bo"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/core/math/converter/OrigamiPOPConverter.java",
"chars": 1323,
"preview": "package com.martinrgb.animer.core.math.converter;\n\npublic class OrigamiPOPConverter extends AnSpringConverter {\n\n pri"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/core/math/converter/RK4Converter.java",
"chars": 1274,
"preview": "package com.martinrgb.animer.core.math.converter;\n\npublic class RK4Converter extends AnSpringConverter {\n\n private bo"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/core/math/converter/UIViewSpringConverter.java",
"chars": 1361,
"preview": "package com.martinrgb.animer.core.math.converter;\n\npublic class UIViewSpringConverter extends AnSpringConverter {\n\n p"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/core/property/AnProperty.java",
"chars": 295,
"preview": "package com.martinrgb.animer.core.property;\n\npublic abstract class AnProperty<T> {\n final String mPropertyName;\n p"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/core/solver/AnSolver.java",
"chars": 1592,
"preview": "package com.martinrgb.animer.core.solver;\n\nimport android.animation.TimeInterpolator;\nimport android.util.Log;\nimport an"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/core/state/PhysicsState.java",
"chars": 1745,
"preview": "package com.martinrgb.animer.core.state;\n\nimport android.util.Log;\nimport java.util.HashMap;\nimport java.util.Map;\n\npubl"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/core/util/AnSpringOscillateHelper.java",
"chars": 5421,
"preview": "package com.martinrgb.animer.core.util;\n\nimport android.os.SystemClock;\nimport androidx.dynamicanimation.animation.Sprin"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/core/util/AnUtil.java",
"chars": 1668,
"preview": "package com.martinrgb.animer.core.util;\n\n// From Facebook Rebound\npublic class AnUtil {\n\n /**\n * Map a value with"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/monitor/AnConfigData.java",
"chars": 2375,
"preview": "package com.martinrgb.animer.monitor;\n\nimport android.util.Log;\n\nimport java.util.LinkedHashMap;\n\npublic class AnConfigD"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/monitor/AnConfigMap.java",
"chars": 1047,
"preview": "package com.martinrgb.animer.monitor;\n\nimport java.util.LinkedHashMap;\n\npublic class AnConfigMap<K,V> extends LinkedHash"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/monitor/AnConfigRegistry.java",
"chars": 9029,
"preview": "package com.martinrgb.animer.monitor;\n\nimport com.martinrgb.animer.Animer;\nimport com.martinrgb.animer.core.interpolator"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/monitor/AnConfigView.java",
"chars": 42804,
"preview": "package com.martinrgb.animer.monitor;\n\nimport android.content.Context;\nimport android.content.res.ColorStateList;\nimport"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/monitor/AnSpinnerAdapter.java",
"chars": 3362,
"preview": "package com.martinrgb.animer.monitor;\n\nimport android.content.Context;\nimport android.content.res.Resources;\nimport andr"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/monitor/fps/Calculation.java",
"chars": 2810,
"preview": "package com.martinrgb.animer.monitor.fps;\n\nimport java.util.AbstractMap;\nimport java.util.ArrayList;\nimport java.util.Li"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/monitor/fps/FPSBuilder.java",
"chars": 5563,
"preview": "package com.martinrgb.animer.monitor.fps;\n\n\nimport android.app.Application;\nimport android.content.Context;\nimport andro"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/monitor/fps/FPSConfig.java",
"chars": 1375,
"preview": "package com.martinrgb.animer.monitor.fps;\n\n\nimport android.view.Gravity;\n\nimport java.io.Serializable;\nimport java.util."
},
{
"path": "animer/src/main/java/com/martinrgb/animer/monitor/fps/FPSDetector.java",
"chars": 343,
"preview": "package com.martinrgb.animer.monitor.fps;\n\n\nimport android.content.Context;\n\n/**\n * Created by brianplummer on 8/29/15.\n"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/monitor/fps/FPSFrameCallback.java",
"chars": 3207,
"preview": "package com.martinrgb.animer.monitor.fps;\n\n\nimport android.util.Log;\nimport android.view.Choreographer;\n\nimport java.uti"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/monitor/fps/Foreground.java",
"chars": 5684,
"preview": "package com.martinrgb.animer.monitor.fps;\n\nimport java.util.AbstractMap;\nimport java.util.ArrayList;\nimport java.util.Li"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/monitor/fps/FrameDataCallback.java",
"chars": 654,
"preview": "package com.martinrgb.animer.monitor.fps;\n\n\n/**\n * Created by brianplummer on 11/12/15.\n */\npublic interface FrameDataCa"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/monitor/shader/ShaderProgram.java",
"chars": 5988,
"preview": "package com.martinrgb.animer.monitor.shader;\n\nimport android.content.Context;\nimport android.opengl.GLES20;\nimport andro"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/monitor/shader/ShaderRenderer.java",
"chars": 2493,
"preview": "package com.martinrgb.animer.monitor.shader;\n\nimport android.content.Context;\nimport android.opengl.GLES20;\nimport andro"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/monitor/shader/ShaderSurfaceView.java",
"chars": 1467,
"preview": "package com.martinrgb.animer.monitor.shader;\n\nimport android.content.Context;\nimport android.graphics.PixelFormat;\nimpor"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/monitor/shader/util/FPSCounter.java",
"chars": 616,
"preview": "package com.martinrgb.animer.monitor.shader.util;\n\nimport android.os.SystemClock;\nimport android.util.Log;\n\npublic class"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/monitor/shader/util/LoggerConfig.java",
"chars": 123,
"preview": "package com.martinrgb.animer.monitor.shader.util;\n\npublic class LoggerConfig {\n public static final boolean ON = true"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/monitor/shader/util/ShaderHelper.java",
"chars": 4326,
"preview": "package com.martinrgb.animer.monitor.shader.util;\n\nimport android.opengl.GLES20;\nimport android.util.Log;\n\nimport static"
},
{
"path": "animer/src/main/java/com/martinrgb/animer/monitor/shader/util/TextReader.java",
"chars": 1025,
"preview": "package com.martinrgb.animer.monitor.shader.util;\n\nimport android.content.Context;\nimport android.content.res.Resources;"
},
{
"path": "animer/src/main/res/drawable/background_spinner.xml",
"chars": 419,
"preview": "<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n <item>\n <shape android:shape=\"rectan"
},
{
"path": "animer/src/main/res/drawable/gradient.xml",
"chars": 349,
"preview": "<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n <item>\n <shape>\n <gradient\n "
},
{
"path": "animer/src/main/res/drawable/ic_button_background.xml",
"chars": 440,
"preview": "<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n <item android:width=\"60dp\"\n androi"
},
{
"path": "animer/src/main/res/drawable/ic_edit_border.xml",
"chars": 902,
"preview": "<vector android:height=\"20dp\" android:viewportHeight=\"60\"\n android:viewportWidth=\"157\" android:width=\"52dp\" xmlns:and"
},
{
"path": "animer/src/main/res/drawable/ic_grid.xml",
"chars": 6902,
"preview": "<vector android:height=\"24dp\" android:viewportHeight=\"480\"\n android:viewportWidth=\"936\" android:width=\"24dp\" xmlns:an"
},
{
"path": "animer/src/main/res/drawable/ic_nub.xml",
"chars": 1703,
"preview": "<vector android:height=\"26dp\" android:viewportHeight=\"78\"\n android:viewportWidth=\"338\" android:width=\"112dp\"\n xmln"
},
{
"path": "animer/src/main/res/drawable/ic_nub2.xml",
"chars": 2137,
"preview": "<vector android:height=\"46dp\" android:viewportHeight=\"138\"\n android:viewportWidth=\"338\" android:width=\"112dp\"\n xml"
},
{
"path": "animer/src/main/res/drawable/ic_spinner.xml",
"chars": 485,
"preview": "<vector android:height=\"12dp\" android:viewportHeight=\"36\"\n android:viewportWidth=\"36\" android:width=\"12dp\" xmlns:andr"
},
{
"path": "animer/src/main/res/drawable/ic_thumb.xml",
"chars": 682,
"preview": "<vector android:height=\"12dp\" android:viewportHeight=\"36\"\n android:viewportWidth=\"36\" android:width=\"12dp\" xmlns:andr"
},
{
"path": "animer/src/main/res/drawable/popbackground_spinner.xml",
"chars": 385,
"preview": "<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n <item>\n <shape android:shape=\"rectan"
},
{
"path": "animer/src/main/res/drawable/text_cursor.xml",
"chars": 274,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape\n xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android"
},
{
"path": "animer/src/main/res/layout/config_view.xml",
"chars": 3827,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns"
},
{
"path": "animer/src/main/res/raw/simplefrag.glsl",
"chars": 17510,
"preview": "#ifdef GL_ES\nprecision highp float;\n#endif\n\n//#extension GL_OES_standard_derivatives : enable\n\n#define PI 3.14159265359\n"
},
{
"path": "animer/src/main/res/raw/simplevert.glsl",
"chars": 3911,
"preview": "attribute vec4 a_position;\n\nuniform vec2 u_resolution;\nuniform float u_time;\nuniform mat4 u_MVPMatrix;\nuniform float u_"
},
{
"path": "animer/src/main/res/values/corlors.xml",
"chars": 839,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n <color name=\"mainColor\">#09CDFF</color>\n <color name=\"secondar"
},
{
"path": "animer/src/main/res/values/dimension.xml",
"chars": 232,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n <dimen name=\"margin_size\">4dp</dimen>\n <dimen name=\"padding_si"
},
{
"path": "animer/src/main/res/values/styles.xml",
"chars": 661,
"preview": "<resources>\n <style name=\"ActionBarThemeOverlay\" parent=\"\">\n <item name=\"android:textColorPrimary\">@color/seco"
},
{
"path": "app/.gitignore",
"chars": 7,
"preview": "/build\n"
},
{
"path": "app/build.gradle",
"chars": 1095,
"preview": "apply plugin: 'com.android.application'\n\nandroid {\n compileSdkVersion 29\n defaultConfig {\n applicationId \"c"
},
{
"path": "app/proguard-rules.pro",
"chars": 751,
"preview": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguar"
},
{
"path": "app/src/androidTest/java/com/martinrgb/animerexample/ExampleInstrumentedTest.java",
"chars": 724,
"preview": "package com.martinrgb.animerexample;\n\nimport android.content.Context;\n\nimport androidx.test.InstrumentationRegistry;\nimp"
},
{
"path": "app/src/main/AndroidManifest.xml",
"chars": 748,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n package="
},
{
"path": "app/src/main/java/com/martinrgb/animerexample/MainActivity.java",
"chars": 6193,
"preview": "package com.martinrgb.animerexample;\n\nimport androidx.appcompat.app.AppCompatActivity;\n\nimport android.os.Bundle;\nimport"
},
{
"path": "app/src/main/java/com/martinrgb/animerexample/PrototypeActivity.java",
"chars": 11618,
"preview": "package com.martinrgb.animerexample;\n\nimport android.graphics.Point;\nimport android.os.Bundle;\nimport android.view.Motio"
},
{
"path": "app/src/main/java/com/martinrgb/animerexample/ScrollerActivity.java",
"chars": 7847,
"preview": "package com.martinrgb.animerexample;\n\nimport android.content.Context;\nimport android.content.res.Resources;\nimport andro"
},
{
"path": "app/src/main/java/com/martinrgb/animerexample/SmoothCornersImage.java",
"chars": 14165,
"preview": "package com.martinrgb.animerexample;\n\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport andr"
},
{
"path": "app/src/main/res/drawable/background_elevation.xml",
"chars": 445,
"preview": "<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n <item>\n <shape android:shape=\"rectan"
},
{
"path": "app/src/main/res/drawable/ic_arrow.xml",
"chars": 957,
"preview": "<vector android:height=\"24dp\" android:viewportHeight=\"94\"\n android:viewportWidth=\"94\" android:width=\"24dp\" xmlns:andr"
},
{
"path": "app/src/main/res/drawable/ic_launcher_background.xml",
"chars": 5606,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:wi"
},
{
"path": "app/src/main/res/drawable/myrect.xml",
"chars": 215,
"preview": "<!-- res/drawable/myrect.xml -->\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:shape=\"re"
},
{
"path": "app/src/main/res/drawable-nodpi/mute.xml",
"chars": 11037,
"preview": "<animated-vector xmlns:android=\"http://schemas.android.com/apk/res/android\" xmlns:aapt=\"http://schemas.android.com/aapt\""
},
{
"path": "app/src/main/res/drawable-v24/ic_launcher_foreground.xml",
"chars": 1880,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:aapt=\"http://schemas.android.com/aapt\"\n "
},
{
"path": "app/src/main/res/layout/activity_main.xml",
"chars": 2587,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xm"
},
{
"path": "app/src/main/res/layout/activity_prototype.xml",
"chars": 2987,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xm"
},
{
"path": "app/src/main/res/layout/activity_scroller.xml",
"chars": 1590,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xm"
},
{
"path": "app/src/main/res/layout/custom_cell_view.xml",
"chars": 1316,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n and"
},
{
"path": "app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml",
"chars": 272,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n <b"
},
{
"path": "app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml",
"chars": 272,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n <b"
},
{
"path": "app/src/main/res/values/attr.xml",
"chars": 242,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n <declare-styleable name=\"SmoothCornersImage\">\n <attr name="
},
{
"path": "app/src/main/res/values/colors.xml",
"chars": 208,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n <color name=\"colorPrimary\">#008577</color>\n <color name=\"color"
},
{
"path": "app/src/main/res/values/dimension.xml",
"chars": 109,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n <dimen name=\"cell_size_dp\">100dp</dimen>\n</resources>\n"
},
{
"path": "app/src/main/res/values/strings.xml",
"chars": 77,
"preview": "<resources>\n <string name=\"app_name\">Animer Example</string>\n</resources>\n"
},
{
"path": "app/src/main/res/values/styles.xml",
"chars": 668,
"preview": "<resources>\n\n <!-- Base application theme. -->\n <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.DarkActionBar"
},
{
"path": "app/src/test/java/com/martinrgb/animerexample/ExampleUnitTest.java",
"chars": 388,
"preview": "package com.martinrgb.animerexample;\n\nimport org.junit.Test;\n\nimport static org.junit.Assert.*;\n\n/**\n * Example local un"
},
{
"path": "build.gradle",
"chars": 796,
"preview": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n r"
},
{
"path": "gradle/wrapper/gradle-wrapper.properties",
"chars": 233,
"preview": "#Tue May 26 17:09:15 CST 2020\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_"
},
{
"path": "gradle.properties",
"chars": 1073,
"preview": "# Project-wide Gradle settings.\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will ov"
},
{
"path": "gradlew",
"chars": 5296,
"preview": "#!/usr/bin/env sh\n\n##############################################################################\n##\n## Gradle start up"
},
{
"path": "gradlew.bat",
"chars": 2260,
"preview": "@if \"%DEBUG%\" == \"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@r"
},
{
"path": "settings.gradle",
"chars": 26,
"preview": "include ':app', ':animer'\n"
}
]
// ... and 1 more files (download for full content)
About this extraction
This page contains the full source code of the MartinRGB/Animer GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 122 files (510.4 KB), approximately 131.1k tokens, and a symbol index with 749 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.