├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── viewmover ├── gradle.properties ├── proguard-rules.pro ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── com │ │ └── scalified │ │ └── viewmover │ │ ├── movers │ │ ├── ViewMoverFactory.java │ │ ├── PositionViewMover.java │ │ ├── MarginViewMover.java │ │ └── ViewMover.java │ │ └── configuration │ │ └── MovingParams.java └── build.gradle ├── settings.gradle ├── gradle.properties ├── gradlew.bat ├── gradlew ├── README.md └── LICENSE /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Scalified/viewmover/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | *.iml 3 | .gradle 4 | build 5 | gen 6 | local.properties 7 | 8 | .metadata 9 | *.DS_Store 10 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: android 2 | 3 | jdk: 4 | - oraclejdk8 5 | 6 | android: 7 | components: 8 | - tools 9 | - platform-tools 10 | - build-tools-25.0.0 11 | - android-25 12 | 13 | script: 14 | - ./gradlew clean build --info 15 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sun Oct 30 23:49:05 EET 2016 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip 7 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 1.1.2 2 | 3 | 1. Fixed [**Animation end listener is missing in the library #3**](https://github.com/Scalified/viewmover/issues/3) 4 | 5 | # 1.1.1 6 | 7 | 1. Fixed movement for **KitKat API** (due to rendering issues in **KitKat**) 8 | 2. Changed the standard Android logging API to **SLF4J Logging API** 9 | 10 | # 1.0.1 11 | 12 | 1. Fixed **NullPointerException** in **MovingParams** 13 | 14 | # 1.0.0 15 | 16 | 1. The first release! Everything is new. 17 | -------------------------------------------------------------------------------- /viewmover/gradle.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2016 Scalified 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | POM_ARTIFACT_ID=viewmover 18 | POM_NAME=View Mover Library 19 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Scalified 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | rootProject.name = 'viewmover-root' 18 | include ':viewmover' 19 | -------------------------------------------------------------------------------- /viewmover/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2016 Scalified 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | -keep class * 18 | 19 | -keepclassmembers class * { 20 | *; 21 | } 22 | -------------------------------------------------------------------------------- /viewmover/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 21 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2016 Scalified 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | POM_GROUP_ID=com.scalified 18 | POM_VERSION=1.1.2 19 | 20 | POM_DESCRIPTION=View Mover Library for Android 21 | POM_URL=https://github.com/Scalified/viewmover 22 | POM_SCM_URL=https://github.com/Scalified/viewmover.git 23 | POM_SCM_CONNECTION=scm:git@https://github.com/Scalified/viewmover.git 24 | POM_SCM_DEV_CONNECTION=scm:git@https://github.com/Scalified/viewmover.git 25 | POM_LICENCE_NAME=Apache License, Version 2.0 26 | POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt 27 | -------------------------------------------------------------------------------- /viewmover/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Scalified 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | apply plugin: 'com.android.library' 18 | 19 | // Publishing 20 | if (hasProperty('AAR_PUBLISHING_SCRIPT')) { 21 | apply from: properties['AAR_PUBLISHING_SCRIPT'] 22 | } 23 | 24 | android { 25 | 26 | compileSdkVersion ANDROID_COMPILE_SDK_VERSION 27 | buildToolsVersion ANDROID_BUILD_TOOLS_VERSION 28 | 29 | compileOptions { 30 | sourceCompatibility JavaVersion.VERSION_1_7 31 | targetCompatibility JavaVersion.VERSION_1_7 32 | } 33 | 34 | buildTypes { 35 | release { 36 | minifyEnabled true 37 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 38 | 'proguard-rules.pro' 39 | } 40 | } 41 | 42 | defaultConfig { 43 | minSdkVersion ANDROID_MIN_SDK_VERSION 44 | targetSdkVersion ANDROID_TARGET_SDK_VERSION 45 | versionCode ANDROID_VERSION_CODE 46 | versionName version 47 | } 48 | 49 | } 50 | 51 | dependencies { 52 | compile 'com.scalified:uitools:1.1.2' 53 | compile 'org.slf4j:slf4j-api:1.7.9' 54 | } 55 | -------------------------------------------------------------------------------- /viewmover/src/main/java/com/scalified/viewmover/movers/ViewMoverFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Scalified 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.scalified.viewmover.movers; 18 | 19 | import android.os.Build; 20 | import android.view.View; 21 | import org.slf4j.Logger; 22 | import org.slf4j.LoggerFactory; 23 | 24 | /** 25 | * A factory class, which creates view mover instances 26 | * depending on the {@code BUILD VERSION} 27 | * 28 | * @author shell 29 | * @version 1.0.0 30 | * @since 1.0.0 31 | */ 32 | public abstract class ViewMoverFactory { 33 | 34 | /** 35 | * Logger 36 | */ 37 | private static final Logger LOGGER = LoggerFactory.getLogger(ViewMoverFactory.class); 38 | 39 | /** 40 | * Creates the {@link ViewMover} subclasses depending on the 41 | * {@code BUILD VERSION} 42 | * 43 | * @param view view to be moved 44 | * @return specific view mover 45 | */ 46 | public static ViewMover createInstance(View view) { 47 | ViewMover viewMover; 48 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN 49 | // KitKat is an exclusion because of its rendering issues 50 | && Build.VERSION.SDK_INT != Build.VERSION_CODES.KITKAT) { 51 | 52 | viewMover = new PositionViewMover(view); 53 | } else { 54 | viewMover = new MarginViewMover(view); 55 | } 56 | LOGGER.trace("Build version code is: {}. {} will be returned", 57 | Build.VERSION.SDK_INT, viewMover.getClass().getSimpleName()); 58 | return viewMover; 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /viewmover/src/main/java/com/scalified/viewmover/movers/PositionViewMover.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Scalified 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.scalified.viewmover.movers; 18 | 19 | import android.annotation.TargetApi; 20 | import android.os.Build; 21 | import android.view.View; 22 | import org.slf4j.Logger; 23 | import org.slf4j.LoggerFactory; 24 | 25 | /** 26 | * View mover class, which is used to move the view, based on view's visual position 27 | * within parent container 28 | *

29 | * Used for {@code TargetApi} {@link android.os.Build.VERSION_CODES#JELLY_BEAN} and higher 30 | * 31 | * @author shell 32 | * @version 1.0.0 33 | * @since 1.0.0 34 | */ 35 | class PositionViewMover extends ViewMover { 36 | 37 | /** 38 | * Logger 39 | */ 40 | private static final Logger LOGGER = LoggerFactory.getLogger(PositionViewMover.class); 41 | 42 | /** 43 | * Creates the {@link PositionViewMover} instance 44 | * 45 | * @param view view to be moved 46 | */ 47 | PositionViewMover(View view) { 48 | super(view); 49 | } 50 | 51 | /** 52 | * Changes the position of the view based on view's visual position within its parent container 53 | * 54 | * @param xAxisDelta X-axis delta in actual pixels 55 | * @param yAxisDelta Y-axis delta in actual pixels 56 | */ 57 | @TargetApi(Build.VERSION_CODES.JELLY_BEAN) 58 | @Override 59 | void changeViewPosition(float xAxisDelta, float yAxisDelta) { 60 | float endLeftBoundPointX = calculateEndLeftBound(xAxisDelta); 61 | float endTopBoundPointY = calculateEndTopBound(yAxisDelta); 62 | getView().setX(endLeftBoundPointX); 63 | getView().setY(endTopBoundPointY); 64 | LOGGER.trace("Updated view position: leftX = {}, topY = {}", endLeftBoundPointX, endTopBoundPointY); 65 | } 66 | 67 | /** 68 | * Calculates the resulting X coordinate of the view's left bound based on the 69 | * X position of the view and the X-axis delta 70 | * 71 | * @param xAxisDelta X-axis delta in actual pixels 72 | * @return resulting X coordinate of the view's left bound 73 | */ 74 | @TargetApi(Build.VERSION_CODES.JELLY_BEAN) 75 | @Override 76 | int calculateEndLeftBound(float xAxisDelta) { 77 | return (int) (getView().getX() + xAxisDelta); 78 | } 79 | 80 | /** 81 | * Calculates the resulting X coordinate of the view's right bound based on the 82 | * resulting X coordinate of the view's left bound and the view's width 83 | * 84 | * @param xAxisDelta X-axis delta in actual pixels 85 | * @return resulting X coordinate of the view's right bound 86 | */ 87 | @Override 88 | int calculateEndRightBound(float xAxisDelta) { 89 | return calculateEndLeftBound(xAxisDelta) + getView().getWidth(); 90 | } 91 | 92 | /** 93 | * Calculates the resulting Y coordinate of the view's top bound based on the 94 | * Y position of the view and the Y-axis delta 95 | * 96 | * @param yAxisDelta Y-axis delta in actual pixels 97 | * @return resulting Y coordinate of the view's top bound 98 | */ 99 | @TargetApi(Build.VERSION_CODES.JELLY_BEAN) 100 | @Override 101 | int calculateEndTopBound(float yAxisDelta) { 102 | return (int) (getView().getY() + yAxisDelta); 103 | } 104 | 105 | /** 106 | * Calculates the resulting Y coordinate of the view's bottom bound based on the 107 | * resulting Y coordinate of the view's top bound and the view's height 108 | * 109 | * @param yAxisDelta Y-axis delta in actual pixels 110 | * @return resulting Y coordinate of the view's bottom bound 111 | */ 112 | @Override 113 | int calculateEndBottomBound(float yAxisDelta) { 114 | return calculateEndTopBound(yAxisDelta) + getView().getHeight(); 115 | } 116 | 117 | } 118 | -------------------------------------------------------------------------------- /viewmover/src/main/java/com/scalified/viewmover/movers/MarginViewMover.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Scalified 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.scalified.viewmover.movers; 18 | 19 | import android.view.View; 20 | import android.view.ViewGroup; 21 | import org.slf4j.Logger; 22 | import org.slf4j.LoggerFactory; 23 | 24 | /** 25 | * View mover class, which is used to move the view, based on the view's margins 26 | * within parent container 27 | *

28 | * While moving the view, the actual view margins are changed 29 | *

30 | * Used for {@code TargetApi} lower than {@link android.os.Build.VERSION_CODES#JELLY_BEAN} 31 | *

32 | * The mover works as expected with {@link android.widget.FrameLayout} and {@link android.widget.RelativeLayout}. 33 | * Working as expected with other layouts not guaranteed 34 | * 35 | * @author shell 36 | * @version 1.0.0 37 | * @since 1.0.0 38 | */ 39 | class MarginViewMover extends ViewMover { 40 | 41 | /** 42 | * Logger 43 | */ 44 | private static final Logger LOGGER = LoggerFactory.getLogger(MarginViewMover.class); 45 | 46 | /** 47 | * Creates the {@link MarginViewMover} instance 48 | * 49 | * @param view view to be moved 50 | */ 51 | MarginViewMover(View view) { 52 | super(view); 53 | } 54 | 55 | /** 56 | * Changes the position of the view, based on view's margins within its parent container 57 | * 58 | * @param xAxisDelta X-axis delta in actual pixels 59 | * @param yAxisDelta Y-axis delta in actual pixels 60 | */ 61 | @Override 62 | void changeViewPosition(float xAxisDelta, float yAxisDelta) { 63 | ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) getView().getLayoutParams(); 64 | if (isViewLeftAligned(layoutParams)) { 65 | layoutParams.leftMargin += xAxisDelta; 66 | } else { 67 | layoutParams.rightMargin -= xAxisDelta; 68 | } 69 | if (isViewTopAligned(layoutParams)) { 70 | layoutParams.topMargin += yAxisDelta; 71 | } else { 72 | layoutParams.bottomMargin -= yAxisDelta; 73 | } 74 | LOGGER.trace("Updated view margins: left = {}, top = {}, right = {}, bottom = {}", 75 | layoutParams.leftMargin, layoutParams.topMargin, layoutParams.rightMargin, layoutParams.bottomMargin); 76 | getView().setLayoutParams(layoutParams); 77 | } 78 | 79 | /** 80 | * Checks whether view is left aligned 81 | * 82 | * @param layoutParams view's layout parameters 83 | * @return true if the view is left aligned, otherwise false 84 | */ 85 | private boolean isViewLeftAligned(ViewGroup.MarginLayoutParams layoutParams) { 86 | final int left = getView().getLeft(); 87 | boolean viewLeftAligned = left == 0 || left == layoutParams.leftMargin; 88 | LOGGER.trace("View is {} aligned", viewLeftAligned ? "LEFT" : "RIGHT"); 89 | return viewLeftAligned; 90 | } 91 | 92 | /** 93 | * Checks whether view is top aligned 94 | * 95 | * @param layoutParams view's layout parameters 96 | * @return true if the view is top aligned, otherwise false 97 | */ 98 | private boolean isViewTopAligned(ViewGroup.MarginLayoutParams layoutParams) { 99 | final int top = getView().getTop(); 100 | boolean viewTopAligned = top == 0 || top == layoutParams.topMargin; 101 | LOGGER.trace("View is {} aligned", viewTopAligned ? "TOP" : "BOTTOM"); 102 | return viewTopAligned; 103 | } 104 | 105 | /** 106 | * Calculates the resulting X coordinate of the view's left bound based on the left 107 | * position of the view relative to its parent container and the X-axis delta 108 | * 109 | * @param xAxisDelta X-axis delta in actual pixels 110 | * @return resulting X coordinate of the view's left bound 111 | */ 112 | @Override 113 | int calculateEndLeftBound(float xAxisDelta) { 114 | return getView().getLeft() + (int) xAxisDelta; 115 | } 116 | 117 | /** 118 | * Calculates the resulting X coordinate of the view's right bound based on the right 119 | * position of the view relative to its parent container and the X-axis delta 120 | * 121 | * @param xAxisDelta X-axis delta in actual pixels 122 | * @return resulting X coordinate of the view's right bound 123 | */ 124 | @Override 125 | int calculateEndRightBound(float xAxisDelta) { 126 | return getView().getRight() + (int) xAxisDelta; 127 | } 128 | 129 | /** 130 | * Calculates the resulting Y coordinate of the view's top bound based on the top 131 | * position of the view relative to its parent container and the Y-axis delta 132 | * 133 | * @param yAxisDelta Y-axis delta in actual pixels 134 | * @return resulting Y coordinate of the view's top bound 135 | */ 136 | @Override 137 | int calculateEndTopBound(float yAxisDelta) { 138 | return getView().getTop() + (int) yAxisDelta; 139 | } 140 | 141 | /** 142 | * Calculates the resulting Y coordinate of the view's bottom bound based on the bottom 143 | * position of the view relative to its parent container and the Y-axis delta 144 | * 145 | * @param yAxisDelta Y-axis delta in actual pixels 146 | * @return resulting Y coordinate of the view's bottom bound 147 | */ 148 | @Override 149 | int calculateEndBottomBound(float yAxisDelta) { 150 | return getView().getBottom() + (int) yAxisDelta; 151 | } 152 | 153 | } 154 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn ( ) { 37 | echo "$*" 38 | } 39 | 40 | die ( ) { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 165 | if [[ "$(uname)" == "Darwin" ]] && [[ "$HOME" == "$PWD" ]]; then 166 | cd "$(dirname "$0")" 167 | fi 168 | 169 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 170 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # View Mover Library for Android 2 | 3 | [![Build Status](https://travis-ci.org/Scalified/viewmover.svg?branch=master)](https://travis-ci.org/Scalified/viewmover) 4 | [![Maven Central](https://img.shields.io/maven-central/v/com.scalified/viewmover.svg)](http://search.maven.org/#search|gav|1|g%3A%22com.scalified%22%20AND%20a%3A%22viewmover%22) 5 | [![Android Arsenal](https://img.shields.io/badge/Android%20Arsenal-View%20Mover-brightgreen.svg?style=flat)](http://android-arsenal.com/details/1/1804) 6 | 7 | ## Description 8 | 9 | The Library allows to move the [**View**](http://developer.android.com/reference/android/view/View.html) within its parent container. While moving, translation animation is used 10 | 11 | ## Requirements 12 | 13 | The Library requires **Android SDK version 9 (Gingerbread)** and higher. 14 | 15 | > For API lower than Jelly Bean (version code 16) moving works as expected with **FrameLayout** and **RelativeLayout**. Working as expected with other layouts not guaranteed 16 | 17 | ## Gradle Dependency 18 | 19 | ```java 20 | dependencies { 21 | compile 'com.scalified:viewmover:1.1.2' 22 | } 23 | ``` 24 | 25 | > **View Mover** has a dependency on an external [**UI Tools**](https://github.com/Scalified/uitools) library. 26 | If it is used already in the project it must be excluded as a transitive dependency 27 | 28 | ## Changelog 29 | 30 | [**Complete Changelog**](CHANGELOG.md) 31 | 32 | ## Usage 33 | 34 | To move the **View** the following steps must be performed: 35 | 36 | 1. Create an instance of the **ViewMover** using **ViewMoverFactory.createInstance(View)** passing the **View** object to be moved 37 | 2. Create the **MovingParams** instance, passing the necessary moving parameters 38 | 3. Call the **move(MovingParams)** method on the created **ViewMover** object passing the **MovingParams** instance 39 | 40 | ### Example 41 | 42 | ```java 43 | View view; 44 | // ... view initialization code goes here 45 | 46 | // Create ViewMover instance 47 | ViewMover mover = ViewMoverFactory.createInstance(view); 48 | 49 | // Create MovingDetails instance 50 | MovingParams params = new MovingParams(getContext(), 300.0f, 300.0f); 51 | 52 | // Move the view 53 | mover.move(params); 54 | ``` 55 | 56 | ### Customization 57 | 58 | **MovingParams** class contains the details of how the view must be moved: 59 | 60 | * **xAxisDelta** - X-axis delta specifies the horizontal axis distance, which **View** is moving at. 61 | Positive value means moving right, negative - left. 62 | * **yAxisDelta** - Y-axis delta specifies the vertical axis distance, which **View** is moving at. 63 | Positive value means moving down, negative - up. 64 | * **animationDuration** - the duration of translate animation, which is used to move the view. 65 | Set to **500 ms** by default. 66 | * **animationInterpolator** - an animation interpolator, which is used to move the view. 67 | Not set by default. 68 | * **animationListener** - an animation listener, which is used to listen view animation events. 69 | Not set by default. 70 | 71 | > X- and Y-axis deltas are stored in **MovingParams** as actual pixels. When **MovingParams** instance created or when 72 | setting X- or Y-axis the density-independent values are converted into real ones. 73 | 74 | **MovingParams** has several *public* constructors, allowing to create the object with different parameters: 75 | 76 | ```java 77 | // Define parameters 78 | Context context = getContext(); 79 | int rightDistance = 200.0f; 80 | int downDistance = 200.0f; 81 | long animationDuration = 1000; 82 | Interpolator animationInterpolator = new AccelerateInterpolator(); 83 | Animation.AnimationListener animationListener = new Animation.AnimationListener() { 84 | @Override 85 | public void onAnimationStart(Animation animation) { 86 | } 87 | 88 | @Override 89 | public void onAnimationEnd(Animation animation) { 90 | } 91 | 92 | @Override 93 | public void onAnimationRepeat(Animation animation) { 94 | } 95 | }; 96 | 97 | // Declare moving parameters 98 | MovingParams params; 99 | 100 | // Create MovingParams object with distances, animation duration, animation interpolator and animation listener 101 | params = new MovingParams(context, rightDistance, upDistance, animationDuration, animationInterpolator, animationListener); 102 | 103 | // Create MovingParams object with distances, animation duration and animation listener 104 | params = new MovingParams(context, rightDistance, upDistance, animationDuration, animationListener); 105 | 106 | // Create MovingParams object with distances, animation duration and animation interpolator 107 | params = new MovingParams(context, rightDistance, upDistance, animationDuration, animationInterpolator); 108 | 109 | // Create MovingParams object with distances and animation duration 110 | params = new MovingParams(context, rightDistance, upDistance, animationDuration); 111 | 112 | // Create MovingParams object with distances only 113 | params = new MovingParams(context, rightDistance, upDistance); 114 | 115 | // Clone an existing MovingParams object 116 | MovingParams clonedDetails = new MovingParams(params) 117 | ``` 118 | 119 | **MovingParams** X-axis and Y-axis deltas can be changed after the object is created: 120 | 121 | ```java 122 | // Create MovingParams object with initial parameters 123 | MovingParams params = new MovingParams(getContext(), 200.0f, 200.0f); 124 | 125 | // Declare the new parameters 126 | float xAxisDelta = 100.0f; 127 | float yAxisDelta = 100.0f; 128 | 129 | // Apply the new parameters to MovingParams object 130 | params.setXAxisDelta(xAxisDelta); 131 | params.setYAxisDelta(yAxisDelta); 132 | ``` 133 | 134 | ## Logging 135 | 136 | To enable logging: 137 | 138 | 1. Add the following dependency: 139 | 140 | ```java 141 | dependencies { 142 | compile 'com.github.tony19:logback-android-classic:1.1.1-3' 143 | } 144 | ``` 145 | 2. Create the **logback.xml** file in the **src/main/assets** with the sample configuration: 146 | 147 | ```xml 148 | 149 | 150 | 151 | 152 | %logger{0} 153 | 154 | 155 | %d{HH:mm:ss.SSS} [%thread] [%logger{0}] - %msg%n 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | ``` 164 | > You may wish to configure different appenders with different log levels for packages, classes etc. 165 | 166 | > More information about **LOGBack** can be found @ [LOGBack Project Site](http://logback.qos.ch) 167 | 168 | 3. Add the following **InvalidPackage** ignore rule into **lint.xml** file (located @ the root of the project): 169 | 170 | ```xml 171 | 172 | 173 | 174 | ``` 175 | 176 | ## License 177 | 178 | ``` 179 | Copyright 2016 Scalified 180 | 181 | Licensed under the Apache License, Version 2.0 (the "License"); 182 | you may not use this file except in compliance with the License. 183 | You may obtain a copy of the License at 184 | 185 | http://www.apache.org/licenses/LICENSE-2.0 186 | 187 | Unless required by applicable law or agreed to in writing, software 188 | distributed under the License is distributed on an "AS IS" BASIS, 189 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 190 | See the License for the specific language governing permissions and 191 | limitations under the License. 192 | ``` 193 | 194 | ## Scalified Links 195 | 196 | * [Scalified](http://www.scalified.com) 197 | * [Scalified Official Facebook Page](https://www.facebook.com/scalified) 198 | * Scalified Support 199 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2016 Scalified 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /viewmover/src/main/java/com/scalified/viewmover/configuration/MovingParams.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Scalified 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.scalified.viewmover.configuration; 18 | 19 | import android.content.Context; 20 | import android.view.animation.Animation; 21 | import android.view.animation.Interpolator; 22 | import com.scalified.uitools.convert.DensityConverter; 23 | import org.slf4j.Logger; 24 | import org.slf4j.LoggerFactory; 25 | 26 | /** 27 | * Entity class, which contains such moving parameters like 28 | * X-, Y-axis etc. 29 | * 30 | * @author shell 31 | * @version 1.0.0 32 | * @since 1.0.0 33 | */ 34 | public class MovingParams { 35 | 36 | /** 37 | * Logger 38 | */ 39 | private static final Logger LOGGER = LoggerFactory.getLogger(MovingParams.class); 40 | 41 | /** 42 | * Move animation duration, which is used by default 43 | */ 44 | private static final long DEFAULT_ANIMATION_DURATION = 500L; 45 | 46 | /** 47 | * Context the view is running in 48 | */ 49 | private final Context context; 50 | 51 | /** 52 | * An X-axis delta in actual pixels 53 | *

54 | * Positive value means that view is moving to the right. 55 | * Negative value means that view is moving to the left 56 | */ 57 | private float xAxisDelta; 58 | 59 | /** 60 | * An Y-axis delta in actual pixels 61 | *

62 | * Positive value means that view is moving down. 63 | * Negative value means that view is moving up 64 | */ 65 | private float yAxisDelta; 66 | 67 | /** 68 | * Move animation duration 69 | *

70 | * By default set to {@link #DEFAULT_ANIMATION_DURATION} 71 | */ 72 | private long animationDuration = DEFAULT_ANIMATION_DURATION; 73 | 74 | /** 75 | * Move animation interpolator 76 | *

77 | * By default is not set and is {@code null} 78 | */ 79 | private Interpolator animationInterpolator; 80 | 81 | /** 82 | * Move animation listener 83 | *

84 | * By default is not set and is {@code null} 85 | */ 86 | private Animation.AnimationListener animationListener; 87 | 88 | /** 89 | * Creates the {@link MovingParams} instance 90 | * 91 | * @param context context the view is running in 92 | * @param xAxisDelta X-axis delta in density-independent pixels. 93 | * Positive value means that view is moving right. 94 | * Negative value means that view is moving left 95 | * @param yAxisDelta Y-axis delta in density-independent pixels. 96 | * Positive value means that view is moving down. 97 | * Negative value means that view is moving up 98 | * @param animationDuration move animation duration 99 | * @param animationInterpolator move animation interpolator 100 | * @param animationListener move animation listener 101 | */ 102 | public MovingParams(Context context, float xAxisDelta, float yAxisDelta, long animationDuration, 103 | Interpolator animationInterpolator, Animation.AnimationListener animationListener) { 104 | this.context = context; 105 | this.xAxisDelta = dpToPx(xAxisDelta); 106 | this.yAxisDelta = dpToPx(yAxisDelta); 107 | this.animationDuration = animationDuration; 108 | this.animationInterpolator = animationInterpolator; 109 | this.animationListener = animationListener; 110 | LOGGER.trace("Moving params initialized with values: xAxisDelta = {}, yAxisDelta = {}, " + 111 | "animationDuration = {}, animationInterpolator is an instance of {} class, " + 112 | "animationListener is instance of {} class", 113 | getXAxisDelta(), getYAxisDelta(), getAnimationDuration(), 114 | getAnimationInterpolator().getClass().getSimpleName(), 115 | getAnimationListener().getClass().getSimpleName()); 116 | } 117 | 118 | /** 119 | * Creates the {@link MovingParams} instance 120 | * 121 | * @param context context the view is running in 122 | * @param xAxisDelta X-axis delta in density-independent pixels. 123 | * Positive value means that view is moving right. 124 | * Negative value means that view is moving left 125 | * @param yAxisDelta Y-axis delta in density-independent pixels. 126 | * Positive value means that view is moving down. 127 | * Negative value means that view is moving up 128 | * @param animationDuration move animation duration 129 | * @param animationListener move animation listener 130 | */ 131 | public MovingParams(Context context, float xAxisDelta, float yAxisDelta, long animationDuration, 132 | Animation.AnimationListener animationListener) { 133 | this.context = context; 134 | this.xAxisDelta = dpToPx(xAxisDelta); 135 | this.yAxisDelta = dpToPx(yAxisDelta); 136 | this.animationDuration = animationDuration; 137 | this.animationListener = animationListener; 138 | LOGGER.trace("Moving params initialized with values: xAxisDelta = {}, yAxisDelta = {}, " + 139 | "animationDuration = {}, animationInterpolator is an instance of {} class, " + 140 | "animationListener is instance of {} class", 141 | getXAxisDelta(), getYAxisDelta(), getAnimationDuration(), 142 | getAnimationListener().getClass().getSimpleName()); 143 | } 144 | 145 | /** 146 | * Creates the {@link MovingParams} instance 147 | * 148 | * @param context context the view is running in 149 | * @param xAxisDelta X-axis delta in density-independent pixels. 150 | * Positive value means that view is moving right. 151 | * Negative value means that view is moving left 152 | * @param yAxisDelta Y-axis delta in density-independent pixels. 153 | * Positive value means that view is moving down. 154 | * Negative value means that view is moving up 155 | * @param animationDuration move animation duration 156 | * @param animationInterpolator move animation interpolator 157 | */ 158 | public MovingParams(Context context, float xAxisDelta, float yAxisDelta, long animationDuration, 159 | Interpolator animationInterpolator) { 160 | this.context = context; 161 | this.xAxisDelta = dpToPx(xAxisDelta); 162 | this.yAxisDelta = dpToPx(yAxisDelta); 163 | this.animationDuration = animationDuration; 164 | this.animationInterpolator = animationInterpolator; 165 | LOGGER.trace("Moving params initialized with values: xAxisDelta = {}, yAxisDelta = {}, " + 166 | "animationDuration = {}, animationInterpolator is an instance of {} class", 167 | getXAxisDelta(), getYAxisDelta(), getAnimationDuration(), 168 | getAnimationInterpolator().getClass().getSimpleName()); 169 | } 170 | 171 | /** 172 | * Creates the {@link MovingParams} instance 173 | * 174 | * @param context context the view is running in 175 | * @param xAxisDelta X-axis delta in density-independent pixels. 176 | * Positive value means that view is moving right. 177 | * Negative value means that view is moving left 178 | * @param yAxisDelta Y-axis delta in density-independent pixels. 179 | * Positive value means that view is moving down. 180 | * Negative value means that view is moving up 181 | * @param animationDuration move animation duration 182 | */ 183 | public MovingParams(Context context, float xAxisDelta, float yAxisDelta, long animationDuration) { 184 | this.context = context; 185 | this.xAxisDelta = dpToPx(xAxisDelta); 186 | this.yAxisDelta = dpToPx(yAxisDelta); 187 | this.animationDuration = animationDuration; 188 | LOGGER.trace("Moving params initialized with values: xAxisDelta = {}, yAxisDelta = {}, animationDuration = {}", 189 | getXAxisDelta(), getYAxisDelta(), getAnimationDuration()); 190 | } 191 | 192 | /** 193 | * Creates the {@link MovingParams} instance 194 | * 195 | * @param context context the view is running in 196 | * @param xAxisDelta X-axis delta in density-independent pixels. 197 | * Positive value means that view is moving right. 198 | * Negative value means that view is moving left 199 | * @param yAxisDelta Y-axis delta in density-independent pixels. 200 | * Positive value means that view is moving down. 201 | * Negative value means that view is moving up 202 | */ 203 | public MovingParams(Context context, float xAxisDelta, float yAxisDelta) { 204 | this.context = context; 205 | this.xAxisDelta = dpToPx(xAxisDelta); 206 | this.yAxisDelta = dpToPx(yAxisDelta); 207 | LOGGER.trace("Moving params initialized with values: xAxisDelta = {}, yAxisDelta = {}", 208 | getXAxisDelta(), getYAxisDelta()); 209 | } 210 | 211 | /** 212 | * Creates the {@link MovingParams} instance by cloning it 213 | * 214 | * @param params moving params, which cloning is performed of 215 | */ 216 | public MovingParams(MovingParams params) { 217 | this.context = params.getContext(); 218 | this.xAxisDelta = params.getXAxisDelta(); 219 | this.yAxisDelta = params.getYAxisDelta(); 220 | this.animationDuration = params.getAnimationDuration(); 221 | this.animationInterpolator = params.getAnimationInterpolator(); 222 | LOGGER.trace("Cloned moving params initialized with values: xAxisDelta = {}, yAxisDelta = {}, " + 223 | "animationDuration = {}, animation interpolator is an instance of {} class", getXAxisDelta(), 224 | getYAxisDelta(), getAnimationDuration(), getAnimationInterpolator() == null ? "null" : 225 | getAnimationInterpolator().getClass().getSimpleName()); 226 | } 227 | 228 | /** 229 | * Returns a context the view is running in 230 | * 231 | * @return context the view is running in 232 | */ 233 | private Context getContext() { 234 | return context; 235 | } 236 | 237 | /** 238 | * Returns an X-axis delta in actual pixels 239 | * 240 | * @return X-axis delta in actual pixels 241 | */ 242 | public float getXAxisDelta() { 243 | return xAxisDelta; 244 | } 245 | 246 | /** 247 | * Sets an X-axis delta 248 | * 249 | * @param xAxisDelta X-axis delta in density-independent pixels 250 | */ 251 | public void setXAxisDelta(float xAxisDelta) { 252 | this.xAxisDelta = dpToPx(xAxisDelta); 253 | LOGGER.trace("Moving params xAxisDelta set to: {}", getXAxisDelta()); 254 | } 255 | 256 | /** 257 | * Returns an Y-axis delta in actual pixels 258 | * 259 | * @return Y-axis delta in actual pixels 260 | */ 261 | public float getYAxisDelta() { 262 | return yAxisDelta; 263 | } 264 | 265 | /** 266 | * Sets an Y-axis delta 267 | * 268 | * @param yAxisDelta Y-axis delta in density-independent pixels 269 | */ 270 | public void setYAxisDelta(float yAxisDelta) { 271 | this.yAxisDelta = dpToPx(yAxisDelta); 272 | LOGGER.trace("Moving params yAxisDelta set to: {}", getYAxisDelta()); 273 | } 274 | 275 | /** 276 | * Returns the move animation duration in ms 277 | * 278 | * @return move animation duration in ms 279 | */ 280 | public long getAnimationDuration() { 281 | return animationDuration; 282 | } 283 | 284 | /** 285 | * Returns move animation interpolator 286 | * 287 | * @return move animation interpolator 288 | */ 289 | public Interpolator getAnimationInterpolator() { 290 | return animationInterpolator; 291 | } 292 | 293 | /** 294 | * Returns move animation listener 295 | * 296 | * @return move animation listener 297 | */ 298 | public Animation.AnimationListener getAnimationListener() { 299 | return animationListener; 300 | } 301 | 302 | /** 303 | * Converts the density-independent value into density-dependent one 304 | * 305 | * @param dp density-independent value 306 | * @return density-dependent value 307 | */ 308 | private float dpToPx(float dp) { 309 | return DensityConverter.dpToPx(getContext(), dp); 310 | } 311 | 312 | } 313 | -------------------------------------------------------------------------------- /viewmover/src/main/java/com/scalified/viewmover/movers/ViewMover.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Scalified 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.scalified.viewmover.movers; 18 | 19 | import android.view.View; 20 | import android.view.animation.Animation; 21 | import android.view.animation.Interpolator; 22 | import android.view.animation.TranslateAnimation; 23 | import com.scalified.viewmover.configuration.MovingParams; 24 | import org.slf4j.Logger; 25 | import org.slf4j.LoggerFactory; 26 | 27 | /** 28 | * Abstract class, which contains the base view movement logic 29 | *

30 | * Is extended by subclasses, which implements specific movement logic 31 | * 32 | * @author shell 33 | * @version 1.0.0 34 | * @since 1.0.0 35 | */ 36 | public abstract class ViewMover { 37 | 38 | /** 39 | * Logger 40 | */ 41 | private static final Logger LOGGER = LoggerFactory.getLogger(ViewMover.class); 42 | 43 | /** 44 | * {@link android.view.View}, which is to be moved 45 | */ 46 | private final View view; 47 | 48 | /** 49 | * Overrides default constructor 50 | * 51 | * @param view {@link android.view.View}, which is to be moved 52 | */ 53 | ViewMover(View view) { 54 | this.view = view; 55 | } 56 | 57 | /** 58 | * Is called to calculate the end X point of the view's left bound 59 | *

60 | * Used to check whether there is enough space inside parent container to move the view 61 | * to the left 62 | * 63 | * @param xAxisDelta X-axis delta in actual pixels 64 | * @return end X point of the view's left bound 65 | */ 66 | abstract int calculateEndLeftBound(float xAxisDelta); 67 | 68 | /** 69 | * Is called to calculate the end X point of the view's right bound 70 | *

71 | * Used to check whether there is enough space inside parent container to move the view 72 | * to the right 73 | * 74 | * @param xAxisDelta X-axis delta in actual pixels 75 | * @return end X point of the view's right bound 76 | */ 77 | abstract int calculateEndRightBound(float xAxisDelta); 78 | 79 | /** 80 | * Is called to calculate the end Y point of the view's top bound 81 | *

82 | * Used to check whether there is enough space inside parent container to move the view 83 | * to the top 84 | * 85 | * @param yAxisDelta Y-axis delta in actual pixels 86 | * @return end Y point of the view's top bound 87 | */ 88 | abstract int calculateEndTopBound(float yAxisDelta); 89 | 90 | /** 91 | * Is called to calculate the end Y point of the view's bottom bound 92 | *

93 | * Used to check whether there is enough space inside parent container to move the view 94 | * to the bottom 95 | * 96 | * @param yAxisDelta Y-axis delta in actual pixels 97 | * @return end Y point of the view's bottom bound 98 | */ 99 | abstract int calculateEndBottomBound(float yAxisDelta); 100 | 101 | /** 102 | * Is called when move animation completes 103 | *

104 | * Used to change the view position within its parent container 105 | * 106 | * @param xAxisDelta X-axis delta in actual pixels 107 | * @param yAxisDelta Y-axis delta in actual pixels 108 | */ 109 | abstract void changeViewPosition(float xAxisDelta, float yAxisDelta); 110 | 111 | /** 112 | * Returns the view, which is to be moved 113 | * 114 | * @return view to be moved 115 | */ 116 | View getView() { 117 | return view; 118 | } 119 | 120 | /** 121 | * Returns the parent container of the view, which is to be moved 122 | * 123 | * @return parent container of the view to be moved 124 | */ 125 | View getParentView() { 126 | return (View) view.getParent(); 127 | } 128 | 129 | /** 130 | * Moves the view based on the {@link MovingParams} 131 | * 132 | * @param params params of the move action 133 | */ 134 | public void move(MovingParams params) { 135 | if (isPreviousAnimationCompleted()) { 136 | MovingParams verifiedParams = getVerifiedMovingParams(params); 137 | if (isMoveNonZero(verifiedParams)) { 138 | final Animation moveAnimation = createAnimation(verifiedParams); 139 | LOGGER.trace("View is about to be moved at: delta X-axis = {}, delta Y-axis = {}", 140 | verifiedParams.getXAxisDelta(), verifiedParams.getYAxisDelta()); 141 | view.startAnimation(moveAnimation); 142 | } 143 | } 144 | } 145 | 146 | /** 147 | * Checks whether previous animation on the view completed 148 | * 149 | * @return true if previous animation on the view completed, otherwise false 150 | */ 151 | boolean isPreviousAnimationCompleted() { 152 | Animation previousAnimation = view.getAnimation(); 153 | boolean previousAnimationCompleted = previousAnimation == null || previousAnimation.hasEnded(); 154 | if (!previousAnimationCompleted) { 155 | LOGGER.warn("Unable to move the view. View is being currently moving"); 156 | } 157 | return previousAnimationCompleted; 158 | } 159 | 160 | /** 161 | * Checks whether both X-axis and Y-axis delta of the moving details are not {@code zero} 162 | * 163 | * @param details moving details, which needs to be checked 164 | * @return true, if any of the X-axis or Y-axis delta of the moving details are {@code zero}, 165 | * otherwise false 166 | */ 167 | boolean isMoveNonZero(MovingParams details) { 168 | boolean moveNonZero = details.getXAxisDelta() != 0.0f 169 | || details.getYAxisDelta() != 0.0f; 170 | if (!moveNonZero) { 171 | LOGGER.warn("Zero movement detected. No movement will be performed"); 172 | } 173 | return moveNonZero; 174 | } 175 | 176 | /** 177 | * Creates an updated copy of the {@link MovingParams} 178 | * with X-axis and Y-axis deltas updated based on calculations returned from 179 | * {@link #updateXAxisDelta(MovingParams)} and 180 | * {@link #updateYAxisDelta(MovingParams)} 181 | * 182 | * @param params moving params, which needs to be updated 183 | */ 184 | private MovingParams getVerifiedMovingParams(final MovingParams params) { 185 | MovingParams mParams = new MovingParams(params); 186 | updateXAxisDelta(mParams); 187 | updateYAxisDelta(mParams); 188 | LOGGER.trace("Updated moving details values: X-axis from {} to {}, Y-axis from {} to {}", 189 | params.getXAxisDelta(), mParams.getXAxisDelta(), params.getYAxisDelta(), mParams.getYAxisDelta()); 190 | return mParams; 191 | } 192 | 193 | /** 194 | * Updates the X-axis delta in moving details based on checking whether 195 | * there is enough space left to move the view horizontally 196 | * 197 | * @param details moving details, which X-axis delta needs to be updated in 198 | */ 199 | private void updateXAxisDelta(MovingParams details) { 200 | if (!hasHorizontalSpaceToMove(details.getXAxisDelta())) { 201 | LOGGER.warn("Unable to move the view horizontally. No horizontal space left to move"); 202 | details.setXAxisDelta(0.0f); 203 | } 204 | } 205 | 206 | /** 207 | * Updates the Y-axis delta in moving details based on checking whether 208 | * there is enough space left to move the view vertically 209 | * 210 | * @param details moving details, which Y-axis delta needs to be updated in 211 | */ 212 | private void updateYAxisDelta(MovingParams details) { 213 | if (!hasVerticalSpaceToMove(details.getYAxisDelta())) { 214 | LOGGER.warn("Unable to move the view vertically. No vertical space left to move"); 215 | details.setYAxisDelta(0.0f); 216 | } 217 | } 218 | 219 | /** 220 | * Checks whether there is enough space left to move the view horizontally within 221 | * its parent container 222 | *

223 | * Calls {@link #calculateEndLeftBound(float)} and {@link #calculateEndRightBound(float)} 224 | * to calculate the resulting X coordinate of the view's left and right bounds 225 | * 226 | * @param xAxisDelta X-axis delta in actual pixels 227 | * @return true if there is enough space to move the view horizontally, otherwise false 228 | */ 229 | private boolean hasHorizontalSpaceToMove(float xAxisDelta) { 230 | int parentWidth = getParentView().getWidth(); 231 | LOGGER.trace("Parent view width is: {}", parentWidth); 232 | int endLeftBound = calculateEndLeftBound(xAxisDelta); 233 | int endRightBound = calculateEndRightBound(xAxisDelta); 234 | LOGGER.trace("Calculated end bounds: left = {}, right = {}", endLeftBound, endRightBound); 235 | return endLeftBound >= 0 && endRightBound <= parentWidth; 236 | } 237 | 238 | /** 239 | * Checks whether there is enough space left to move the view vertically within 240 | * its parent container 241 | *

242 | * Calls {@link #calculateEndTopBound(float)} and {@link #calculateEndBottomBound(float)} 243 | * to calculate the resulting Y coordinate of the view's top and bottom bounds 244 | * 245 | * @param yAxisDelta Y-axis delta in actual pixels 246 | * @return true if there is enough space to move the view vertically, otherwise false 247 | */ 248 | private boolean hasVerticalSpaceToMove(float yAxisDelta) { 249 | int parentHeight = getParentView().getHeight(); 250 | LOGGER.trace("Parent view height is: {}", parentHeight); 251 | int endTopBound = calculateEndTopBound(yAxisDelta); 252 | int endBottomBound = calculateEndBottomBound(yAxisDelta); 253 | LOGGER.trace("Calculated end bounds: top = {}, bottom = {}", endTopBound, endBottomBound); 254 | return endTopBound >= 0 && endBottomBound <= parentHeight; 255 | } 256 | 257 | /** 258 | * Creates the moving animation 259 | *

260 | * Configures the moving animation based on moving params 261 | * 262 | * @param params params, which is used to configure the moving animation 263 | * @return moving animation 264 | */ 265 | private Animation createAnimation(MovingParams params) { 266 | Animation animation = new TranslateAnimation(0, params.getXAxisDelta(), 0, params.getYAxisDelta()); 267 | animation.setFillEnabled(true); 268 | animation.setFillBefore(false); 269 | animation.setDuration(params.getAnimationDuration()); 270 | Interpolator interpolator = params.getAnimationInterpolator(); 271 | if (interpolator != null) { 272 | animation.setInterpolator(interpolator); 273 | } 274 | animation.setAnimationListener(new MoveAnimationListener(params)); 275 | return animation; 276 | } 277 | 278 | /** 279 | * Move animation listener class 280 | *

281 | * Used to listen the animation and call the {@link #changeViewPosition(float, float)} 282 | * when animation completes 283 | */ 284 | private class MoveAnimationListener implements Animation.AnimationListener { 285 | 286 | /** 287 | * Moving parameters 288 | */ 289 | private final MovingParams params; 290 | 291 | /** 292 | * An external animation listener 293 | */ 294 | private final Animation.AnimationListener animationListener; 295 | 296 | /** 297 | * Creates an instance of the 298 | * {@link com.scalified.viewmover.movers.ViewMover.MoveAnimationListener} 299 | * 300 | * @param params moving params 301 | */ 302 | private MoveAnimationListener(MovingParams params) { 303 | this.params = params; 304 | this.animationListener = params.getAnimationListener(); 305 | } 306 | 307 | @Override 308 | public void onAnimationStart(Animation animation) { 309 | if (animationListener != null) { 310 | animationListener.onAnimationStart(animation); 311 | } 312 | } 313 | 314 | @Override 315 | public void onAnimationRepeat(Animation animation) { 316 | if (animationListener != null) { 317 | animationListener.onAnimationRepeat(animation); 318 | } 319 | } 320 | 321 | /** 322 | * Is called when animation completes 323 | *

324 | * Calls the {@link #changeViewPosition(float, float)} giving the subclasses 325 | * the ability to change the position of the view based on their logic 326 | * 327 | * @param animation moving animation 328 | */ 329 | @Override 330 | public void onAnimationEnd(Animation animation) { 331 | changeViewPosition(params.getXAxisDelta(), params.getYAxisDelta()); 332 | if (animationListener != null) { 333 | animationListener.onAnimationEnd(animation); 334 | } 335 | } 336 | 337 | } 338 | 339 | } 340 | --------------------------------------------------------------------------------