├── .gitignore ├── README.md ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── mrecyclerview ├── .gitignore ├── build.gradle └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── marshon │ │ ├── adapters │ │ ├── AlphaInAnimationAdapter.java │ │ ├── AnimationAdapter.java │ │ ├── ScaleInAnimationAdapter.java │ │ ├── SlideInBottomAnimationAdapter.java │ │ ├── SlideInLeftAnimationAdapter.java │ │ └── SlideInRightAnimationAdapter.java │ │ ├── animators │ │ ├── BaseItemAnimator.java │ │ ├── FadeInAnimator.java │ │ ├── FadeInDownAnimator.java │ │ ├── FadeInLeftAnimator.java │ │ ├── FadeInRightAnimator.java │ │ ├── FadeInUpAnimator.java │ │ ├── FlipInBottomXAnimator.java │ │ ├── FlipInLeftYAnimator.java │ │ ├── FlipInRightYAnimator.java │ │ ├── FlipInTopXAnimator.java │ │ ├── LandingAnimator.java │ │ ├── OvershootInLeftAnimator.java │ │ ├── OvershootInRightAnimator.java │ │ ├── ScaleInAnimator.java │ │ ├── ScaleInBottomAnimator.java │ │ ├── ScaleInLeftAnimator.java │ │ ├── ScaleInRightAnimator.java │ │ ├── ScaleInTopAnimator.java │ │ ├── SlideInDownAnimator.java │ │ ├── SlideInLeftAnimator.java │ │ ├── SlideInRightAnimator.java │ │ ├── SlideInUpAnimator.java │ │ └── holder │ │ │ └── AnimateViewHolder.java │ │ ├── internal │ │ └── ViewHelper.java │ │ ├── mrecyclerview │ │ ├── ArrowRefreshHeader.java │ │ ├── BaseRefreshHeader.java │ │ ├── JellyView.java │ │ ├── LoadingMoreFooter.java │ │ ├── MRecyclerView.java │ │ └── SimpleViewSwithcer.java │ │ └── swipe │ │ └── SwipeWraper.java │ └── res │ ├── drawable-hdpi │ ├── ic_pulltorefresh_arrow.png │ ├── loading_01.png │ ├── loading_02.png │ ├── loading_03.png │ ├── loading_04.png │ ├── loading_05.png │ ├── loading_06.png │ ├── loading_07.png │ ├── loading_08.png │ ├── loading_09.png │ ├── loading_10.png │ ├── loading_11.png │ ├── loading_12.png │ ├── progressbar.xml │ └── ptrhead.png │ ├── layout │ ├── listview_footer.xml │ ├── listview_header.xml │ ├── pull_to_refresh_head.xml │ └── swipe.xml │ ├── values-zh │ └── strings.xml │ └── values │ ├── attrs.xml │ └── dimens.xml ├── proguard-project.txt ├── sample ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── demotest │ │ └── testapp │ │ ├── ChooseAnimatorsAdapter.java │ │ ├── MarshonRecyclerViewActivity.java │ │ └── adapter │ │ └── MarshonRecyclerAdapter.java │ └── res │ ├── drawable │ ├── beauty.jpg │ ├── ic_launcher.png │ └── meinv.png │ ├── layout │ ├── activity_marsreview.xml │ └── listitem.xml │ └── values │ ├── colors.xml │ ├── strings.xml │ └── styles.xml └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /local.properties 3 | /.idea/workspace.xml 4 | /.idea/libraries 5 | .DS_Store 6 | /build 7 | /captures 8 | 9 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion 10 | *.iml 11 | ## Directory-based project format: 12 | .idea/ 13 | # if you remove the above rule, at least ignore the following: 14 | # User-specific stuff: 15 | # .idea/workspace.xml 16 | # .idea/tasks.xml 17 | # .idea/dictionaries 18 | # Sensitive or high-churn files: 19 | # .idea/dataSources.ids 20 | # .idea/dataSources.xml 21 | # .idea/sqlDataSources.xml 22 | # .idea/dynamic.xml 23 | # .idea/uiDesigner.xml 24 | # Gradle: 25 | # .idea/gradle.xml 26 | # .idea/libraries 27 | # Mongo Explorer plugin: 28 | # .idea/mongoSettings.xml 29 | ## File-based project format: 30 | *.ipr 31 | *.iws 32 | ## Plugin-specific files: 33 | # IntelliJ 34 | /out/ 35 | # mpeltonen/sbt-idea plugin 36 | .idea_modules/ 37 | # JIRA plugin 38 | atlassian-ide-plugin.xml 39 | # Crashlytics plugin (for Android Studio and IntelliJ) 40 | com_crashlytics_export_strings.xml 41 | crashlytics.properties 42 | crashlytics-build.properties 43 | 44 | # Built application files 45 | *.apk 46 | *.ap_ 47 | # Files for the Dalvik VM 48 | *.dex 49 | # Java class files 50 | *.class 51 | # Generated files 52 | bin/ 53 | gen/ 54 | # Gradle files 55 | .gradle/ 56 | build/ 57 | /*/build/ 58 | # Local configuration file (sdk path, etc) 59 | local.properties 60 | # Proguard folder generated by Eclipse 61 | proguard/ 62 | # Log Files 63 | *.log 64 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MRecyclerView 2 | 项目CSDN地址: 3 | http://blog.csdn.net/u014665060/article/details/51241526 4 | Android RecyclerView+item动画+下拉刷新,上拉加载更多,侧滑删除(易用,可定制)(可DIY) 5 | 特别声明:开源框架并非全部本人亲手敲出来的,本人只是站在巨人的肩膀上,整合了一下别人优秀的代码,并加修改融合,希望方便到各位盆友并Get到盆友们的支持,喜欢的star或者fork下. 6 | ###下拉刷新,上拉加载更多(可DIY): 7 | ![](http://img.blog.csdn.net/20160426203038364?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 8 | 9 | ###支持多种动画: 10 | 11 | ![](http://img.blog.csdn.net/20160426203050349?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 12 | 13 | ###多个ItemType(只需30行代码): 14 | 15 | ![](http://img.blog.csdn.net/20160426203100780?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 16 | 17 | 18 | #1.介绍下MReyclerView 19 | 20 | 21 | 因为之前使用过XlistView,在其可以实现下拉刷新,上拉加载更多功能上深得喜爱,可定制型也非常强,可以自己实现成类似于京东,淘宝等下拉刷新动画效果.原理差不多,加个HeaderView和FooterView作为下拉刷新和上拉加载更多.通过改变HeaderView的height来实现滑动的效果.加上属性动画让用户体验更佳. 22 | 23 | 24 | 25 | ###=============分割线============================================================= 26 | 27 | 一不小心又B了那么多,其实MRecyclerView用法没多大难度,跟RecyclerView用法一样,哎. 28 | 29 | #2.ItemAnimator 30 | 31 | 承上启下,ItemAnimator确实让人兴奋,虽然比不上5.0以上的transition动画,但是有了这些动画, 用起来也能够挺爽的不要不要的了.不信你看↓.. 32 | 33 | AnimationAdapter: 34 | 这是一个装饰了RecyclerView.Adapter的类.其主要改造的地方在这里: 35 | 36 | @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { 37 | mAdapter.onBindViewHolder(holder, position); 38 | 39 | int adapterPosition = holder.getAdapterPosition(); 40 | if (!isFirstOnly || adapterPosition > mLastPosition) { 41 | for (Animator anim : getAnimators(holder.itemView)) { 42 | anim.setDuration(mDuration).start(); 43 | anim.setInterpolator(mInterpolator); 44 | } 45 | mLastPosition = adapterPosition; 46 | } else { 47 | ViewHelper.clear(holder.itemView); 48 | } 49 | } 50 | 51 | 由于上面可以看出,在Item展示的时候是逐个读取动画来执行,并且提供了 isFirstOnly 来配置是否只是第一次展示的时候才执行动画.通过 AnimationAdapter.setFirstOnly(true);来设置. 52 | 但是 AnimationAdapter是一个抽象类, 需要重载一个类来实现里面的getAnimators方法.详细写法可参照demo里的ChooseAnimatorsAdapter类.也可以查看Xrecyclerview包下的animators包,里面提供了很多已经写好的AnimatorAdapters类,拿来即用,懒嘛..哈哈 另外提一下, 在下拉刷新和动画并不和侧滑冲突,爽爽哒 53 | 54 | #3.侧滑菜单栏 55 | 详情键SwipeWraper,只要在listietm最外层套上他,并且当做FrameLayout来使用就可以实现侧滑菜单功能.哎 56 | 57 | 58 | View deleteView = holder.itemView.findViewById(R.id.tv_delete); 59 | final SwipeWraper swipelayout = (SwipeWraper) holder.itemView.findViewById(R.id.swipelayout); 60 | deleteView.setOnClickListener(new View.OnClickListener() { 61 | @Override 62 | public void onClick(View v) { 63 | swipelayout.close(true); 64 | datas.remove(holder.getLayoutPosition()-1); 65 | animAdapter.notifyItemRemoved(holder.getLayoutPosition()); 66 | } 67 | }); 68 | 69 | 可以省去很多load img方法重写. 70 | 值得开心的是:产品狗一般不让一个recyclerview里面只放一种item. 这个框架作者也考虑到了这点, 写法稍微复杂点,不过有兴趣的去看下张大神的github哈.# MRecyclerView 71 | 72 | 73 | 74 | 可以省去很多load img方法重写. 75 | 产品狗一般不让一个recyclerview里面只放一种item. 这个框架作者也考虑到了这点, 写法稍微复杂点,在此安利本人喜欢的张大神的github.里面有更详细的baseadapter用法的介绍: 76 | 链接:[https://github.com/hongyangAndroid/baseAdapter](https://github.com/hongyangAndroid/baseAdapter) 77 | 还有很多功能没提,大家细细探索哈.. 78 | 79 | ##THANKS PROVIDE: 80 | 81 | ItemAnimators: 82 | [https://github.com/wasabeef/recyclerview-animators](https://github.com/wasabeef/recyclerview-animators) 83 | 84 | 85 | 86 | 如以上内容造成侵权 敬请告知删除,谢谢! 87 | 88 | 联系QQ: 371166028 邮箱:itmarshon@163.com 89 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:2.2.1' 9 | // classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.0' 10 | 11 | classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.3.1' 12 | classpath 'com.github.dcendents:android-maven-gradle-plugin:1.3' 13 | // NOTE: Do not place your application dependencies here; they belong 14 | // in the individual module build.gradle files 15 | } 16 | } 17 | 18 | allprojects { 19 | repositories { 20 | jcenter() 21 | maven { url "http://dl.bintray.com/jjhesk/maven" } 22 | 23 | } 24 | } 25 | 26 | //task clean(type: Delete) { 27 | // delete rootProject.buildDir 28 | //} 29 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenchengyin/MRecyclerView/94a913223534b877428a9b7bfd2740686e1a9a79/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Nov 09 15:09:07 CST 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-2.14.1-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 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 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /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 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 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 Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /mrecyclerview/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | *.iml 3 | .idea -------------------------------------------------------------------------------- /mrecyclerview/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion "23.0.3" 6 | 7 | defaultConfig { 8 | minSdkVersion 14 9 | targetSdkVersion 23 10 | } 11 | 12 | } 13 | 14 | dependencies { 15 | compile 'com.android.support:appcompat-v7:23.1.0' 16 | compile 'com.android.support:recyclerview-v7:23.1.0' 17 | // compile 'jp.wasabeef:recyclerview-animators:2.2.3' 18 | 19 | } 20 | 21 | 22 | -------------------------------------------------------------------------------- /mrecyclerview/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /mrecyclerview/src/main/java/com/marshon/adapters/AlphaInAnimationAdapter.java: -------------------------------------------------------------------------------- 1 | package com.marshon.adapters; 2 | 3 | import android.animation.Animator; 4 | import android.animation.ObjectAnimator; 5 | import android.support.v7.widget.RecyclerView; 6 | import android.view.View; 7 | 8 | /** 9 | * Copyright (C) 2015 Wasabeef 10 | * 11 | * Licensed under the Apache License, Version 2.0 (the "License"); 12 | * you may not use this file except in compliance with the License. 13 | * You may obtain a copy of the License at 14 | * 15 | * http://www.apache.org/licenses/LICENSE-2.0 16 | * 17 | * Unless required by applicable law or agreed to in writing, software 18 | * distributed under the License is distributed on an "AS IS" BASIS, 19 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20 | * See the License for the specific language governing permissions and 21 | * limitations under the License. 22 | */ 23 | 24 | public class AlphaInAnimationAdapter extends AnimationAdapter { 25 | 26 | private static final float DEFAULT_ALPHA_FROM = 0f; 27 | private final float mFrom; 28 | 29 | public AlphaInAnimationAdapter(RecyclerView.Adapter adapter) { 30 | this(adapter, DEFAULT_ALPHA_FROM); 31 | } 32 | 33 | public AlphaInAnimationAdapter(RecyclerView.Adapter adapter, float from) { 34 | super(adapter); 35 | mFrom = from; 36 | } 37 | 38 | @Override protected Animator[] getAnimators(View view) { 39 | return new Animator[] { ObjectAnimator.ofFloat(view, "alpha", mFrom, 1f),ObjectAnimator.ofFloat(view, "scaleX", mFrom, 1f),ObjectAnimator.ofFloat(view, "scaleY", mFrom, 1f) }; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /mrecyclerview/src/main/java/com/marshon/adapters/AnimationAdapter.java: -------------------------------------------------------------------------------- 1 | package com.marshon.adapters; 2 | 3 | import android.animation.Animator; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.view.animation.Interpolator; 8 | import android.view.animation.LinearInterpolator; 9 | 10 | import com.marshon.internal.ViewHelper; 11 | 12 | /** 13 | * Copyright (C) 2015 Wasabeef 14 | * 15 | * Licensed under the Apache License, Version 2.0 (the "License"); 16 | * you may not use this file except in compliance with the License. 17 | * You may obtain a copy of the License at 18 | * 19 | * http://www.apache.org/licenses/LICENSE-2.0 20 | * 21 | * Unless required by applicable law or agreed to in writing, software 22 | * distributed under the License is distributed on an "AS IS" BASIS, 23 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 24 | * See the License for the specific language governing permissions and 25 | * limitations under the License. 26 | */ 27 | public abstract class AnimationAdapter extends RecyclerView.Adapter { 28 | 29 | private RecyclerView.Adapter mAdapter; 30 | private int mDuration = 300; 31 | private Interpolator mInterpolator = new LinearInterpolator(); 32 | private int mLastPosition = -1; 33 | 34 | private boolean isFirstOnly = true; 35 | 36 | public AnimationAdapter(RecyclerView.Adapter adapter) { 37 | mAdapter = adapter; 38 | } 39 | 40 | @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 41 | return mAdapter.onCreateViewHolder(parent, viewType); 42 | } 43 | 44 | @Override public void registerAdapterDataObserver(RecyclerView.AdapterDataObserver observer) { 45 | super.registerAdapterDataObserver(observer); 46 | mAdapter.registerAdapterDataObserver(observer); 47 | } 48 | 49 | @Override public void unregisterAdapterDataObserver(RecyclerView.AdapterDataObserver observer) { 50 | super.unregisterAdapterDataObserver(observer); 51 | mAdapter.unregisterAdapterDataObserver(observer); 52 | } 53 | 54 | @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { 55 | mAdapter.onBindViewHolder(holder, position); 56 | 57 | int adapterPosition = holder.getAdapterPosition(); 58 | if (!isFirstOnly || adapterPosition > mLastPosition) { 59 | for (Animator anim : getAnimators(holder.itemView)) { 60 | anim.setDuration(mDuration).start(); 61 | anim.setInterpolator(mInterpolator); 62 | } 63 | mLastPosition = adapterPosition; 64 | } else { 65 | ViewHelper.clear(holder.itemView); 66 | } 67 | } 68 | 69 | @Override public void onViewRecycled(RecyclerView.ViewHolder holder) { 70 | mAdapter.onViewRecycled(holder); 71 | super.onViewRecycled(holder); 72 | } 73 | 74 | @Override public int getItemCount() { 75 | return mAdapter.getItemCount(); 76 | } 77 | 78 | public void setDuration(int duration) { 79 | mDuration = duration; 80 | } 81 | 82 | public void setInterpolator(Interpolator interpolator) { 83 | mInterpolator = interpolator; 84 | } 85 | 86 | public void setStartPosition(int start) { 87 | mLastPosition = start; 88 | } 89 | 90 | protected abstract Animator[] getAnimators(View view); 91 | 92 | public void setFirstOnly(boolean firstOnly) { 93 | isFirstOnly = firstOnly; 94 | } 95 | 96 | @Override public int getItemViewType(int position) { 97 | return mAdapter.getItemViewType(position); 98 | } 99 | 100 | public RecyclerView.Adapter getWrappedAdapter() { 101 | return mAdapter; 102 | } 103 | 104 | @Override public long getItemId(int position) { 105 | return mAdapter.getItemId(position); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /mrecyclerview/src/main/java/com/marshon/adapters/ScaleInAnimationAdapter.java: -------------------------------------------------------------------------------- 1 | package com.marshon.adapters; 2 | 3 | import android.animation.Animator; 4 | import android.animation.ObjectAnimator; 5 | import android.support.v7.widget.RecyclerView; 6 | import android.view.View; 7 | 8 | /** 9 | * Copyright (C) 2015 Wasabeef 10 | * 11 | * Licensed under the Apache License, Version 2.0 (the "License"); 12 | * you may not use this file except in compliance with the License. 13 | * You may obtain a copy of the License at 14 | * 15 | * http://www.apache.org/licenses/LICENSE-2.0 16 | * 17 | * Unless required by applicable law or agreed to in writing, software 18 | * distributed under the License is distributed on an "AS IS" BASIS, 19 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20 | * See the License for the specific language governing permissions and 21 | * limitations under the License. 22 | */ 23 | 24 | public class ScaleInAnimationAdapter extends AnimationAdapter { 25 | 26 | private static final float DEFAULT_SCALE_FROM = .5f; 27 | private final float mFrom; 28 | 29 | public ScaleInAnimationAdapter(RecyclerView.Adapter adapter) { 30 | this(adapter, DEFAULT_SCALE_FROM); 31 | } 32 | 33 | public ScaleInAnimationAdapter(RecyclerView.Adapter adapter, float from) { 34 | super(adapter); 35 | mFrom = from; 36 | } 37 | 38 | @Override protected Animator[] getAnimators(View view) { 39 | ObjectAnimator scaleX = ObjectAnimator.ofFloat(view, "scaleX", mFrom, 1f); 40 | ObjectAnimator scaleY = ObjectAnimator.ofFloat(view, "scaleY", mFrom, 1f); 41 | return new ObjectAnimator[] { scaleX, scaleY }; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /mrecyclerview/src/main/java/com/marshon/adapters/SlideInBottomAnimationAdapter.java: -------------------------------------------------------------------------------- 1 | package com.marshon.adapters; 2 | 3 | import android.animation.Animator; 4 | import android.animation.ObjectAnimator; 5 | import android.support.v7.widget.RecyclerView; 6 | import android.view.View; 7 | 8 | /** 9 | * Copyright (C) 2015 Wasabeef 10 | * 11 | * Licensed under the Apache License, Version 2.0 (the "License"); 12 | * you may not use this file except in compliance with the License. 13 | * You may obtain a copy of the License at 14 | * 15 | * http://www.apache.org/licenses/LICENSE-2.0 16 | * 17 | * Unless required by applicable law or agreed to in writing, software 18 | * distributed under the License is distributed on an "AS IS" BASIS, 19 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20 | * See the License for the specific language governing permissions and 21 | * limitations under the License. 22 | */ 23 | 24 | public class SlideInBottomAnimationAdapter extends AnimationAdapter { 25 | 26 | public SlideInBottomAnimationAdapter(RecyclerView.Adapter adapter) { 27 | super(adapter); 28 | } 29 | 30 | @Override protected Animator[] getAnimators(View view) { 31 | return new Animator[] { 32 | ObjectAnimator.ofFloat(view, "translationY", view.getMeasuredHeight(), 0) 33 | }; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /mrecyclerview/src/main/java/com/marshon/adapters/SlideInLeftAnimationAdapter.java: -------------------------------------------------------------------------------- 1 | package com.marshon.adapters; 2 | 3 | import android.animation.Animator; 4 | import android.animation.ObjectAnimator; 5 | import android.support.v7.widget.RecyclerView; 6 | import android.view.View; 7 | 8 | /** 9 | * Copyright (C) 2015 Wasabeef 10 | * 11 | * Licensed under the Apache License, Version 2.0 (the "License"); 12 | * you may not use this file except in compliance with the License. 13 | * You may obtain a copy of the License at 14 | * 15 | * http://www.apache.org/licenses/LICENSE-2.0 16 | * 17 | * Unless required by applicable law or agreed to in writing, software 18 | * distributed under the License is distributed on an "AS IS" BASIS, 19 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20 | * See the License for the specific language governing permissions and 21 | * limitations under the License. 22 | */ 23 | 24 | public class SlideInLeftAnimationAdapter extends AnimationAdapter { 25 | 26 | public SlideInLeftAnimationAdapter(RecyclerView.Adapter adapter) { 27 | super(adapter); 28 | } 29 | 30 | @Override protected Animator[] getAnimators(View view) { 31 | return new Animator[] { 32 | ObjectAnimator.ofFloat(view, "translationX", -view.getRootView().getWidth(), 0) 33 | }; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /mrecyclerview/src/main/java/com/marshon/adapters/SlideInRightAnimationAdapter.java: -------------------------------------------------------------------------------- 1 | package com.marshon.adapters; 2 | 3 | import android.animation.Animator; 4 | import android.animation.ObjectAnimator; 5 | import android.support.v7.widget.RecyclerView; 6 | import android.view.View; 7 | 8 | /** 9 | * Copyright (C) 2015 Wasabeef 10 | * 11 | * Licensed under the Apache License, Version 2.0 (the "License"); 12 | * you may not use this file except in compliance with the License. 13 | * You may obtain a copy of the License at 14 | * 15 | * http://www.apache.org/licenses/LICENSE-2.0 16 | * 17 | * Unless required by applicable law or agreed to in writing, software 18 | * distributed under the License is distributed on an "AS IS" BASIS, 19 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20 | * See the License for the specific language governing permissions and 21 | * limitations under the License. 22 | */ 23 | 24 | public class SlideInRightAnimationAdapter extends AnimationAdapter { 25 | 26 | public SlideInRightAnimationAdapter(RecyclerView.Adapter adapter) { 27 | super(adapter); 28 | } 29 | 30 | @Override protected Animator[] getAnimators(View view) { 31 | return new Animator[] { 32 | ObjectAnimator.ofFloat(view, "translationX", view.getRootView().getWidth(), 0) 33 | }; 34 | } 35 | 36 | 37 | } 38 | -------------------------------------------------------------------------------- /mrecyclerview/src/main/java/com/marshon/animators/BaseItemAnimator.java: -------------------------------------------------------------------------------- 1 | package com.marshon.animators; 2 | /* 3 | * Copyright (C) 2015 Wasabeef 4 | * Copyright (C) 2014 The Android Open Source Project 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | */ 19 | 20 | import android.support.v4.view.ViewCompat; 21 | import android.support.v4.view.ViewPropertyAnimatorCompat; 22 | import android.support.v4.view.ViewPropertyAnimatorListener; 23 | import android.support.v7.widget.RecyclerView; 24 | import android.support.v7.widget.RecyclerView.ViewHolder; 25 | import android.support.v7.widget.SimpleItemAnimator; 26 | import android.view.View; 27 | import android.view.animation.Interpolator; 28 | import android.view.animation.LinearInterpolator; 29 | 30 | import com.marshon.animators.holder.AnimateViewHolder; 31 | import com.marshon.internal.ViewHelper; 32 | 33 | import java.util.ArrayList; 34 | import java.util.List; 35 | 36 | public abstract class BaseItemAnimator extends SimpleItemAnimator { 37 | 38 | private static final boolean DEBUG = false; 39 | 40 | private ArrayList mPendingRemovals = new ArrayList<>(); 41 | private ArrayList mPendingAdditions = new ArrayList<>(); 42 | private ArrayList mPendingMoves = new ArrayList<>(); 43 | private ArrayList mPendingChanges = new ArrayList<>(); 44 | 45 | private ArrayList> mAdditionsList = new ArrayList<>(); 46 | private ArrayList> mMovesList = new ArrayList<>(); 47 | private ArrayList> mChangesList = new ArrayList<>(); 48 | 49 | protected ArrayList mAddAnimations = new ArrayList<>(); 50 | private ArrayList mMoveAnimations = new ArrayList<>(); 51 | protected ArrayList mRemoveAnimations = new ArrayList<>(); 52 | private ArrayList mChangeAnimations = new ArrayList<>(); 53 | 54 | protected Interpolator mInterpolator = new LinearInterpolator(); 55 | 56 | private static class MoveInfo { 57 | 58 | public ViewHolder holder; 59 | public int fromX, fromY, toX, toY; 60 | 61 | private MoveInfo(ViewHolder holder, int fromX, int fromY, int toX, int toY) { 62 | this.holder = holder; 63 | this.fromX = fromX; 64 | this.fromY = fromY; 65 | this.toX = toX; 66 | this.toY = toY; 67 | } 68 | } 69 | 70 | private static class ChangeInfo { 71 | 72 | public ViewHolder oldHolder, newHolder; 73 | public int fromX, fromY, toX, toY; 74 | 75 | private ChangeInfo(ViewHolder oldHolder, ViewHolder newHolder) { 76 | this.oldHolder = oldHolder; 77 | this.newHolder = newHolder; 78 | } 79 | 80 | private ChangeInfo(ViewHolder oldHolder, ViewHolder newHolder, int fromX, int fromY, int toX, 81 | int toY) { 82 | this(oldHolder, newHolder); 83 | this.fromX = fromX; 84 | this.fromY = fromY; 85 | this.toX = toX; 86 | this.toY = toY; 87 | } 88 | 89 | @Override public String toString() { 90 | return "ChangeInfo{" + 91 | "oldHolder=" + oldHolder + 92 | ", newHolder=" + newHolder + 93 | ", fromX=" + fromX + 94 | ", fromY=" + fromY + 95 | ", toX=" + toX + 96 | ", toY=" + toY + 97 | '}'; 98 | } 99 | } 100 | 101 | public BaseItemAnimator() { 102 | super(); 103 | setSupportsChangeAnimations(false); 104 | } 105 | 106 | public void setInterpolator(Interpolator mInterpolator) { 107 | this.mInterpolator = mInterpolator; 108 | } 109 | 110 | @Override public void runPendingAnimations() { 111 | boolean removalsPending = !mPendingRemovals.isEmpty(); 112 | boolean movesPending = !mPendingMoves.isEmpty(); 113 | boolean changesPending = !mPendingChanges.isEmpty(); 114 | boolean additionsPending = !mPendingAdditions.isEmpty(); 115 | if (!removalsPending && !movesPending && !additionsPending && !changesPending) { 116 | // nothing to animate 117 | return; 118 | } 119 | // First, remove stuff 120 | for (ViewHolder holder : mPendingRemovals) { 121 | doAnimateRemove(holder); 122 | } 123 | mPendingRemovals.clear(); 124 | // Next, move stuff 125 | if (movesPending) { 126 | final ArrayList moves = new ArrayList(); 127 | moves.addAll(mPendingMoves); 128 | mMovesList.add(moves); 129 | mPendingMoves.clear(); 130 | Runnable mover = new Runnable() { 131 | @Override public void run() { 132 | for (MoveInfo moveInfo : moves) { 133 | animateMoveImpl(moveInfo.holder, moveInfo.fromX, moveInfo.fromY, moveInfo.toX, 134 | moveInfo.toY); 135 | } 136 | moves.clear(); 137 | mMovesList.remove(moves); 138 | } 139 | }; 140 | if (removalsPending) { 141 | View view = moves.get(0).holder.itemView; 142 | ViewCompat.postOnAnimationDelayed(view, mover, getRemoveDuration()); 143 | } else { 144 | mover.run(); 145 | } 146 | } 147 | // Next, change stuff, to run in parallel with move animations 148 | if (changesPending) { 149 | final ArrayList changes = new ArrayList(); 150 | changes.addAll(mPendingChanges); 151 | mChangesList.add(changes); 152 | mPendingChanges.clear(); 153 | Runnable changer = new Runnable() { 154 | @Override public void run() { 155 | for (ChangeInfo change : changes) { 156 | animateChangeImpl(change); 157 | } 158 | changes.clear(); 159 | mChangesList.remove(changes); 160 | } 161 | }; 162 | if (removalsPending) { 163 | ViewHolder holder = changes.get(0).oldHolder; 164 | ViewCompat.postOnAnimationDelayed(holder.itemView, changer, getRemoveDuration()); 165 | } else { 166 | changer.run(); 167 | } 168 | } 169 | // Next, add stuff 170 | if (additionsPending) { 171 | final ArrayList additions = new ArrayList(); 172 | additions.addAll(mPendingAdditions); 173 | mAdditionsList.add(additions); 174 | mPendingAdditions.clear(); 175 | Runnable adder = new Runnable() { 176 | public void run() { 177 | for (ViewHolder holder : additions) { 178 | doAnimateAdd(holder); 179 | } 180 | additions.clear(); 181 | mAdditionsList.remove(additions); 182 | } 183 | }; 184 | if (removalsPending || movesPending || changesPending) { 185 | long removeDuration = removalsPending ? getRemoveDuration() : 0; 186 | long moveDuration = movesPending ? getMoveDuration() : 0; 187 | long changeDuration = changesPending ? getChangeDuration() : 0; 188 | long totalDelay = removeDuration + Math.max(moveDuration, changeDuration); 189 | View view = additions.get(0).itemView; 190 | ViewCompat.postOnAnimationDelayed(view, adder, totalDelay); 191 | } else { 192 | adder.run(); 193 | } 194 | } 195 | } 196 | 197 | protected void preAnimateRemoveImpl(final RecyclerView.ViewHolder holder) { 198 | } 199 | 200 | protected void preAnimateAddImpl(final RecyclerView.ViewHolder holder) { 201 | } 202 | 203 | protected abstract void animateRemoveImpl(final RecyclerView.ViewHolder holder); 204 | 205 | protected abstract void animateAddImpl(final RecyclerView.ViewHolder holder); 206 | 207 | private void preAnimateRemove(final RecyclerView.ViewHolder holder) { 208 | ViewHelper.clear(holder.itemView); 209 | 210 | if (holder instanceof AnimateViewHolder) { 211 | ((AnimateViewHolder) holder).preAnimateRemoveImpl(); 212 | } else { 213 | preAnimateRemoveImpl(holder); 214 | } 215 | } 216 | 217 | private void preAnimateAdd(final RecyclerView.ViewHolder holder) { 218 | ViewHelper.clear(holder.itemView); 219 | 220 | if (holder instanceof AnimateViewHolder) { 221 | ((AnimateViewHolder) holder).preAnimateAddImpl(); 222 | } else { 223 | preAnimateAddImpl(holder); 224 | } 225 | } 226 | 227 | private void doAnimateRemove(final RecyclerView.ViewHolder holder) { 228 | if (holder instanceof AnimateViewHolder) { 229 | ((AnimateViewHolder) holder).animateRemoveImpl(new DefaultRemoveVpaListener(holder)); 230 | } else { 231 | animateRemoveImpl(holder); 232 | } 233 | 234 | mRemoveAnimations.add(holder); 235 | } 236 | 237 | private void doAnimateAdd(final RecyclerView.ViewHolder holder) { 238 | if (holder instanceof AnimateViewHolder) { 239 | ((AnimateViewHolder) holder).animateAddImpl(new DefaultAddVpaListener(holder)); 240 | } else { 241 | animateAddImpl(holder); 242 | } 243 | 244 | mAddAnimations.add(holder); 245 | } 246 | 247 | @Override public boolean animateRemove(final ViewHolder holder) { 248 | endAnimation(holder); 249 | preAnimateRemove(holder); 250 | mPendingRemovals.add(holder); 251 | return true; 252 | } 253 | 254 | protected long getRemoveDelay(final RecyclerView.ViewHolder holder) { 255 | return Math.abs(holder.getOldPosition() * getRemoveDuration() / 4); 256 | } 257 | 258 | @Override public boolean animateAdd(final ViewHolder holder) { 259 | endAnimation(holder); 260 | preAnimateAdd(holder); 261 | mPendingAdditions.add(holder); 262 | return true; 263 | } 264 | 265 | protected long getAddDelay(final RecyclerView.ViewHolder holder) { 266 | return Math.abs(holder.getAdapterPosition() * getAddDuration() / 4); 267 | } 268 | 269 | @Override 270 | public boolean animateMove(final ViewHolder holder, int fromX, int fromY, int toX, int toY) { 271 | final View view = holder.itemView; 272 | fromX += ViewCompat.getTranslationX(holder.itemView); 273 | fromY += ViewCompat.getTranslationY(holder.itemView); 274 | endAnimation(holder); 275 | int deltaX = toX - fromX; 276 | int deltaY = toY - fromY; 277 | if (deltaX == 0 && deltaY == 0) { 278 | dispatchMoveFinished(holder); 279 | return false; 280 | } 281 | if (deltaX != 0) { 282 | ViewCompat.setTranslationX(view, -deltaX); 283 | } 284 | if (deltaY != 0) { 285 | ViewCompat.setTranslationY(view, -deltaY); 286 | } 287 | mPendingMoves.add(new MoveInfo(holder, fromX, fromY, toX, toY)); 288 | return true; 289 | } 290 | 291 | private void animateMoveImpl(final ViewHolder holder, int fromX, int fromY, int toX, int toY) { 292 | final View view = holder.itemView; 293 | final int deltaX = toX - fromX; 294 | final int deltaY = toY - fromY; 295 | if (deltaX != 0) { 296 | ViewCompat.animate(view).translationX(0); 297 | } 298 | if (deltaY != 0) { 299 | ViewCompat.animate(view).translationY(0); 300 | } 301 | // TODO: make EndActions end listeners instead, since end actions aren't called when 302 | // vpas are canceled (and can't end them. why?) 303 | // need listener functionality in VPACompat for this. Ick. 304 | mMoveAnimations.add(holder); 305 | final ViewPropertyAnimatorCompat animation = ViewCompat.animate(view); 306 | animation.setDuration(getMoveDuration()).setListener(new VpaListenerAdapter() { 307 | @Override public void onAnimationStart(View view) { 308 | dispatchMoveStarting(holder); 309 | } 310 | 311 | @Override public void onAnimationCancel(View view) { 312 | if (deltaX != 0) { 313 | ViewCompat.setTranslationX(view, 0); 314 | } 315 | if (deltaY != 0) { 316 | ViewCompat.setTranslationY(view, 0); 317 | } 318 | } 319 | 320 | @Override public void onAnimationEnd(View view) { 321 | animation.setListener(null); 322 | dispatchMoveFinished(holder); 323 | mMoveAnimations.remove(holder); 324 | dispatchFinishedWhenDone(); 325 | } 326 | }).start(); 327 | } 328 | 329 | @Override 330 | public boolean animateChange(ViewHolder oldHolder, ViewHolder newHolder, int fromX, int fromY, 331 | int toX, int toY) { 332 | final float prevTranslationX = ViewCompat.getTranslationX(oldHolder.itemView); 333 | final float prevTranslationY = ViewCompat.getTranslationY(oldHolder.itemView); 334 | final float prevAlpha = ViewCompat.getAlpha(oldHolder.itemView); 335 | endAnimation(oldHolder); 336 | int deltaX = (int) (toX - fromX - prevTranslationX); 337 | int deltaY = (int) (toY - fromY - prevTranslationY); 338 | // recover prev translation state after ending animation 339 | ViewCompat.setTranslationX(oldHolder.itemView, prevTranslationX); 340 | ViewCompat.setTranslationY(oldHolder.itemView, prevTranslationY); 341 | ViewCompat.setAlpha(oldHolder.itemView, prevAlpha); 342 | if (newHolder != null && newHolder.itemView != null) { 343 | // carry over translation values 344 | endAnimation(newHolder); 345 | ViewCompat.setTranslationX(newHolder.itemView, -deltaX); 346 | ViewCompat.setTranslationY(newHolder.itemView, -deltaY); 347 | ViewCompat.setAlpha(newHolder.itemView, 0); 348 | } 349 | mPendingChanges.add(new ChangeInfo(oldHolder, newHolder, fromX, fromY, toX, toY)); 350 | return true; 351 | } 352 | 353 | private void animateChangeImpl(final ChangeInfo changeInfo) { 354 | final ViewHolder holder = changeInfo.oldHolder; 355 | final View view = holder == null ? null : holder.itemView; 356 | final ViewHolder newHolder = changeInfo.newHolder; 357 | final View newView = newHolder != null ? newHolder.itemView : null; 358 | if (view != null) { 359 | mChangeAnimations.add(changeInfo.oldHolder); 360 | final ViewPropertyAnimatorCompat oldViewAnim = 361 | ViewCompat.animate(view).setDuration(getChangeDuration()); 362 | oldViewAnim.translationX(changeInfo.toX - changeInfo.fromX); 363 | oldViewAnim.translationY(changeInfo.toY - changeInfo.fromY); 364 | oldViewAnim.alpha(0).setListener(new VpaListenerAdapter() { 365 | @Override public void onAnimationStart(View view) { 366 | dispatchChangeStarting(changeInfo.oldHolder, true); 367 | } 368 | 369 | @Override public void onAnimationEnd(View view) { 370 | oldViewAnim.setListener(null); 371 | ViewCompat.setAlpha(view, 1); 372 | ViewCompat.setTranslationX(view, 0); 373 | ViewCompat.setTranslationY(view, 0); 374 | dispatchChangeFinished(changeInfo.oldHolder, true); 375 | mChangeAnimations.remove(changeInfo.oldHolder); 376 | dispatchFinishedWhenDone(); 377 | } 378 | }).start(); 379 | } 380 | if (newView != null) { 381 | mChangeAnimations.add(changeInfo.newHolder); 382 | final ViewPropertyAnimatorCompat newViewAnimation = ViewCompat.animate(newView); 383 | newViewAnimation.translationX(0).translationY(0).setDuration(getChangeDuration()). 384 | alpha(1).setListener(new VpaListenerAdapter() { 385 | @Override public void onAnimationStart(View view) { 386 | dispatchChangeStarting(changeInfo.newHolder, false); 387 | } 388 | 389 | @Override public void onAnimationEnd(View view) { 390 | newViewAnimation.setListener(null); 391 | ViewCompat.setAlpha(newView, 1); 392 | ViewCompat.setTranslationX(newView, 0); 393 | ViewCompat.setTranslationY(newView, 0); 394 | dispatchChangeFinished(changeInfo.newHolder, false); 395 | mChangeAnimations.remove(changeInfo.newHolder); 396 | dispatchFinishedWhenDone(); 397 | } 398 | }).start(); 399 | } 400 | } 401 | 402 | private void endChangeAnimation(List infoList, ViewHolder item) { 403 | for (int i = infoList.size() - 1; i >= 0; i--) { 404 | ChangeInfo changeInfo = infoList.get(i); 405 | if (endChangeAnimationIfNecessary(changeInfo, item)) { 406 | if (changeInfo.oldHolder == null && changeInfo.newHolder == null) { 407 | infoList.remove(changeInfo); 408 | } 409 | } 410 | } 411 | } 412 | 413 | private void endChangeAnimationIfNecessary(ChangeInfo changeInfo) { 414 | if (changeInfo.oldHolder != null) { 415 | endChangeAnimationIfNecessary(changeInfo, changeInfo.oldHolder); 416 | } 417 | if (changeInfo.newHolder != null) { 418 | endChangeAnimationIfNecessary(changeInfo, changeInfo.newHolder); 419 | } 420 | } 421 | 422 | private boolean endChangeAnimationIfNecessary(ChangeInfo changeInfo, ViewHolder item) { 423 | boolean oldItem = false; 424 | if (changeInfo.newHolder == item) { 425 | changeInfo.newHolder = null; 426 | } else if (changeInfo.oldHolder == item) { 427 | changeInfo.oldHolder = null; 428 | oldItem = true; 429 | } else { 430 | return false; 431 | } 432 | ViewCompat.setAlpha(item.itemView, 1); 433 | ViewCompat.setTranslationX(item.itemView, 0); 434 | ViewCompat.setTranslationY(item.itemView, 0); 435 | dispatchChangeFinished(item, oldItem); 436 | return true; 437 | } 438 | 439 | @Override public void endAnimation(ViewHolder item) { 440 | final View view = item.itemView; 441 | // this will trigger end callback which should set properties to their target values. 442 | ViewCompat.animate(view).cancel(); 443 | // TODO if some other animations are chained to end, how do we cancel them as well? 444 | for (int i = mPendingMoves.size() - 1; i >= 0; i--) { 445 | MoveInfo moveInfo = mPendingMoves.get(i); 446 | if (moveInfo.holder == item) { 447 | ViewCompat.setTranslationY(view, 0); 448 | ViewCompat.setTranslationX(view, 0); 449 | dispatchMoveFinished(item); 450 | mPendingMoves.remove(i); 451 | } 452 | } 453 | endChangeAnimation(mPendingChanges, item); 454 | if (mPendingRemovals.remove(item)) { 455 | ViewHelper.clear(item.itemView); 456 | dispatchRemoveFinished(item); 457 | } 458 | if (mPendingAdditions.remove(item)) { 459 | ViewHelper.clear(item.itemView); 460 | dispatchAddFinished(item); 461 | } 462 | 463 | for (int i = mChangesList.size() - 1; i >= 0; i--) { 464 | ArrayList changes = mChangesList.get(i); 465 | endChangeAnimation(changes, item); 466 | if (changes.isEmpty()) { 467 | mChangesList.remove(i); 468 | } 469 | } 470 | for (int i = mMovesList.size() - 1; i >= 0; i--) { 471 | ArrayList moves = mMovesList.get(i); 472 | for (int j = moves.size() - 1; j >= 0; j--) { 473 | MoveInfo moveInfo = moves.get(j); 474 | if (moveInfo.holder == item) { 475 | ViewCompat.setTranslationY(view, 0); 476 | ViewCompat.setTranslationX(view, 0); 477 | dispatchMoveFinished(item); 478 | moves.remove(j); 479 | if (moves.isEmpty()) { 480 | mMovesList.remove(i); 481 | } 482 | break; 483 | } 484 | } 485 | } 486 | for (int i = mAdditionsList.size() - 1; i >= 0; i--) { 487 | ArrayList additions = mAdditionsList.get(i); 488 | if (additions.remove(item)) { 489 | ViewHelper.clear(item.itemView); 490 | dispatchAddFinished(item); 491 | if (additions.isEmpty()) { 492 | mAdditionsList.remove(i); 493 | } 494 | } 495 | } 496 | 497 | // animations should be ended by the cancel above. 498 | if (mRemoveAnimations.remove(item) && DEBUG) { 499 | throw new IllegalStateException( 500 | "after animation is cancelled, item should not be in " + "mRemoveAnimations list"); 501 | } 502 | 503 | if (mAddAnimations.remove(item) && DEBUG) { 504 | throw new IllegalStateException( 505 | "after animation is cancelled, item should not be in " + "mAddAnimations list"); 506 | } 507 | 508 | if (mChangeAnimations.remove(item) && DEBUG) { 509 | throw new IllegalStateException( 510 | "after animation is cancelled, item should not be in " + "mChangeAnimations list"); 511 | } 512 | 513 | if (mMoveAnimations.remove(item) && DEBUG) { 514 | throw new IllegalStateException( 515 | "after animation is cancelled, item should not be in " + "mMoveAnimations list"); 516 | } 517 | dispatchFinishedWhenDone(); 518 | } 519 | 520 | @Override public boolean isRunning() { 521 | return (!mPendingAdditions.isEmpty() || 522 | !mPendingChanges.isEmpty() || 523 | !mPendingMoves.isEmpty() || 524 | !mPendingRemovals.isEmpty() || 525 | !mMoveAnimations.isEmpty() || 526 | !mRemoveAnimations.isEmpty() || 527 | !mAddAnimations.isEmpty() || 528 | !mChangeAnimations.isEmpty() || 529 | !mMovesList.isEmpty() || 530 | !mAdditionsList.isEmpty() || 531 | !mChangesList.isEmpty()); 532 | } 533 | 534 | /** 535 | * Check the state of currently pending and running animations. If there are none 536 | * pending/running, call #dispatchAnimationsFinished() to notify any 537 | * listeners. 538 | */ 539 | private void dispatchFinishedWhenDone() { 540 | if (!isRunning()) { 541 | dispatchAnimationsFinished(); 542 | } 543 | } 544 | 545 | @Override public void endAnimations() { 546 | int count = mPendingMoves.size(); 547 | for (int i = count - 1; i >= 0; i--) { 548 | MoveInfo item = mPendingMoves.get(i); 549 | View view = item.holder.itemView; 550 | ViewCompat.setTranslationY(view, 0); 551 | ViewCompat.setTranslationX(view, 0); 552 | dispatchMoveFinished(item.holder); 553 | mPendingMoves.remove(i); 554 | } 555 | count = mPendingRemovals.size(); 556 | for (int i = count - 1; i >= 0; i--) { 557 | ViewHolder item = mPendingRemovals.get(i); 558 | dispatchRemoveFinished(item); 559 | mPendingRemovals.remove(i); 560 | } 561 | count = mPendingAdditions.size(); 562 | for (int i = count - 1; i >= 0; i--) { 563 | ViewHolder item = mPendingAdditions.get(i); 564 | ViewHelper.clear(item.itemView); 565 | dispatchAddFinished(item); 566 | mPendingAdditions.remove(i); 567 | } 568 | count = mPendingChanges.size(); 569 | for (int i = count - 1; i >= 0; i--) { 570 | endChangeAnimationIfNecessary(mPendingChanges.get(i)); 571 | } 572 | mPendingChanges.clear(); 573 | if (!isRunning()) { 574 | return; 575 | } 576 | 577 | int listCount = mMovesList.size(); 578 | for (int i = listCount - 1; i >= 0; i--) { 579 | ArrayList moves = mMovesList.get(i); 580 | count = moves.size(); 581 | for (int j = count - 1; j >= 0; j--) { 582 | MoveInfo moveInfo = moves.get(j); 583 | ViewHolder item = moveInfo.holder; 584 | View view = item.itemView; 585 | ViewCompat.setTranslationY(view, 0); 586 | ViewCompat.setTranslationX(view, 0); 587 | dispatchMoveFinished(moveInfo.holder); 588 | moves.remove(j); 589 | if (moves.isEmpty()) { 590 | mMovesList.remove(moves); 591 | } 592 | } 593 | } 594 | listCount = mAdditionsList.size(); 595 | for (int i = listCount - 1; i >= 0; i--) { 596 | ArrayList additions = mAdditionsList.get(i); 597 | count = additions.size(); 598 | for (int j = count - 1; j >= 0; j--) { 599 | ViewHolder item = additions.get(j); 600 | View view = item.itemView; 601 | ViewCompat.setAlpha(view, 1); 602 | dispatchAddFinished(item); 603 | //this check prevent exception when removal already happened during finishing animation 604 | if (j < additions.size()) { 605 | additions.remove(j); 606 | } 607 | if (additions.isEmpty()) { 608 | mAdditionsList.remove(additions); 609 | } 610 | } 611 | } 612 | listCount = mChangesList.size(); 613 | for (int i = listCount - 1; i >= 0; i--) { 614 | ArrayList changes = mChangesList.get(i); 615 | count = changes.size(); 616 | for (int j = count - 1; j >= 0; j--) { 617 | endChangeAnimationIfNecessary(changes.get(j)); 618 | if (changes.isEmpty()) { 619 | mChangesList.remove(changes); 620 | } 621 | } 622 | } 623 | 624 | cancelAll(mRemoveAnimations); 625 | cancelAll(mMoveAnimations); 626 | cancelAll(mAddAnimations); 627 | cancelAll(mChangeAnimations); 628 | 629 | dispatchAnimationsFinished(); 630 | } 631 | 632 | void cancelAll(List viewHolders) { 633 | for (int i = viewHolders.size() - 1; i >= 0; i--) { 634 | ViewCompat.animate(viewHolders.get(i).itemView).cancel(); 635 | } 636 | } 637 | 638 | private static class VpaListenerAdapter implements ViewPropertyAnimatorListener { 639 | 640 | @Override public void onAnimationStart(View view) { 641 | } 642 | 643 | @Override public void onAnimationEnd(View view) { 644 | } 645 | 646 | @Override public void onAnimationCancel(View view) { 647 | } 648 | } 649 | 650 | protected class DefaultAddVpaListener extends VpaListenerAdapter { 651 | 652 | RecyclerView.ViewHolder mViewHolder; 653 | 654 | public DefaultAddVpaListener(final RecyclerView.ViewHolder holder) { 655 | mViewHolder = holder; 656 | } 657 | 658 | @Override public void onAnimationStart(View view) { 659 | dispatchAddStarting(mViewHolder); 660 | } 661 | 662 | @Override public void onAnimationCancel(View view) { 663 | ViewHelper.clear(view); 664 | } 665 | 666 | @Override public void onAnimationEnd(View view) { 667 | ViewHelper.clear(view); 668 | dispatchAddFinished(mViewHolder); 669 | mAddAnimations.remove(mViewHolder); 670 | dispatchFinishedWhenDone(); 671 | } 672 | } 673 | 674 | protected class DefaultRemoveVpaListener extends VpaListenerAdapter { 675 | 676 | RecyclerView.ViewHolder mViewHolder; 677 | 678 | public DefaultRemoveVpaListener(final RecyclerView.ViewHolder holder) { 679 | mViewHolder = holder; 680 | } 681 | 682 | @Override public void onAnimationStart(View view) { 683 | dispatchRemoveStarting(mViewHolder); 684 | } 685 | 686 | @Override public void onAnimationCancel(View view) { 687 | ViewHelper.clear(view); 688 | } 689 | 690 | @Override public void onAnimationEnd(View view) { 691 | ViewHelper.clear(view); 692 | dispatchRemoveFinished(mViewHolder); 693 | mRemoveAnimations.remove(mViewHolder); 694 | dispatchFinishedWhenDone(); 695 | } 696 | } 697 | } 698 | -------------------------------------------------------------------------------- /mrecyclerview/src/main/java/com/marshon/animators/FadeInAnimator.java: -------------------------------------------------------------------------------- 1 | package com.marshon.animators; 2 | 3 | /** 4 | * Copyright (C) 2015 Wasabeef 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import android.support.v4.view.ViewCompat; 20 | import android.support.v7.widget.RecyclerView; 21 | import android.view.animation.Interpolator; 22 | 23 | public class FadeInAnimator extends BaseItemAnimator { 24 | 25 | public FadeInAnimator() { 26 | } 27 | 28 | public FadeInAnimator(Interpolator interpolator) { 29 | mInterpolator = interpolator; 30 | } 31 | 32 | @Override protected void animateRemoveImpl(final RecyclerView.ViewHolder holder) { 33 | ViewCompat.animate(holder.itemView) 34 | .alpha(0) 35 | .setDuration(getRemoveDuration()) 36 | .setInterpolator(mInterpolator) 37 | .setListener(new DefaultRemoveVpaListener(holder)) 38 | .setStartDelay(getRemoveDelay(holder)) 39 | .start(); 40 | } 41 | 42 | @Override protected void preAnimateAddImpl(RecyclerView.ViewHolder holder) { 43 | ViewCompat.setAlpha(holder.itemView, 0); 44 | } 45 | 46 | @Override protected void animateAddImpl(final RecyclerView.ViewHolder holder) { 47 | ViewCompat.animate(holder.itemView) 48 | .alpha(1) 49 | .setDuration(getAddDuration()) 50 | .setInterpolator(mInterpolator) 51 | .setListener(new DefaultAddVpaListener(holder)) 52 | .setStartDelay(getAddDelay(holder)) 53 | .start(); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /mrecyclerview/src/main/java/com/marshon/animators/FadeInDownAnimator.java: -------------------------------------------------------------------------------- 1 | package com.marshon.animators; 2 | 3 | /** 4 | * Copyright (C) 2015 Wasabeef 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import android.support.v4.view.ViewCompat; 20 | import android.support.v7.widget.RecyclerView; 21 | import android.view.animation.Interpolator; 22 | 23 | public class FadeInDownAnimator extends BaseItemAnimator { 24 | 25 | public FadeInDownAnimator() { 26 | } 27 | 28 | public FadeInDownAnimator(Interpolator interpolator) { 29 | mInterpolator = interpolator; 30 | } 31 | 32 | @Override protected void animateRemoveImpl(final RecyclerView.ViewHolder holder) { 33 | ViewCompat.animate(holder.itemView) 34 | .translationY(-holder.itemView.getHeight() * .25f) 35 | .alpha(0) 36 | .setDuration(getRemoveDuration()) 37 | .setInterpolator(mInterpolator) 38 | .setListener(new DefaultRemoveVpaListener(holder)) 39 | .setStartDelay(getRemoveDelay(holder)) 40 | .start(); 41 | } 42 | 43 | @Override protected void preAnimateAddImpl(RecyclerView.ViewHolder holder) { 44 | ViewCompat.setTranslationY(holder.itemView, -holder.itemView.getHeight() * .25f); 45 | ViewCompat.setAlpha(holder.itemView, 0); 46 | } 47 | 48 | @Override protected void animateAddImpl(final RecyclerView.ViewHolder holder) { 49 | ViewCompat.animate(holder.itemView) 50 | .translationY(0) 51 | .alpha(1) 52 | .setDuration(getAddDuration()) 53 | .setInterpolator(mInterpolator) 54 | .setListener(new DefaultAddVpaListener(holder)) 55 | .setStartDelay(getAddDelay(holder)) 56 | .start(); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /mrecyclerview/src/main/java/com/marshon/animators/FadeInLeftAnimator.java: -------------------------------------------------------------------------------- 1 | package com.marshon.animators; 2 | 3 | /** 4 | * Copyright (C) 2015 Wasabeef 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import android.support.v4.view.ViewCompat; 20 | import android.support.v7.widget.RecyclerView; 21 | import android.view.animation.Interpolator; 22 | 23 | public class FadeInLeftAnimator extends BaseItemAnimator { 24 | 25 | public FadeInLeftAnimator() { 26 | } 27 | 28 | public FadeInLeftAnimator(Interpolator interpolator) { 29 | mInterpolator = interpolator; 30 | } 31 | 32 | @Override protected void animateRemoveImpl(final RecyclerView.ViewHolder holder) { 33 | ViewCompat.animate(holder.itemView) 34 | .translationX(-holder.itemView.getRootView().getWidth() * .25f) 35 | .alpha(0) 36 | .setDuration(getRemoveDuration()) 37 | .setInterpolator(mInterpolator) 38 | .setListener(new DefaultRemoveVpaListener(holder)) 39 | .setStartDelay(getRemoveDelay(holder)) 40 | .start(); 41 | } 42 | 43 | @Override protected void preAnimateAddImpl(RecyclerView.ViewHolder holder) { 44 | ViewCompat.setTranslationX(holder.itemView, -holder.itemView.getRootView().getWidth() * .25f); 45 | ViewCompat.setAlpha(holder.itemView, 0); 46 | } 47 | 48 | @Override protected void animateAddImpl(final RecyclerView.ViewHolder holder) { 49 | ViewCompat.animate(holder.itemView) 50 | .translationX(0) 51 | .alpha(1) 52 | .setDuration(getAddDuration()) 53 | .setInterpolator(mInterpolator) 54 | .setListener(new DefaultAddVpaListener(holder)) 55 | .setStartDelay(getAddDelay(holder)) 56 | .start(); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /mrecyclerview/src/main/java/com/marshon/animators/FadeInRightAnimator.java: -------------------------------------------------------------------------------- 1 | package com.marshon.animators; 2 | 3 | /** 4 | * Copyright (C) 2015 Wasabeef 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import android.support.v4.view.ViewCompat; 20 | import android.support.v7.widget.RecyclerView; 21 | import android.view.animation.Interpolator; 22 | 23 | public class FadeInRightAnimator extends BaseItemAnimator { 24 | 25 | public FadeInRightAnimator() { 26 | } 27 | 28 | public FadeInRightAnimator(Interpolator interpolator) { 29 | mInterpolator = interpolator; 30 | } 31 | 32 | @Override protected void animateRemoveImpl(final RecyclerView.ViewHolder holder) { 33 | ViewCompat.animate(holder.itemView) 34 | .translationX(holder.itemView.getRootView().getWidth() * .25f) 35 | .alpha(0) 36 | .setDuration(getRemoveDuration()) 37 | .setInterpolator(mInterpolator) 38 | .setListener(new DefaultRemoveVpaListener(holder)) 39 | .setStartDelay(getRemoveDelay(holder)) 40 | .start(); 41 | } 42 | 43 | @Override protected void preAnimateAddImpl(RecyclerView.ViewHolder holder) { 44 | ViewCompat.setTranslationX(holder.itemView, holder.itemView.getRootView().getWidth() * .25f); 45 | ViewCompat.setAlpha(holder.itemView, 0); 46 | } 47 | 48 | @Override protected void animateAddImpl(final RecyclerView.ViewHolder holder) { 49 | ViewCompat.animate(holder.itemView) 50 | .translationX(0) 51 | .alpha(1) 52 | .setDuration(getAddDuration()) 53 | .setInterpolator(mInterpolator) 54 | .setListener(new DefaultAddVpaListener(holder)) 55 | .setStartDelay(getAddDelay(holder)) 56 | .start(); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /mrecyclerview/src/main/java/com/marshon/animators/FadeInUpAnimator.java: -------------------------------------------------------------------------------- 1 | package com.marshon.animators; 2 | 3 | /** 4 | * Copyright (C) 2015 Wasabeef 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import android.support.v4.view.ViewCompat; 20 | import android.support.v7.widget.RecyclerView; 21 | import android.view.animation.Interpolator; 22 | 23 | public class FadeInUpAnimator extends BaseItemAnimator { 24 | 25 | public FadeInUpAnimator() { 26 | } 27 | 28 | public FadeInUpAnimator(Interpolator interpolator) { 29 | mInterpolator = interpolator; 30 | } 31 | 32 | @Override protected void animateRemoveImpl(final RecyclerView.ViewHolder holder) { 33 | ViewCompat.animate(holder.itemView) 34 | .translationY(holder.itemView.getHeight() * .25f) 35 | .alpha(0) 36 | .setDuration(getRemoveDuration()) 37 | .setInterpolator(mInterpolator) 38 | .setListener(new DefaultRemoveVpaListener(holder)) 39 | .setStartDelay(getRemoveDelay(holder)) 40 | .start(); 41 | } 42 | 43 | @Override protected void preAnimateAddImpl(RecyclerView.ViewHolder holder) { 44 | ViewCompat.setTranslationY(holder.itemView, holder.itemView.getHeight() * .25f); 45 | ViewCompat.setAlpha(holder.itemView, 0); 46 | } 47 | 48 | @Override protected void animateAddImpl(final RecyclerView.ViewHolder holder) { 49 | ViewCompat.animate(holder.itemView) 50 | .translationY(0) 51 | .alpha(1) 52 | .setDuration(getAddDuration()) 53 | .setInterpolator(mInterpolator) 54 | .setListener(new DefaultAddVpaListener(holder)) 55 | .setStartDelay(getAddDelay(holder)) 56 | .start(); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /mrecyclerview/src/main/java/com/marshon/animators/FlipInBottomXAnimator.java: -------------------------------------------------------------------------------- 1 | package com.marshon.animators; 2 | 3 | /** 4 | * Copyright (C) 2015 Wasabeef 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import android.support.v4.view.ViewCompat; 20 | import android.support.v7.widget.RecyclerView; 21 | import android.view.animation.Interpolator; 22 | 23 | public class FlipInBottomXAnimator extends BaseItemAnimator { 24 | 25 | public FlipInBottomXAnimator() { 26 | } 27 | 28 | public FlipInBottomXAnimator(Interpolator interpolator) { 29 | mInterpolator = interpolator; 30 | } 31 | 32 | @Override protected void animateRemoveImpl(final RecyclerView.ViewHolder holder) { 33 | ViewCompat.animate(holder.itemView) 34 | .rotationX(-90) 35 | .setDuration(getRemoveDuration()) 36 | .setInterpolator(mInterpolator) 37 | .setListener(new DefaultRemoveVpaListener(holder)) 38 | .setStartDelay(getRemoveDelay(holder)) 39 | .start(); 40 | } 41 | 42 | @Override protected void preAnimateAddImpl(RecyclerView.ViewHolder holder) { 43 | ViewCompat.setRotationX(holder.itemView, -90); 44 | } 45 | 46 | @Override protected void animateAddImpl(final RecyclerView.ViewHolder holder) { 47 | ViewCompat.animate(holder.itemView) 48 | .rotationX(0) 49 | .setDuration(getAddDuration()) 50 | .setInterpolator(mInterpolator) 51 | .setListener(new DefaultAddVpaListener(holder)) 52 | .setStartDelay(getAddDelay(holder)) 53 | .start(); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /mrecyclerview/src/main/java/com/marshon/animators/FlipInLeftYAnimator.java: -------------------------------------------------------------------------------- 1 | package com.marshon.animators; 2 | 3 | /** 4 | * Copyright (C) 2015 Wasabeef 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import android.support.v4.view.ViewCompat; 20 | import android.support.v7.widget.RecyclerView; 21 | import android.view.animation.Interpolator; 22 | 23 | public class FlipInLeftYAnimator extends BaseItemAnimator { 24 | 25 | public FlipInLeftYAnimator() { 26 | } 27 | 28 | public FlipInLeftYAnimator(Interpolator interpolator) { 29 | mInterpolator = interpolator; 30 | } 31 | 32 | @Override protected void animateRemoveImpl(final RecyclerView.ViewHolder holder) { 33 | ViewCompat.animate(holder.itemView) 34 | .rotationY(90) 35 | .setDuration(getRemoveDuration()) 36 | .setInterpolator(mInterpolator) 37 | .setListener(new DefaultRemoveVpaListener(holder)) 38 | .setStartDelay(getRemoveDelay(holder)) 39 | .start(); 40 | } 41 | 42 | @Override protected void preAnimateAddImpl(RecyclerView.ViewHolder holder) { 43 | ViewCompat.setRotationY(holder.itemView, 90); 44 | } 45 | 46 | @Override protected void animateAddImpl(final RecyclerView.ViewHolder holder) { 47 | ViewCompat.animate(holder.itemView) 48 | .rotationY(0) 49 | .setDuration(getAddDuration()) 50 | .setInterpolator(mInterpolator) 51 | .setListener(new DefaultAddVpaListener(holder)) 52 | .setStartDelay(getAddDelay(holder)) 53 | .start(); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /mrecyclerview/src/main/java/com/marshon/animators/FlipInRightYAnimator.java: -------------------------------------------------------------------------------- 1 | package com.marshon.animators; 2 | 3 | /** 4 | * Copyright (C) 2015 Wasabeef 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import android.support.v4.view.ViewCompat; 20 | import android.support.v7.widget.RecyclerView; 21 | import android.view.animation.Interpolator; 22 | 23 | public class FlipInRightYAnimator extends BaseItemAnimator { 24 | 25 | public FlipInRightYAnimator() { 26 | } 27 | 28 | public FlipInRightYAnimator(Interpolator interpolator) { 29 | mInterpolator = interpolator; 30 | } 31 | 32 | @Override protected void animateRemoveImpl(final RecyclerView.ViewHolder holder) { 33 | ViewCompat.animate(holder.itemView) 34 | .rotationY(-90) 35 | .setDuration(getRemoveDuration()) 36 | .setInterpolator(mInterpolator) 37 | .setListener(new DefaultRemoveVpaListener(holder)) 38 | .setStartDelay(getRemoveDelay(holder)) 39 | .start(); 40 | } 41 | 42 | @Override protected void preAnimateAddImpl(RecyclerView.ViewHolder holder) { 43 | ViewCompat.setRotationY(holder.itemView, -90); 44 | } 45 | 46 | @Override protected void animateAddImpl(final RecyclerView.ViewHolder holder) { 47 | ViewCompat.animate(holder.itemView) 48 | .rotationY(0) 49 | .setDuration(getAddDuration()) 50 | .setInterpolator(mInterpolator) 51 | .setListener(new DefaultAddVpaListener(holder)) 52 | .setStartDelay(getAddDelay(holder)) 53 | .start(); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /mrecyclerview/src/main/java/com/marshon/animators/FlipInTopXAnimator.java: -------------------------------------------------------------------------------- 1 | package com.marshon.animators; 2 | 3 | /** 4 | * Copyright (C) 2015 Wasabeef 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import android.support.v4.view.ViewCompat; 20 | import android.support.v7.widget.RecyclerView; 21 | import android.view.animation.Interpolator; 22 | 23 | public class FlipInTopXAnimator extends BaseItemAnimator { 24 | 25 | public FlipInTopXAnimator() { 26 | } 27 | 28 | public FlipInTopXAnimator(Interpolator interpolator) { 29 | mInterpolator = interpolator; 30 | } 31 | 32 | @Override protected void animateRemoveImpl(final RecyclerView.ViewHolder holder) { 33 | ViewCompat.animate(holder.itemView) 34 | .rotationX(90) 35 | .setDuration(getRemoveDuration()) 36 | .setInterpolator(mInterpolator) 37 | .setListener(new DefaultRemoveVpaListener(holder)) 38 | .setStartDelay(getRemoveDelay(holder)) 39 | .start(); 40 | } 41 | 42 | @Override protected void preAnimateAddImpl(RecyclerView.ViewHolder holder) { 43 | ViewCompat.setRotationX(holder.itemView, 90); 44 | } 45 | 46 | @Override protected void animateAddImpl(final RecyclerView.ViewHolder holder) { 47 | ViewCompat.animate(holder.itemView) 48 | .rotationX(0) 49 | .setDuration(getAddDuration()) 50 | .setInterpolator(mInterpolator) 51 | .setListener(new DefaultAddVpaListener(holder)) 52 | .setStartDelay(getAddDelay(holder)) 53 | .start(); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /mrecyclerview/src/main/java/com/marshon/animators/LandingAnimator.java: -------------------------------------------------------------------------------- 1 | package com.marshon.animators; 2 | 3 | /** 4 | * Copyright (C) 2015 Wasabeef 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import android.support.v4.view.ViewCompat; 20 | import android.support.v7.widget.RecyclerView; 21 | import android.view.animation.Interpolator; 22 | 23 | public class LandingAnimator extends BaseItemAnimator { 24 | 25 | public LandingAnimator() { 26 | } 27 | 28 | public LandingAnimator(Interpolator interpolator) { 29 | mInterpolator = interpolator; 30 | } 31 | 32 | @Override protected void animateRemoveImpl(final RecyclerView.ViewHolder holder) { 33 | ViewCompat.animate(holder.itemView) 34 | .alpha(0) 35 | .scaleX(1.5f) 36 | .scaleY(1.5f) 37 | .setDuration(getRemoveDuration()) 38 | .setInterpolator(mInterpolator) 39 | .setListener(new DefaultRemoveVpaListener(holder)) 40 | .setStartDelay(getRemoveDelay(holder)) 41 | .start(); 42 | } 43 | 44 | @Override protected void preAnimateAddImpl(RecyclerView.ViewHolder holder) { 45 | ViewCompat.setAlpha(holder.itemView, 0); 46 | ViewCompat.setScaleX(holder.itemView, 1.5f); 47 | ViewCompat.setScaleY(holder.itemView, 1.5f); 48 | } 49 | 50 | @Override protected void animateAddImpl(final RecyclerView.ViewHolder holder) { 51 | ViewCompat.animate(holder.itemView) 52 | .alpha(1) 53 | .scaleX(1) 54 | .scaleY(1) 55 | .setDuration(getAddDuration()) 56 | .setInterpolator(mInterpolator) 57 | .setListener(new DefaultAddVpaListener(holder)) 58 | .setStartDelay(getAddDelay(holder)) 59 | .start(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /mrecyclerview/src/main/java/com/marshon/animators/OvershootInLeftAnimator.java: -------------------------------------------------------------------------------- 1 | package com.marshon.animators; 2 | 3 | /** 4 | * Copyright (C) 2015 Wasabeef 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import android.support.v4.view.ViewCompat; 20 | import android.support.v7.widget.RecyclerView; 21 | import android.view.animation.OvershootInterpolator; 22 | 23 | public class OvershootInLeftAnimator extends BaseItemAnimator { 24 | 25 | private final float mTension; 26 | 27 | public OvershootInLeftAnimator() { 28 | mTension = 2.0f; 29 | } 30 | 31 | public OvershootInLeftAnimator(float mTension) { 32 | this.mTension = mTension; 33 | } 34 | 35 | @Override protected void animateRemoveImpl(final RecyclerView.ViewHolder holder) { 36 | ViewCompat.animate(holder.itemView) 37 | .translationX(-holder.itemView.getRootView().getWidth()) 38 | .setDuration(getRemoveDuration()) 39 | .setListener(new DefaultRemoveVpaListener(holder)) 40 | .setStartDelay(getRemoveDelay(holder)) 41 | .start(); 42 | } 43 | 44 | @Override protected void preAnimateAddImpl(RecyclerView.ViewHolder holder) { 45 | ViewCompat.setTranslationX(holder.itemView, -holder.itemView.getRootView().getWidth()); 46 | } 47 | 48 | @Override protected void animateAddImpl(final RecyclerView.ViewHolder holder) { 49 | ViewCompat.animate(holder.itemView) 50 | .translationX(0) 51 | .setDuration(getAddDuration()) 52 | .setListener(new DefaultAddVpaListener(holder)) 53 | .setInterpolator(new OvershootInterpolator(mTension)) 54 | .setStartDelay(getAddDelay(holder)) 55 | .start(); 56 | } 57 | } 58 | 59 | -------------------------------------------------------------------------------- /mrecyclerview/src/main/java/com/marshon/animators/OvershootInRightAnimator.java: -------------------------------------------------------------------------------- 1 | package com.marshon.animators; 2 | 3 | /** 4 | * Copyright (C) 2015 Wasabeef 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import android.support.v4.view.ViewCompat; 20 | import android.support.v7.widget.RecyclerView; 21 | import android.view.animation.OvershootInterpolator; 22 | 23 | public class OvershootInRightAnimator extends BaseItemAnimator { 24 | 25 | private final float mTension; 26 | 27 | public OvershootInRightAnimator() { 28 | mTension = 2.0f; 29 | } 30 | 31 | public OvershootInRightAnimator(float mTension) { 32 | this.mTension = mTension; 33 | } 34 | 35 | @Override protected void animateRemoveImpl(final RecyclerView.ViewHolder holder) { 36 | ViewCompat.animate(holder.itemView) 37 | .translationX(holder.itemView.getRootView().getWidth()) 38 | .setDuration(getRemoveDuration()) 39 | .setListener(new DefaultRemoveVpaListener(holder)) 40 | .setStartDelay(getRemoveDelay(holder)) 41 | .start(); 42 | } 43 | 44 | @Override protected void preAnimateAddImpl(RecyclerView.ViewHolder holder) { 45 | ViewCompat.setTranslationX(holder.itemView, holder.itemView.getRootView().getWidth()); 46 | } 47 | 48 | @Override protected void animateAddImpl(final RecyclerView.ViewHolder holder) { 49 | ViewCompat.animate(holder.itemView) 50 | .translationX(0) 51 | .setDuration(getAddDuration()) 52 | .setInterpolator(new OvershootInterpolator(mTension)) 53 | .setListener(new DefaultAddVpaListener(holder)) 54 | .setStartDelay(getAddDelay(holder)) 55 | .start(); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /mrecyclerview/src/main/java/com/marshon/animators/ScaleInAnimator.java: -------------------------------------------------------------------------------- 1 | package com.marshon.animators; 2 | 3 | /** 4 | * Copyright (C) 2015 Wasabeef 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import android.support.v4.view.ViewCompat; 20 | import android.support.v7.widget.RecyclerView; 21 | import android.view.animation.Interpolator; 22 | 23 | public class ScaleInAnimator extends BaseItemAnimator { 24 | 25 | public ScaleInAnimator() { 26 | } 27 | 28 | public ScaleInAnimator(Interpolator interpolator) { 29 | mInterpolator = interpolator; 30 | } 31 | 32 | @Override protected void animateRemoveImpl(final RecyclerView.ViewHolder holder) { 33 | ViewCompat.animate(holder.itemView) 34 | .scaleX(0) 35 | .scaleY(0) 36 | .setDuration(getRemoveDuration()) 37 | .setInterpolator(mInterpolator) 38 | .setListener(new DefaultRemoveVpaListener(holder)) 39 | .setStartDelay(getRemoveDelay(holder)) 40 | .start(); 41 | } 42 | 43 | @Override protected void preAnimateAddImpl(RecyclerView.ViewHolder holder) { 44 | ViewCompat.setScaleX(holder.itemView, 0); 45 | ViewCompat.setScaleY(holder.itemView, 0); 46 | } 47 | 48 | @Override protected void animateAddImpl(final RecyclerView.ViewHolder holder) { 49 | ViewCompat.animate(holder.itemView) 50 | .scaleX(1) 51 | .scaleY(1) 52 | .setDuration(getAddDuration()) 53 | .setInterpolator(mInterpolator) 54 | .setListener(new DefaultAddVpaListener(holder)) 55 | .setStartDelay(getAddDelay(holder)) 56 | .start(); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /mrecyclerview/src/main/java/com/marshon/animators/ScaleInBottomAnimator.java: -------------------------------------------------------------------------------- 1 | package com.marshon.animators; 2 | 3 | /** 4 | * Copyright (C) 2015 Wasabeef 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import android.support.v4.view.ViewCompat; 20 | import android.support.v7.widget.RecyclerView; 21 | import android.view.animation.Interpolator; 22 | 23 | public class ScaleInBottomAnimator extends BaseItemAnimator { 24 | 25 | public ScaleInBottomAnimator() { 26 | } 27 | 28 | public ScaleInBottomAnimator(Interpolator interpolator) { 29 | mInterpolator = interpolator; 30 | } 31 | 32 | @Override protected void preAnimateRemoveImpl(RecyclerView.ViewHolder holder) { 33 | // @TODO https://code.google.com/p/android/issues/detail?id=80863 34 | // ViewCompat.setPivotY(holder.itemView, holder.itemView.getHeight()); 35 | holder.itemView.setPivotY(holder.itemView.getHeight()); 36 | } 37 | 38 | @Override protected void animateRemoveImpl(final RecyclerView.ViewHolder holder) { 39 | ViewCompat.animate(holder.itemView) 40 | .scaleX(0) 41 | .scaleY(0) 42 | .setDuration(getRemoveDuration()) 43 | .setInterpolator(mInterpolator) 44 | .setListener(new DefaultRemoveVpaListener(holder)) 45 | .setStartDelay(getRemoveDelay(holder)) 46 | .start(); 47 | } 48 | 49 | @Override protected void preAnimateAddImpl(RecyclerView.ViewHolder holder) { 50 | // @TODO https://code.google.com/p/android/issues/detail?id=80863 51 | // ViewCompat.setPivotY(holder.itemView, holder.itemView.getHeight()); 52 | holder.itemView.setPivotY(holder.itemView.getHeight()); 53 | ViewCompat.setScaleX(holder.itemView, 0); 54 | ViewCompat.setScaleY(holder.itemView, 0); 55 | } 56 | 57 | @Override protected void animateAddImpl(final RecyclerView.ViewHolder holder) { 58 | ViewCompat.animate(holder.itemView) 59 | .scaleX(1) 60 | .scaleY(1) 61 | .setDuration(getAddDuration()) 62 | .setInterpolator(mInterpolator) 63 | .setListener(new DefaultAddVpaListener(holder)) 64 | .setStartDelay(getAddDelay(holder)) 65 | .start(); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /mrecyclerview/src/main/java/com/marshon/animators/ScaleInLeftAnimator.java: -------------------------------------------------------------------------------- 1 | package com.marshon.animators; 2 | 3 | /** 4 | * Copyright (C) 2015 Wasabeef 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import android.support.v4.view.ViewCompat; 20 | import android.support.v7.widget.RecyclerView; 21 | import android.view.animation.Interpolator; 22 | 23 | public class ScaleInLeftAnimator extends BaseItemAnimator { 24 | 25 | public ScaleInLeftAnimator() { 26 | } 27 | 28 | public ScaleInLeftAnimator(Interpolator interpolator) { 29 | mInterpolator = interpolator; 30 | } 31 | 32 | @Override protected void preAnimateRemoveImpl(RecyclerView.ViewHolder holder) { 33 | ViewCompat.setPivotX(holder.itemView, 0); 34 | } 35 | 36 | @Override protected void animateRemoveImpl(final RecyclerView.ViewHolder holder) { 37 | ViewCompat.animate(holder.itemView) 38 | .scaleX(0) 39 | .scaleY(0) 40 | .setDuration(getRemoveDuration()) 41 | .setInterpolator(mInterpolator) 42 | .setListener(new DefaultRemoveVpaListener(holder)) 43 | .setStartDelay(getRemoveDelay(holder)) 44 | .start(); 45 | } 46 | 47 | @Override protected void preAnimateAddImpl(RecyclerView.ViewHolder holder) { 48 | ViewCompat.setPivotX(holder.itemView, 0); 49 | ViewCompat.setScaleX(holder.itemView, 0); 50 | ViewCompat.setScaleY(holder.itemView, 0); 51 | } 52 | 53 | @Override protected void animateAddImpl(final RecyclerView.ViewHolder holder) { 54 | ViewCompat.animate(holder.itemView) 55 | .scaleX(1) 56 | .scaleY(1) 57 | .setDuration(getAddDuration()) 58 | .setInterpolator(mInterpolator) 59 | .setListener(new DefaultAddVpaListener(holder)) 60 | .setStartDelay(getAddDelay(holder)) 61 | .start(); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /mrecyclerview/src/main/java/com/marshon/animators/ScaleInRightAnimator.java: -------------------------------------------------------------------------------- 1 | package com.marshon.animators; 2 | 3 | /** 4 | * Copyright (C) 2015 Wasabeef 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import android.support.v4.view.ViewCompat; 20 | import android.support.v7.widget.RecyclerView; 21 | import android.view.animation.Interpolator; 22 | 23 | public class ScaleInRightAnimator extends BaseItemAnimator { 24 | 25 | public ScaleInRightAnimator() { 26 | } 27 | 28 | public ScaleInRightAnimator(Interpolator interpolator) { 29 | mInterpolator = interpolator; 30 | } 31 | 32 | @Override protected void preAnimateRemoveImpl(RecyclerView.ViewHolder holder) { 33 | ViewCompat.setPivotX(holder.itemView, holder.itemView.getWidth()); 34 | } 35 | 36 | @Override protected void animateRemoveImpl(final RecyclerView.ViewHolder holder) { 37 | ViewCompat.animate(holder.itemView) 38 | .scaleX(0) 39 | .scaleY(0) 40 | .setDuration(getRemoveDuration()) 41 | .setInterpolator(mInterpolator) 42 | .setListener(new DefaultRemoveVpaListener(holder)) 43 | .setStartDelay(getRemoveDelay(holder)) 44 | .start(); 45 | } 46 | 47 | @Override protected void preAnimateAddImpl(RecyclerView.ViewHolder holder) { 48 | ViewCompat.setPivotX(holder.itemView, holder.itemView.getWidth()); 49 | ViewCompat.setScaleX(holder.itemView, 0); 50 | ViewCompat.setScaleY(holder.itemView, 0); 51 | } 52 | 53 | @Override protected void animateAddImpl(final RecyclerView.ViewHolder holder) { 54 | ViewCompat.animate(holder.itemView) 55 | .scaleX(1) 56 | .scaleY(1) 57 | .setDuration(getAddDuration()) 58 | .setInterpolator(mInterpolator) 59 | .setListener(new DefaultAddVpaListener(holder)) 60 | .setStartDelay(getAddDelay(holder)) 61 | .start(); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /mrecyclerview/src/main/java/com/marshon/animators/ScaleInTopAnimator.java: -------------------------------------------------------------------------------- 1 | package com.marshon.animators; 2 | 3 | /** 4 | * Copyright (C) 2015 Wasabeef 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import android.support.v4.view.ViewCompat; 20 | import android.support.v7.widget.RecyclerView; 21 | import android.view.animation.Interpolator; 22 | 23 | public class ScaleInTopAnimator extends BaseItemAnimator { 24 | 25 | public ScaleInTopAnimator() { 26 | } 27 | 28 | public ScaleInTopAnimator(Interpolator interpolator) { 29 | mInterpolator = interpolator; 30 | } 31 | 32 | @Override protected void preAnimateRemoveImpl(RecyclerView.ViewHolder holder) { 33 | // @TODO https://code.google.com/p/android/issues/detail?id=80863 34 | // ViewCompat.setPivotY(holder.itemView, 0); 35 | holder.itemView.setPivotY(0); 36 | } 37 | 38 | @Override protected void animateRemoveImpl(final RecyclerView.ViewHolder holder) { 39 | ViewCompat.animate(holder.itemView) 40 | .scaleX(0) 41 | .scaleY(0) 42 | .setDuration(getRemoveDuration()) 43 | .setInterpolator(mInterpolator) 44 | .setListener(new DefaultRemoveVpaListener(holder)) 45 | .setStartDelay(getRemoveDelay(holder)) 46 | .start(); 47 | } 48 | 49 | @Override protected void preAnimateAddImpl(RecyclerView.ViewHolder holder) { 50 | // @TODO https://code.google.com/p/android/issues/detail?id=80863 51 | // ViewCompat.setPivotY(holder.itemView, 0); 52 | holder.itemView.setPivotY(0); 53 | ViewCompat.setScaleX(holder.itemView, 0); 54 | ViewCompat.setScaleY(holder.itemView, 0); 55 | } 56 | 57 | @Override protected void animateAddImpl(final RecyclerView.ViewHolder holder) { 58 | ViewCompat.animate(holder.itemView) 59 | .scaleX(1) 60 | .scaleY(1) 61 | .setDuration(getAddDuration()) 62 | .setInterpolator(mInterpolator) 63 | .setListener(new DefaultAddVpaListener(holder)) 64 | .setStartDelay(getAddDelay(holder)) 65 | .start(); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /mrecyclerview/src/main/java/com/marshon/animators/SlideInDownAnimator.java: -------------------------------------------------------------------------------- 1 | package com.marshon.animators; 2 | 3 | /** 4 | * Copyright (C) 2015 Wasabeef 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import android.support.v4.view.ViewCompat; 20 | import android.support.v7.widget.RecyclerView; 21 | import android.view.animation.Interpolator; 22 | 23 | public class SlideInDownAnimator extends BaseItemAnimator { 24 | 25 | public SlideInDownAnimator() { 26 | 27 | } 28 | 29 | public SlideInDownAnimator(Interpolator interpolator) { 30 | mInterpolator = interpolator; 31 | } 32 | 33 | @Override protected void animateRemoveImpl(final RecyclerView.ViewHolder holder) { 34 | ViewCompat.animate(holder.itemView) 35 | .translationY(-holder.itemView.getHeight()) 36 | .alpha(0) 37 | .setDuration(getRemoveDuration()) 38 | .setInterpolator(mInterpolator) 39 | .setListener(new DefaultRemoveVpaListener(holder)) 40 | .setStartDelay(getRemoveDelay(holder)) 41 | .start(); 42 | } 43 | 44 | @Override protected void preAnimateAddImpl(RecyclerView.ViewHolder holder) { 45 | ViewCompat.setTranslationY(holder.itemView, -holder.itemView.getHeight()); 46 | ViewCompat.setAlpha(holder.itemView, 0); 47 | } 48 | 49 | @Override protected void animateAddImpl(final RecyclerView.ViewHolder holder) { 50 | ViewCompat.animate(holder.itemView) 51 | .translationY(0) 52 | .alpha(1) 53 | .setDuration(getAddDuration()) 54 | .setInterpolator(mInterpolator) 55 | .setListener(new DefaultAddVpaListener(holder)) 56 | .setStartDelay(getAddDelay(holder)) 57 | .start(); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /mrecyclerview/src/main/java/com/marshon/animators/SlideInLeftAnimator.java: -------------------------------------------------------------------------------- 1 | package com.marshon.animators; 2 | 3 | /** 4 | * Copyright (C) 2015 Wasabeef 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import android.support.v4.view.ViewCompat; 20 | import android.support.v7.widget.RecyclerView; 21 | import android.view.animation.Interpolator; 22 | 23 | public class SlideInLeftAnimator extends BaseItemAnimator { 24 | 25 | public SlideInLeftAnimator() { 26 | 27 | } 28 | 29 | public SlideInLeftAnimator(Interpolator interpolator) { 30 | mInterpolator = interpolator; 31 | } 32 | 33 | @Override protected void animateRemoveImpl(final RecyclerView.ViewHolder holder) { 34 | ViewCompat.animate(holder.itemView) 35 | .translationX(-holder.itemView.getRootView().getWidth()) 36 | .setDuration(getRemoveDuration()) 37 | .setInterpolator(mInterpolator) 38 | .setListener(new DefaultRemoveVpaListener(holder)) 39 | .setStartDelay(getRemoveDelay(holder)) 40 | .start(); 41 | } 42 | 43 | @Override protected void preAnimateAddImpl(RecyclerView.ViewHolder holder) { 44 | ViewCompat.setTranslationX(holder.itemView, -holder.itemView.getRootView().getWidth()); 45 | } 46 | 47 | @Override protected void animateAddImpl(final RecyclerView.ViewHolder holder) { 48 | ViewCompat.animate(holder.itemView) 49 | .translationX(0) 50 | .setDuration(getAddDuration()) 51 | .setInterpolator(mInterpolator) 52 | .setListener(new DefaultAddVpaListener(holder)) 53 | .setStartDelay(getAddDelay(holder)) 54 | .start(); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /mrecyclerview/src/main/java/com/marshon/animators/SlideInRightAnimator.java: -------------------------------------------------------------------------------- 1 | package com.marshon.animators; 2 | 3 | /** 4 | * Copyright (C) 2015 Wasabeef 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import android.support.v4.view.ViewCompat; 20 | import android.support.v7.widget.RecyclerView; 21 | import android.view.animation.Interpolator; 22 | 23 | public class SlideInRightAnimator extends BaseItemAnimator { 24 | 25 | public SlideInRightAnimator() { 26 | 27 | } 28 | 29 | public SlideInRightAnimator(Interpolator interpolator) { 30 | mInterpolator = interpolator; 31 | } 32 | 33 | @Override protected void animateRemoveImpl(final RecyclerView.ViewHolder holder) { 34 | ViewCompat.animate(holder.itemView) 35 | .translationX(holder.itemView.getRootView().getWidth()) 36 | .setDuration(getRemoveDuration()) 37 | .setInterpolator(mInterpolator) 38 | .setListener(new DefaultRemoveVpaListener(holder)) 39 | .setStartDelay(getRemoveDelay(holder)) 40 | .start(); 41 | } 42 | 43 | @Override protected void preAnimateAddImpl(RecyclerView.ViewHolder holder) { 44 | ViewCompat.setTranslationX(holder.itemView, holder.itemView.getRootView().getWidth()); 45 | } 46 | 47 | @Override protected void animateAddImpl(final RecyclerView.ViewHolder holder) { 48 | ViewCompat.animate(holder.itemView) 49 | .translationX(0) 50 | .setDuration(getAddDuration()) 51 | .setInterpolator(mInterpolator) 52 | .setListener(new DefaultAddVpaListener(holder)) 53 | .setStartDelay(getAddDelay(holder)) 54 | .start(); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /mrecyclerview/src/main/java/com/marshon/animators/SlideInUpAnimator.java: -------------------------------------------------------------------------------- 1 | package com.marshon.animators; 2 | 3 | /** 4 | * Copyright (C) 2015 Wasabeef 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import android.support.v4.view.ViewCompat; 20 | import android.support.v7.widget.RecyclerView; 21 | import android.view.animation.Interpolator; 22 | 23 | public class SlideInUpAnimator extends BaseItemAnimator { 24 | 25 | public SlideInUpAnimator() { 26 | 27 | } 28 | 29 | public SlideInUpAnimator(Interpolator interpolator) { 30 | mInterpolator = interpolator; 31 | } 32 | 33 | @Override protected void animateRemoveImpl(final RecyclerView.ViewHolder holder) { 34 | ViewCompat.animate(holder.itemView) 35 | .translationY(holder.itemView.getHeight()) 36 | .alpha(0) 37 | .setDuration(getRemoveDuration()) 38 | .setInterpolator(mInterpolator) 39 | .setListener(new DefaultRemoveVpaListener(holder)) 40 | .setStartDelay(getRemoveDelay(holder)) 41 | .start(); 42 | } 43 | 44 | @Override protected void preAnimateAddImpl(RecyclerView.ViewHolder holder) { 45 | ViewCompat.setTranslationY(holder.itemView, holder.itemView.getHeight()); 46 | ViewCompat.setAlpha(holder.itemView, 0); 47 | } 48 | 49 | @Override protected void animateAddImpl(final RecyclerView.ViewHolder holder) { 50 | ViewCompat.animate(holder.itemView) 51 | .translationY(0) 52 | .alpha(1) 53 | .setDuration(getAddDuration()) 54 | .setInterpolator(mInterpolator) 55 | .setListener(new DefaultAddVpaListener(holder)) 56 | .setStartDelay(getAddDelay(holder)) 57 | .start(); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /mrecyclerview/src/main/java/com/marshon/animators/holder/AnimateViewHolder.java: -------------------------------------------------------------------------------- 1 | package com.marshon.animators.holder; 2 | 3 | import android.support.v4.view.ViewPropertyAnimatorListener; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.view.View; 6 | 7 | public abstract class AnimateViewHolder extends RecyclerView.ViewHolder { 8 | 9 | public AnimateViewHolder(View itemView) { 10 | super(itemView); 11 | } 12 | 13 | public void preAnimateAddImpl() { 14 | } 15 | 16 | public void preAnimateRemoveImpl() { 17 | } 18 | 19 | public abstract void animateAddImpl(ViewPropertyAnimatorListener listener); 20 | 21 | public abstract void animateRemoveImpl(ViewPropertyAnimatorListener listener); 22 | } 23 | -------------------------------------------------------------------------------- /mrecyclerview/src/main/java/com/marshon/internal/ViewHelper.java: -------------------------------------------------------------------------------- 1 | package com.marshon.internal; 2 | 3 | import android.support.v4.view.ViewCompat; 4 | import android.view.View; 5 | 6 | /** 7 | * Copyright (C) 2015 Wasabeef 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | */ 21 | 22 | public final class ViewHelper { 23 | 24 | public static void clear(View v) { 25 | ViewCompat.setAlpha(v, 1); 26 | ViewCompat.setScaleY(v, 1); 27 | ViewCompat.setScaleX(v, 1); 28 | ViewCompat.setTranslationY(v, 0); 29 | ViewCompat.setTranslationX(v, 0); 30 | ViewCompat.setRotation(v, 0); 31 | ViewCompat.setRotationY(v, 0); 32 | ViewCompat.setRotationX(v, 0); 33 | ViewCompat.setPivotY(v, v.getMeasuredHeight() / 2); 34 | ViewCompat.setPivotX(v, v.getMeasuredWidth() / 2); 35 | ViewCompat.animate(v).setInterpolator(null).setStartDelay(0); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /mrecyclerview/src/main/java/com/marshon/mrecyclerview/ArrowRefreshHeader.java: -------------------------------------------------------------------------------- 1 | package com.marshon.mrecyclerview; 2 | 3 | import android.animation.ValueAnimator; 4 | import android.content.Context; 5 | import android.os.Handler; 6 | import android.util.AttributeSet; 7 | import android.view.Gravity; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import android.view.animation.Animation; 12 | import android.view.animation.RotateAnimation; 13 | import android.widget.ImageView; 14 | import android.widget.LinearLayout; 15 | import android.widget.ProgressBar; 16 | import android.widget.TextView; 17 | 18 | import com.marshon.mrecyclerview.R; 19 | 20 | import java.util.Date; 21 | 22 | public class ArrowRefreshHeader extends LinearLayout implements BaseRefreshHeader{ 23 | private LinearLayout mContainer; 24 | private ImageView mArrowImageView; 25 | private SimpleViewSwithcer mProgressBar; 26 | private TextView mStatusTextView; 27 | private int mState = STATE_NORMAL; 28 | private Context mContext; 29 | 30 | private TextView mHeaderTimeView; 31 | 32 | private Animation mRotateUpAnim; 33 | private Animation mRotateDownAnim; 34 | 35 | private final int ROTATE_ANIM_DURATION = 180; 36 | 37 | public int mMeasuredHeight; 38 | private float maxPullHeight = 400; 39 | 40 | public ArrowRefreshHeader(Context context) { 41 | super(context); 42 | initView(context); 43 | } 44 | 45 | /** 46 | * @param context 47 | * @param attrs 48 | */ 49 | public ArrowRefreshHeader(Context context, AttributeSet attrs) { 50 | super(context, attrs); 51 | initView(context); 52 | } 53 | 54 | private void initView(Context context) { 55 | 56 | mContext = context; 57 | // 初始情况,设置下拉刷新view高度为0 58 | mContainer = (LinearLayout) LayoutInflater.from(context).inflate( 59 | R.layout.listview_header, null); 60 | LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); 61 | lp.setMargins(0, 0, 0, 0); 62 | this.setLayoutParams(lp); 63 | this.setPadding(0, 0, 0, 0); 64 | 65 | addView(mContainer, new LayoutParams(LayoutParams.MATCH_PARENT, 0)); 66 | setGravity(Gravity.BOTTOM); 67 | 68 | 69 | mArrowImageView = (ImageView)findViewById(R.id.listview_header_arrow); 70 | mStatusTextView = (TextView)findViewById(R.id.refresh_status_textview); 71 | 72 | //init the progress view 73 | mProgressBar = (SimpleViewSwithcer)findViewById(R.id.listview_header_progressbar); 74 | 75 | 76 | ProgressBar progressBar=new ProgressBar(context, null, android.R.attr.progressBarStyle); 77 | progressBar.setIndeterminate(true); 78 | 79 | mProgressBar.setView(progressBar); 80 | 81 | 82 | mRotateUpAnim = new RotateAnimation(0.0f, -180.0f, 83 | Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 84 | 0.5f); 85 | mRotateUpAnim.setDuration(ROTATE_ANIM_DURATION); 86 | mRotateUpAnim.setFillAfter(true); 87 | mRotateDownAnim = new RotateAnimation(-180.0f, 0.0f, 88 | Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 89 | 0.5f); 90 | mRotateDownAnim.setDuration(ROTATE_ANIM_DURATION); 91 | mRotateDownAnim.setFillAfter(true); 92 | 93 | mHeaderTimeView = (TextView)findViewById(R.id.last_refresh_time); 94 | measure(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT); 95 | mMeasuredHeight = getMeasuredHeight(); 96 | } 97 | 98 | public void setProgressStyle(int style) { 99 | // if(style == ProgressStyle.SysProgress){ 100 | mProgressBar.setView(new ProgressBar(mContext, null, android.R.attr.progressBarStyle)); 101 | // }else{ 102 | // AVLoadingIndicatorView progressView = new AVLoadingIndicatorView(this.getContext()); 103 | // progressView.setIndicatorColor(0xffB5B5B5); 104 | // progressView.setIndicatorId(style); 105 | // mProgressBar.setView(progressView); 106 | // } 107 | } 108 | 109 | public void setArrowImageView(int resid){ 110 | mArrowImageView.setImageResource(resid); 111 | } 112 | 113 | public void setState(int state) { 114 | if (state == mState) return ; 115 | 116 | if (state == STATE_REFRESHING) { // 显示进度 117 | mArrowImageView.clearAnimation(); 118 | mArrowImageView.setVisibility(View.INVISIBLE); 119 | mProgressBar.setVisibility(View.VISIBLE); 120 | } else if(state == STATE_DONE) { 121 | mArrowImageView.setVisibility(View.INVISIBLE); 122 | mProgressBar.setVisibility(View.INVISIBLE); 123 | } else { // 显示箭头图片 124 | mArrowImageView.setVisibility(View.VISIBLE); 125 | mProgressBar.setVisibility(View.INVISIBLE); 126 | } 127 | 128 | switch(state){ 129 | case STATE_NORMAL: 130 | if (mState == STATE_RELEASE_TO_REFRESH) { 131 | mArrowImageView.startAnimation(mRotateDownAnim); 132 | } 133 | if (mState == STATE_REFRESHING) { 134 | mArrowImageView.clearAnimation(); 135 | } 136 | mStatusTextView.setText(R.string.listview_header_hint_normal); 137 | break; 138 | case STATE_RELEASE_TO_REFRESH: 139 | if (mState != STATE_RELEASE_TO_REFRESH) { 140 | mArrowImageView.clearAnimation(); 141 | mArrowImageView.startAnimation(mRotateUpAnim); 142 | mStatusTextView.setText(R.string.listview_header_hint_release); 143 | } 144 | break; 145 | case STATE_REFRESHING: 146 | mStatusTextView.setText(R.string.refreshing); 147 | break; 148 | case STATE_DONE: 149 | mStatusTextView.setText(R.string.refresh_done); 150 | break; 151 | default: 152 | } 153 | 154 | mState = state; 155 | } 156 | 157 | public int getState() { 158 | return mState; 159 | } 160 | 161 | @Override 162 | public void refreshComplate(){ 163 | mHeaderTimeView.setText(friendlyTime(new Date())); 164 | setState(STATE_DONE); 165 | new Handler().postDelayed(new Runnable() { 166 | public void run() { 167 | reset(); 168 | } 169 | }, 200); 170 | } 171 | 172 | public void setVisiableHeight(int height) { 173 | if (height < 0) 174 | height = 0; 175 | if (height>400) 176 | height= (int) (maxPullHeight-0.5f); 177 | 178 | LayoutParams lp = (LayoutParams) mContainer 179 | .getLayoutParams(); 180 | lp.height = height; 181 | 182 | mContainer.setLayoutParams(lp); 183 | 184 | //计算百分比 185 | // float rate = height / maxPullHeight; 186 | // if (scalerIMG!=null){ 187 | // scalerIMG.setScaleY(1.0f+rate); 188 | // scalerIMG.setScaleX(1.0f+rate); 189 | // } 190 | 191 | } 192 | 193 | public int getVisiableHeight() { 194 | int height = 0; 195 | LayoutParams lp = (LayoutParams) mContainer 196 | .getLayoutParams(); 197 | height = lp.height; 198 | return height; 199 | } 200 | 201 | @Override 202 | public void onMove(float delta) { 203 | if(getVisiableHeight() > 0 || delta > 0) { 204 | setVisiableHeight((int) delta + getVisiableHeight()); 205 | if (mState <= STATE_RELEASE_TO_REFRESH) { // 未处于刷新状态,更新箭头 206 | if (getVisiableHeight() > mMeasuredHeight) { 207 | setState(STATE_RELEASE_TO_REFRESH); 208 | }else { 209 | setState(STATE_NORMAL); 210 | } 211 | } 212 | } 213 | } 214 | 215 | @Override 216 | public boolean releaseAction() { 217 | boolean isOnRefresh = false; 218 | int height = getVisiableHeight(); 219 | if (height == 0) // not visible. 220 | isOnRefresh = false; 221 | 222 | if(getVisiableHeight() > mMeasuredHeight && mState < STATE_REFRESHING){ 223 | setState(STATE_REFRESHING); 224 | isOnRefresh = true; 225 | } 226 | // refreshing and header isn't shown fully. do nothing. 227 | if (mState == STATE_REFRESHING && height <= mMeasuredHeight) { 228 | //return; 229 | } 230 | int destHeight = 0; // default: scroll back to dismiss header. 231 | // is refreshing, just scroll back to show all the header. 232 | if (mState == STATE_REFRESHING) { 233 | destHeight = mMeasuredHeight; 234 | } 235 | smoothScrollTo(destHeight); 236 | 237 | return isOnRefresh; 238 | } 239 | 240 | public void reset() { 241 | smoothScrollTo(0); 242 | new Handler().postDelayed(new Runnable() { 243 | public void run() { 244 | setState(STATE_NORMAL); 245 | } 246 | }, 500); 247 | } 248 | 249 | private void smoothScrollTo(int destHeight) { 250 | ValueAnimator animator = ValueAnimator.ofInt(getVisiableHeight(), destHeight); 251 | animator.setDuration(300).start(); 252 | animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 253 | @Override 254 | public void onAnimationUpdate(ValueAnimator animation) 255 | { 256 | setVisiableHeight((int) animation.getAnimatedValue()); 257 | } 258 | }); 259 | animator.start(); 260 | } 261 | 262 | public static String friendlyTime(Date time) { 263 | //获取time距离当前的秒数 264 | int ct = (int)((System.currentTimeMillis() - time.getTime())/1000); 265 | 266 | if(ct == 0) { 267 | return "刚刚"; 268 | } 269 | 270 | if(ct > 0 && ct < 60) { 271 | return ct + "秒前"; 272 | } 273 | 274 | if(ct >= 60 && ct < 3600) { 275 | return Math.max(ct / 60,1) + "分钟前"; 276 | } 277 | if(ct >= 3600 && ct < 86400) 278 | return ct / 3600 + "小时前"; 279 | if(ct >= 86400 && ct < 2592000){ //86400 * 30 280 | int day = ct / 86400 ; 281 | return day + "天前"; 282 | } 283 | if(ct >= 2592000 && ct < 31104000) { //86400 * 30 284 | return ct / 2592000 + "月前"; 285 | } 286 | return ct / 31104000 + "年前"; 287 | } 288 | 289 | } 290 | -------------------------------------------------------------------------------- /mrecyclerview/src/main/java/com/marshon/mrecyclerview/BaseRefreshHeader.java: -------------------------------------------------------------------------------- 1 | package com.marshon.mrecyclerview; 2 | 3 | /** 4 | * Created by jianghejie on 15/11/22. 5 | */ 6 | interface BaseRefreshHeader { 7 | public void onMove(float delta) ; 8 | public boolean releaseAction(); 9 | public void refreshComplate(); 10 | public final static int STATE_NORMAL = 0; 11 | public final static int STATE_RELEASE_TO_REFRESH = 1; 12 | public final static int STATE_REFRESHING = 2; 13 | public final static int STATE_DONE = 3; 14 | } 15 | -------------------------------------------------------------------------------- /mrecyclerview/src/main/java/com/marshon/mrecyclerview/JellyView.java: -------------------------------------------------------------------------------- 1 | package com.marshon.mrecyclerview; 2 | 3 | /** 4 | * Created by jianghejie on 15/11/22. 5 | */ 6 | 7 | import android.annotation.TargetApi; 8 | import android.content.Context; 9 | import android.graphics.Canvas; 10 | import android.graphics.Paint; 11 | import android.graphics.Path; 12 | import android.os.Build; 13 | import android.util.AttributeSet; 14 | import android.util.Log; 15 | import android.view.View; 16 | 17 | 18 | public class JellyView extends View implements BaseRefreshHeader{ 19 | Path path; 20 | 21 | Paint paint; 22 | 23 | private int minimumHeight = 0; 24 | 25 | private int jellyHeight =0; 26 | 27 | public JellyView(Context context) { 28 | super(context); 29 | init(); 30 | } 31 | 32 | public JellyView(Context context, AttributeSet attrs) { 33 | super(context, attrs); 34 | init(); 35 | } 36 | 37 | public JellyView(Context context, AttributeSet attrs, int defStyleAttr) { 38 | super(context, attrs, defStyleAttr); 39 | init(); 40 | } 41 | 42 | @SuppressWarnings("unused") 43 | @TargetApi(Build.VERSION_CODES.LOLLIPOP) 44 | public JellyView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 45 | super(context, attrs, defStyleAttr, defStyleRes); 46 | init(); 47 | } 48 | 49 | private void init() { 50 | if (isInEditMode()) { 51 | return; 52 | } 53 | path = new Path(); 54 | paint = new Paint(); 55 | paint.setColor(getContext().getResources().getColor(android.R.color.holo_blue_bright)); 56 | paint.setAntiAlias(true); 57 | } 58 | 59 | public void setJellyColor(int jellyColor) { 60 | paint.setColor(jellyColor); 61 | } 62 | 63 | @Override 64 | protected void onDraw(Canvas canvas) { 65 | super.onDraw(canvas); 66 | path.reset(); 67 | path.lineTo(0, minimumHeight); 68 | path.quadTo(getMeasuredWidth() / 2, minimumHeight + jellyHeight, getMeasuredWidth(), minimumHeight); 69 | path.lineTo(getMeasuredWidth(), 0); 70 | canvas.drawPath(path, paint); 71 | } 72 | 73 | @Override 74 | public void setMinimumHeight(int minimumHeight) { 75 | this.minimumHeight = minimumHeight; 76 | } 77 | 78 | public void setJellyHeight(int ribbonHeight) { 79 | this.jellyHeight = ribbonHeight; 80 | } 81 | 82 | @Override 83 | public int getMinimumHeight() { 84 | return minimumHeight; 85 | } 86 | 87 | public int getJellyHeight() { 88 | return jellyHeight; 89 | } 90 | 91 | 92 | @Override 93 | public void refreshComplate(){ 94 | 95 | } 96 | 97 | @Override 98 | public void onMove(float delta) { 99 | jellyHeight = jellyHeight + (int)delta; 100 | Log.i("jellyHeight", "delta = " + delta); 101 | this.invalidate(); 102 | } 103 | 104 | @Override 105 | public boolean releaseAction() { 106 | return false; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /mrecyclerview/src/main/java/com/marshon/mrecyclerview/LoadingMoreFooter.java: -------------------------------------------------------------------------------- 1 | package com.marshon.mrecyclerview; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.view.Gravity; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.LinearLayout; 9 | import android.widget.ProgressBar; 10 | import android.widget.TextView; 11 | 12 | import com.marshon.mrecyclerview.R; 13 | 14 | 15 | public class LoadingMoreFooter extends LinearLayout { 16 | 17 | private SimpleViewSwithcer progressCon; 18 | private Context mContext; 19 | public final static int STATE_LOADING = 0; 20 | public final static int STATE_COMPLETE = 1; 21 | public final static int STATE_NOMORE = 2; 22 | private TextView mText; 23 | public LoadingMoreFooter(Context context) { 24 | super(context); 25 | initView(context); 26 | } 27 | 28 | /** 29 | * @param context 30 | * @param attrs 31 | */ 32 | public LoadingMoreFooter(Context context, AttributeSet attrs) { 33 | super(context, attrs); 34 | initView(context); 35 | } 36 | public void initView(Context context ){ 37 | mContext = context; 38 | setGravity(Gravity.CENTER); 39 | setLayoutParams(new ViewGroup.LayoutParams( 40 | ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); 41 | progressCon = new SimpleViewSwithcer(context); 42 | progressCon.setLayoutParams(new ViewGroup.LayoutParams( 43 | ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); 44 | 45 | ProgressBar progressBar=new ProgressBar(context, null, android.R.attr.progressBarStyle); 46 | progressBar.setIndeterminate(true); 47 | progressCon.setView(progressBar); 48 | 49 | addView(progressCon); 50 | mText = new TextView(context); 51 | mText.setText("正在加载..."); 52 | 53 | LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); 54 | layoutParams.setMargins( (int)getResources().getDimension(R.dimen.textandiconmargin),0,0,0 ); 55 | 56 | mText.setLayoutParams(layoutParams); 57 | addView(mText); 58 | } 59 | 60 | public void setProgressStyle(int style) { 61 | // if(style == ProgressStyle.SysProgress){ 62 | progressCon.setView(new ProgressBar(mContext, null, android.R.attr.progressBarStyle)); 63 | // }else{ 64 | // AVLoadingIndicatorView progressView = new AVLoadingIndicatorView(this.getContext()); 65 | // progressView.setIndicatorColor(0xffB5B5B5); 66 | // progressView.setIndicatorId(style); 67 | // progressCon.setView(progressView); 68 | // } 69 | } 70 | 71 | public void setState(int state) { 72 | switch(state) { 73 | case STATE_LOADING: 74 | progressCon.setVisibility(View.VISIBLE); 75 | mText.setText(mContext.getText(R.string.listview_loading)); 76 | this.setVisibility(View.VISIBLE); 77 | break; 78 | case STATE_COMPLETE: 79 | mText.setText(mContext.getText(R.string.listview_loading)); 80 | this.setVisibility(View.GONE); 81 | break; 82 | case STATE_NOMORE: 83 | mText.setText(mContext.getText(R.string.nomore_loading)); 84 | progressCon.setVisibility(View.GONE); 85 | this.setVisibility(View.VISIBLE); 86 | break; 87 | } 88 | 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /mrecyclerview/src/main/java/com/marshon/mrecyclerview/MRecyclerView.java: -------------------------------------------------------------------------------- 1 | package com.marshon.mrecyclerview; 2 | 3 | import android.content.Context; 4 | import android.support.v7.widget.GridLayoutManager; 5 | import android.support.v7.widget.LinearLayoutManager; 6 | import android.support.v7.widget.RecyclerView; 7 | import android.support.v7.widget.StaggeredGridLayoutManager; 8 | import android.util.AttributeSet; 9 | import android.util.Log; 10 | import android.view.MotionEvent; 11 | import android.view.View; 12 | import android.view.ViewGroup; 13 | 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | 17 | public class MRecyclerView extends RecyclerView { 18 | 19 | private Context mContext; 20 | private boolean isLoadingData = false; 21 | private boolean isnomore = false; 22 | private int mRefreshProgressStyle =1; 23 | private int mLoadingMoreProgressStyle = 1; 24 | private ArrayList mHeaderViews = new ArrayList<>(); 25 | private ArrayList mFootViews = new ArrayList<>(); 26 | private Adapter mAdapter; 27 | private Adapter mWrapAdapter; 28 | private float mLastY = -1; 29 | private static final float DRAG_RATE = 3; 30 | private LoadingListener mLoadingListener; 31 | private ArrowRefreshHeader mRefreshHeader; 32 | private boolean pullRefreshEnabled = true; 33 | private boolean loadingMoreEnabled = true; 34 | private static final int TYPE_REFRESH_HEADER = -5; 35 | private static final int TYPE_NORMAL = 0; 36 | private static final int TYPE_FOOTER = -3; 37 | private static final int HEADER_INIT_INDEX = 10000; 38 | private static List sHeaderTypes = new ArrayList<>(); 39 | private int mPageCount = 0; 40 | //adapter没有数据的时候显示,类似于listView的emptyView 41 | private View mEmptyView; 42 | 43 | public MRecyclerView(Context context) { 44 | this(context, null); 45 | } 46 | 47 | public MRecyclerView(Context context, AttributeSet attrs) { 48 | this(context, attrs, 0); 49 | } 50 | 51 | public MRecyclerView(Context context, AttributeSet attrs, int defStyle) { 52 | super(context, attrs, defStyle); 53 | init(context); 54 | } 55 | 56 | private void init(Context context) { 57 | mContext = context; 58 | if (pullRefreshEnabled) { 59 | ArrowRefreshHeader refreshHeader = new ArrowRefreshHeader(mContext); 60 | mHeaderViews.add(0, refreshHeader); 61 | mRefreshHeader = refreshHeader; 62 | mRefreshHeader.setProgressStyle(mRefreshProgressStyle); 63 | } 64 | LoadingMoreFooter footView = new LoadingMoreFooter(mContext); 65 | footView.setProgressStyle(mLoadingMoreProgressStyle); 66 | addFootView(footView); 67 | mFootViews.get(0).setVisibility(GONE); 68 | } 69 | 70 | public void addHeaderView(View view) { 71 | if (pullRefreshEnabled && !(mHeaderViews.get(0) instanceof ArrowRefreshHeader)) { 72 | ArrowRefreshHeader refreshHeader = new ArrowRefreshHeader(mContext); 73 | mHeaderViews.add(0, refreshHeader); 74 | mRefreshHeader = refreshHeader; 75 | mRefreshHeader.setProgressStyle(mRefreshProgressStyle); 76 | } 77 | mHeaderViews.add(view); 78 | sHeaderTypes.add(HEADER_INIT_INDEX + mHeaderViews.size()); 79 | } 80 | 81 | public void addFootView(final View view) { 82 | mFootViews.clear(); 83 | mFootViews.add(view); 84 | } 85 | 86 | public void loadMoreComplete() { 87 | isLoadingData = false; 88 | View footView = mFootViews.get(0); 89 | if (footView instanceof LoadingMoreFooter) { 90 | ((LoadingMoreFooter) footView).setState(LoadingMoreFooter.STATE_COMPLETE); 91 | } else { 92 | footView.setVisibility(View.GONE); 93 | } 94 | 95 | } 96 | 97 | public void setIsnomore(boolean isnomore){ 98 | this.isnomore = isnomore; 99 | View footView = mFootViews.get(0); 100 | ((LoadingMoreFooter) footView).setState(this.isnomore ? LoadingMoreFooter.STATE_NOMORE:LoadingMoreFooter.STATE_COMPLETE); 101 | } 102 | public void reset(){ 103 | setIsnomore(false); 104 | loadMoreComplete(); 105 | refreshComplete(); 106 | } 107 | 108 | public void noMoreLoading() { 109 | isLoadingData = false; 110 | View footView = mFootViews.get(0); 111 | isnomore = true; 112 | if (footView instanceof LoadingMoreFooter) { 113 | ((LoadingMoreFooter) footView).setState(LoadingMoreFooter.STATE_NOMORE); 114 | } else { 115 | footView.setVisibility(View.GONE); 116 | } 117 | } 118 | 119 | public void refreshComplete() { 120 | mRefreshHeader.refreshComplate(); 121 | } 122 | 123 | public void setRefreshHeader(ArrowRefreshHeader refreshHeader) { 124 | mRefreshHeader = refreshHeader; 125 | } 126 | 127 | public void setPullRefreshEnabled(boolean enabled) { 128 | pullRefreshEnabled = enabled; 129 | } 130 | 131 | public void setLoadingMoreEnabled(boolean enabled) { 132 | loadingMoreEnabled = enabled; 133 | if (!enabled) { 134 | if (mFootViews.size() > 0) { 135 | mFootViews.get(0).setVisibility(GONE); 136 | } 137 | } 138 | } 139 | 140 | public void setRefreshProgressStyle(int style) { 141 | mRefreshProgressStyle = style; 142 | if (mRefreshHeader != null) { 143 | mRefreshHeader.setProgressStyle(style); 144 | } 145 | } 146 | 147 | public void setLoadingMoreProgressStyle(int style) { 148 | mLoadingMoreProgressStyle = style; 149 | if (mFootViews.size() > 0 && mFootViews.get(0) instanceof LoadingMoreFooter) { 150 | ((LoadingMoreFooter) mFootViews.get(0)).setProgressStyle(style); 151 | } 152 | } 153 | 154 | public void setArrowImageView(int resid) { 155 | if (mRefreshHeader != null) { 156 | mRefreshHeader.setArrowImageView(resid); 157 | } 158 | } 159 | 160 | public void setEmptyView(View emptyView) { 161 | this.mEmptyView = emptyView; 162 | mDataObserver.onChanged(); 163 | } 164 | 165 | public View getEmptyView() { 166 | return mEmptyView; 167 | } 168 | 169 | @Override 170 | public void setAdapter(Adapter adapter) { 171 | mAdapter = adapter; 172 | mWrapAdapter = new WrapAdapter(mHeaderViews, mFootViews, adapter); 173 | super.setAdapter(mWrapAdapter); 174 | mAdapter.registerAdapterDataObserver(mDataObserver); 175 | mDataObserver.onChanged(); 176 | } 177 | 178 | @Override 179 | public void onScrollStateChanged(int state) { 180 | super.onScrollStateChanged(state); 181 | 182 | if (state == RecyclerView.SCROLL_STATE_IDLE && mLoadingListener != null && !isLoadingData && loadingMoreEnabled) { 183 | LayoutManager layoutManager = getLayoutManager(); 184 | int lastVisibleItemPosition; 185 | if (layoutManager instanceof GridLayoutManager) { 186 | lastVisibleItemPosition = ((GridLayoutManager) layoutManager).findLastVisibleItemPosition(); 187 | } else if (layoutManager instanceof StaggeredGridLayoutManager) { 188 | int[] into = new int[((StaggeredGridLayoutManager) layoutManager).getSpanCount()]; 189 | ((StaggeredGridLayoutManager) layoutManager).findLastVisibleItemPositions(into); 190 | lastVisibleItemPosition = findMax(into); 191 | } else { 192 | lastVisibleItemPosition = ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition(); 193 | } 194 | if (layoutManager.getChildCount() > 0 195 | && lastVisibleItemPosition >= layoutManager.getItemCount() - 1 && layoutManager.getItemCount() > layoutManager.getChildCount() && !isnomore && mRefreshHeader.getState() < ArrowRefreshHeader.STATE_REFRESHING) { 196 | 197 | View footView = mFootViews.get(0); 198 | isLoadingData = true; 199 | if (footView instanceof LoadingMoreFooter) { 200 | ((LoadingMoreFooter) footView).setState(LoadingMoreFooter.STATE_LOADING); 201 | } else { 202 | footView.setVisibility(View.VISIBLE); 203 | } 204 | mLoadingListener.onLoadMore(); 205 | } 206 | } 207 | } 208 | 209 | @Override 210 | public boolean onTouchEvent(MotionEvent ev) { 211 | if (mLastY == -1) { 212 | mLastY = ev.getRawY(); 213 | } 214 | switch (ev.getAction()) { 215 | case MotionEvent.ACTION_DOWN: 216 | mLastY = ev.getRawY(); 217 | break; 218 | case MotionEvent.ACTION_MOVE: 219 | final float deltaY = ev.getRawY() - mLastY; 220 | mLastY = ev.getRawY(); 221 | if (isOnTop() && pullRefreshEnabled) { 222 | mRefreshHeader.onMove(deltaY / DRAG_RATE); 223 | if (mRefreshHeader.getVisiableHeight() > 0 && mRefreshHeader.getState() < ArrowRefreshHeader.STATE_REFRESHING) { 224 | Log.i("getVisiableHeight", "getVisiableHeight = " + mRefreshHeader.getVisiableHeight()); 225 | Log.i("getVisiableHeight", " mRefreshHeader.getState() = " + mRefreshHeader.getState()); 226 | return false; 227 | } 228 | } 229 | break; 230 | default: 231 | mLastY = -1; // reset 232 | if (isOnTop() && pullRefreshEnabled) { 233 | if (mRefreshHeader.releaseAction()) { 234 | if (mLoadingListener != null) { 235 | mLoadingListener.onRefresh(); 236 | } 237 | } 238 | } 239 | break; 240 | } 241 | return super.onTouchEvent(ev); 242 | } 243 | 244 | private int findMax(int[] lastPositions) { 245 | int max = lastPositions[0]; 246 | for (int value : lastPositions) { 247 | if (value > max) { 248 | max = value; 249 | } 250 | } 251 | return max; 252 | } 253 | 254 | private int findMin(int[] firstPositions) { 255 | int min = firstPositions[0]; 256 | for (int value : firstPositions) { 257 | if (value < min) { 258 | min = value; 259 | } 260 | } 261 | return min; 262 | } 263 | 264 | private boolean isOnTop() { 265 | if (mHeaderViews == null || mHeaderViews.isEmpty()) { 266 | return false; 267 | } 268 | 269 | View view = mHeaderViews.get(0); 270 | if (view.getParent() != null) { 271 | return true; 272 | } else { 273 | return false; 274 | } 275 | // LayoutManager layoutManager = getLayoutManager(); 276 | // int firstVisibleItemPosition; 277 | // if (layoutManager instanceof GridLayoutManager) { 278 | // firstVisibleItemPosition = ((GridLayoutManager) layoutManager).findFirstVisibleItemPosition(); 279 | // } else if ( layoutManager instanceof StaggeredGridLayoutManager ) { 280 | // int[] into = new int[((StaggeredGridLayoutManager) layoutManager).getSpanCount()]; 281 | // ((StaggeredGridLayoutManager) layoutManager).findFirstVisibleItemPositions(into); 282 | // firstVisibleItemPosition = findMin(into); 283 | // } else { 284 | // firstVisibleItemPosition = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition(); 285 | // } 286 | // if ( firstVisibleItemPosition <= 1 ) { 287 | // return true; 288 | // } 289 | // return false; 290 | } 291 | 292 | private final RecyclerView.AdapterDataObserver mDataObserver = new RecyclerView.AdapterDataObserver() { 293 | @Override 294 | public void onChanged() { 295 | Adapter adapter = getAdapter(); 296 | if (adapter != null && mEmptyView != null) { 297 | int emptyCount = 0; 298 | if (pullRefreshEnabled) { 299 | emptyCount++; 300 | } 301 | if (loadingMoreEnabled) { 302 | emptyCount++; 303 | } 304 | if (adapter.getItemCount() == emptyCount) { 305 | mEmptyView.setVisibility(View.VISIBLE); 306 | MRecyclerView.this.setVisibility(View.GONE); 307 | } else { 308 | mEmptyView.setVisibility(View.GONE); 309 | MRecyclerView.this.setVisibility(View.VISIBLE); 310 | } 311 | } 312 | if (mWrapAdapter != null) { 313 | mWrapAdapter.notifyDataSetChanged(); 314 | } 315 | } 316 | 317 | @Override 318 | public void onItemRangeInserted(int positionStart, int itemCount) { 319 | mWrapAdapter.notifyItemRangeInserted(positionStart, itemCount); 320 | } 321 | 322 | @Override 323 | public void onItemRangeChanged(int positionStart, int itemCount) { 324 | mWrapAdapter.notifyItemRangeChanged(positionStart, itemCount); 325 | } 326 | 327 | @Override 328 | public void onItemRangeChanged(int positionStart, int itemCount, Object payload) { 329 | mWrapAdapter.notifyItemRangeChanged(positionStart, itemCount, payload); 330 | } 331 | 332 | @Override 333 | public void onItemRangeRemoved(int positionStart, int itemCount) { 334 | mWrapAdapter.notifyItemRangeRemoved(positionStart, itemCount); 335 | } 336 | 337 | @Override 338 | public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) { 339 | mWrapAdapter.notifyItemMoved(fromPosition, toPosition); 340 | } 341 | }; 342 | 343 | private class WrapAdapter extends RecyclerView.Adapter { 344 | 345 | private RecyclerView.Adapter adapter; 346 | 347 | private ArrayList mHeaderViews; 348 | 349 | private ArrayList mFootViews; 350 | 351 | private int headerPosition = 1; 352 | 353 | public WrapAdapter(ArrayList headerViews, ArrayList footViews, RecyclerView.Adapter adapter) { 354 | this.adapter = adapter; 355 | this.mHeaderViews = headerViews; 356 | this.mFootViews = footViews; 357 | } 358 | 359 | @Override 360 | public void onAttachedToRecyclerView(RecyclerView recyclerView) { 361 | super.onAttachedToRecyclerView(recyclerView); 362 | RecyclerView.LayoutManager manager = recyclerView.getLayoutManager(); 363 | if (manager instanceof GridLayoutManager) { 364 | final GridLayoutManager gridManager = ((GridLayoutManager) manager); 365 | gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { 366 | @Override 367 | public int getSpanSize(int position) { 368 | return (isHeader(position) || isFooter(position)) 369 | ? gridManager.getSpanCount() : 1; 370 | } 371 | }); 372 | } 373 | } 374 | 375 | @Override 376 | public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) { 377 | super.onViewAttachedToWindow(holder); 378 | ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams(); 379 | if (lp != null 380 | && lp instanceof StaggeredGridLayoutManager.LayoutParams 381 | && (isHeader(holder.getLayoutPosition()) || isFooter(holder.getLayoutPosition()))) { 382 | StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) lp; 383 | p.setFullSpan(true); 384 | } 385 | } 386 | 387 | public boolean isHeader(int position) { 388 | return position >= 0 && position < mHeaderViews.size(); 389 | } 390 | 391 | public boolean isContentHeader(int position) { 392 | return position >= 1 && position < mHeaderViews.size(); 393 | } 394 | 395 | public boolean isFooter(int position) { 396 | return position < getItemCount() && position >= getItemCount() - mFootViews.size(); 397 | } 398 | 399 | public boolean isRefreshHeader(int position) { 400 | return position == 0; 401 | } 402 | 403 | public int getHeadersCount() { 404 | return mHeaderViews.size(); 405 | } 406 | 407 | public int getFootersCount() { 408 | return mFootViews.size(); 409 | } 410 | 411 | @Override 412 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 413 | if (viewType == TYPE_REFRESH_HEADER) { 414 | mCurrentPosition++; 415 | return new SimpleViewHolder(mHeaderViews.get(0)); 416 | } else if (isContentHeader(mCurrentPosition)) { 417 | if (viewType == sHeaderTypes.get(mCurrentPosition - 1)) { 418 | mCurrentPosition++; 419 | return new SimpleViewHolder(mHeaderViews.get(headerPosition++)); 420 | } 421 | } else if (viewType == TYPE_FOOTER) { 422 | return new SimpleViewHolder(mFootViews.get(0)); 423 | } 424 | return adapter.onCreateViewHolder(parent, viewType); 425 | } 426 | 427 | private int mCurrentPosition; 428 | 429 | @Override 430 | public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { 431 | if (isHeader(position)) { 432 | return; 433 | } 434 | int adjPosition = position - getHeadersCount(); 435 | int adapterCount; 436 | if (adapter != null) { 437 | adapterCount = adapter.getItemCount(); 438 | if (adjPosition < adapterCount) { 439 | adapter.onBindViewHolder(holder, adjPosition); 440 | return; 441 | } 442 | } 443 | } 444 | 445 | @Override 446 | public int getItemCount() { 447 | if (adapter != null) { 448 | return getHeadersCount() + getFootersCount() + adapter.getItemCount(); 449 | } else { 450 | return getHeadersCount() + getFootersCount(); 451 | } 452 | } 453 | 454 | @Override 455 | public int getItemViewType(int position) { 456 | if (isRefreshHeader(position)) { 457 | return TYPE_REFRESH_HEADER; 458 | } 459 | if (isHeader(position)) { 460 | position = position - 1; 461 | return sHeaderTypes.get(position); 462 | } 463 | if (isFooter(position)) { 464 | return TYPE_FOOTER; 465 | } 466 | int adjPosition = position - getHeadersCount(); 467 | int adapterCount; 468 | if (adapter != null) { 469 | adapterCount = adapter.getItemCount(); 470 | if (adjPosition < adapterCount) { 471 | return adapter.getItemViewType(adjPosition); 472 | } 473 | } 474 | return TYPE_NORMAL; 475 | } 476 | 477 | @Override 478 | public long getItemId(int position) { 479 | if (adapter != null && position >= getHeadersCount()) { 480 | int adjPosition = position - getHeadersCount(); 481 | int adapterCount = adapter.getItemCount(); 482 | if (adjPosition < adapterCount) { 483 | return adapter.getItemId(adjPosition); 484 | } 485 | } 486 | return -1; 487 | } 488 | 489 | @Override 490 | public void unregisterAdapterDataObserver(AdapterDataObserver observer) { 491 | if (adapter != null) { 492 | adapter.unregisterAdapterDataObserver(observer); 493 | } 494 | } 495 | 496 | @Override 497 | public void registerAdapterDataObserver(AdapterDataObserver observer) { 498 | if (adapter != null) { 499 | adapter.registerAdapterDataObserver(observer); 500 | } 501 | } 502 | 503 | private class SimpleViewHolder extends RecyclerView.ViewHolder { 504 | public SimpleViewHolder(View itemView) { 505 | super(itemView); 506 | } 507 | } 508 | } 509 | 510 | public void setLoadingListener(LoadingListener listener) { 511 | mLoadingListener = listener; 512 | } 513 | 514 | public interface LoadingListener { 515 | 516 | void onRefresh(); 517 | 518 | void onLoadMore(); 519 | } 520 | 521 | public void setRefreshing(boolean refreshing) { 522 | if (refreshing && pullRefreshEnabled && mLoadingListener != null) { 523 | mRefreshHeader.setState(ArrowRefreshHeader.STATE_REFRESHING); 524 | mRefreshHeader.onMove(mRefreshHeader.getMeasuredHeight()); 525 | mLoadingListener.onRefresh(); 526 | } 527 | } 528 | } 529 | -------------------------------------------------------------------------------- /mrecyclerview/src/main/java/com/marshon/mrecyclerview/SimpleViewSwithcer.java: -------------------------------------------------------------------------------- 1 | package com.marshon.mrecyclerview; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | 8 | /** 9 | * Created by jianghejie on 15/11/22. 10 | */ 11 | public class SimpleViewSwithcer extends ViewGroup { 12 | 13 | public SimpleViewSwithcer(Context context) { 14 | super(context); 15 | 16 | } 17 | 18 | public SimpleViewSwithcer(Context context, AttributeSet attrs) { 19 | this(context, attrs, 0); 20 | } 21 | 22 | public SimpleViewSwithcer(Context context, AttributeSet attrs, int defStyle) { 23 | super(context, attrs, defStyle); 24 | } 25 | 26 | @Override 27 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 28 | int childCount = this.getChildCount(); 29 | int maxHeight = 0; 30 | int maxWidth = 0; 31 | for (int i = 0; i < childCount; i++) { 32 | View child = this.getChildAt(i); 33 | this.measureChild(child, widthMeasureSpec, heightMeasureSpec); 34 | int cw = child.getMeasuredWidth(); 35 | // int ch = child.getMeasuredHeight(); 36 | maxWidth = child.getMeasuredWidth(); 37 | maxHeight = child.getMeasuredHeight(); 38 | } 39 | setMeasuredDimension(maxWidth, maxHeight); 40 | } 41 | 42 | @Override 43 | protected void onLayout(boolean changed, int l, int t, int r, int b) { 44 | 45 | final int count = getChildCount(); 46 | 47 | for (int i = 0; i < count; i++) { 48 | final View child = getChildAt(i); 49 | if (child.getVisibility() != View.GONE) { 50 | child.layout(0, 0, r - l, b - t); 51 | 52 | } 53 | } 54 | } 55 | 56 | public void setView(View view) { 57 | if(this.getChildCount() != 0){ 58 | this.removeViewAt(0); 59 | } 60 | 61 | this.addView(view,0); 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /mrecyclerview/src/main/res/drawable-hdpi/ic_pulltorefresh_arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenchengyin/MRecyclerView/94a913223534b877428a9b7bfd2740686e1a9a79/mrecyclerview/src/main/res/drawable-hdpi/ic_pulltorefresh_arrow.png -------------------------------------------------------------------------------- /mrecyclerview/src/main/res/drawable-hdpi/loading_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenchengyin/MRecyclerView/94a913223534b877428a9b7bfd2740686e1a9a79/mrecyclerview/src/main/res/drawable-hdpi/loading_01.png -------------------------------------------------------------------------------- /mrecyclerview/src/main/res/drawable-hdpi/loading_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenchengyin/MRecyclerView/94a913223534b877428a9b7bfd2740686e1a9a79/mrecyclerview/src/main/res/drawable-hdpi/loading_02.png -------------------------------------------------------------------------------- /mrecyclerview/src/main/res/drawable-hdpi/loading_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenchengyin/MRecyclerView/94a913223534b877428a9b7bfd2740686e1a9a79/mrecyclerview/src/main/res/drawable-hdpi/loading_03.png -------------------------------------------------------------------------------- /mrecyclerview/src/main/res/drawable-hdpi/loading_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenchengyin/MRecyclerView/94a913223534b877428a9b7bfd2740686e1a9a79/mrecyclerview/src/main/res/drawable-hdpi/loading_04.png -------------------------------------------------------------------------------- /mrecyclerview/src/main/res/drawable-hdpi/loading_05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenchengyin/MRecyclerView/94a913223534b877428a9b7bfd2740686e1a9a79/mrecyclerview/src/main/res/drawable-hdpi/loading_05.png -------------------------------------------------------------------------------- /mrecyclerview/src/main/res/drawable-hdpi/loading_06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenchengyin/MRecyclerView/94a913223534b877428a9b7bfd2740686e1a9a79/mrecyclerview/src/main/res/drawable-hdpi/loading_06.png -------------------------------------------------------------------------------- /mrecyclerview/src/main/res/drawable-hdpi/loading_07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenchengyin/MRecyclerView/94a913223534b877428a9b7bfd2740686e1a9a79/mrecyclerview/src/main/res/drawable-hdpi/loading_07.png -------------------------------------------------------------------------------- /mrecyclerview/src/main/res/drawable-hdpi/loading_08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenchengyin/MRecyclerView/94a913223534b877428a9b7bfd2740686e1a9a79/mrecyclerview/src/main/res/drawable-hdpi/loading_08.png -------------------------------------------------------------------------------- /mrecyclerview/src/main/res/drawable-hdpi/loading_09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenchengyin/MRecyclerView/94a913223534b877428a9b7bfd2740686e1a9a79/mrecyclerview/src/main/res/drawable-hdpi/loading_09.png -------------------------------------------------------------------------------- /mrecyclerview/src/main/res/drawable-hdpi/loading_10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenchengyin/MRecyclerView/94a913223534b877428a9b7bfd2740686e1a9a79/mrecyclerview/src/main/res/drawable-hdpi/loading_10.png -------------------------------------------------------------------------------- /mrecyclerview/src/main/res/drawable-hdpi/loading_11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenchengyin/MRecyclerView/94a913223534b877428a9b7bfd2740686e1a9a79/mrecyclerview/src/main/res/drawable-hdpi/loading_11.png -------------------------------------------------------------------------------- /mrecyclerview/src/main/res/drawable-hdpi/loading_12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenchengyin/MRecyclerView/94a913223534b877428a9b7bfd2740686e1a9a79/mrecyclerview/src/main/res/drawable-hdpi/loading_12.png -------------------------------------------------------------------------------- /mrecyclerview/src/main/res/drawable-hdpi/progressbar.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /mrecyclerview/src/main/res/drawable-hdpi/ptrhead.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenchengyin/MRecyclerView/94a913223534b877428a9b7bfd2740686e1a9a79/mrecyclerview/src/main/res/drawable-hdpi/ptrhead.png -------------------------------------------------------------------------------- /mrecyclerview/src/main/res/layout/listview_footer.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 13 | 20 | 21 | -------------------------------------------------------------------------------- /mrecyclerview/src/main/res/layout/listview_header.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 14 | 15 | 23 | 29 | 30 | 36 | 37 | 42 | 43 | 48 | 49 | 54 | 55 | 56 | 57 | 66 | 67 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /mrecyclerview/src/main/res/layout/pull_to_refresh_head.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 13 | 14 | 21 | 22 | 28 | 29 | 30 | 31 | 38 | 45 | 46 | 47 | 48 | 54 | 55 | 61 | 62 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /mrecyclerview/src/main/res/layout/swipe.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 19 | -------------------------------------------------------------------------------- /mrecyclerview/src/main/res/values-zh/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 下拉刷新 3 | 释放立即刷新 4 | 正在加载... 5 | 没有了 6 | 正在刷新... 7 | 刷新完成 8 | 上次更新时间: 9 | 10 | -------------------------------------------------------------------------------- /mrecyclerview/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /mrecyclerview/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10dp 4 | 5 | -------------------------------------------------------------------------------- /proguard-project.txt: -------------------------------------------------------------------------------- 1 | # To enable ProGuard in your project, edit project.properties 2 | # to define the proguard.config property as described in that file. 3 | # 4 | # Add project specific ProGuard rules here. 5 | # By default, the flags in this file are appended to flags specified 6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt 7 | # You can edit the include path and order by changing the ProGuard 8 | # include property in project.properties. 9 | # 10 | # For more details, see 11 | # http://developer.android.com/guide/developing/tools/proguard.html 12 | 13 | # Add any project specific keep options here: 14 | 15 | # If your project uses WebView with JS, uncomment the following 16 | # and specify the fully qualified class name to the JavaScript interface 17 | # class: 18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 19 | # public *; 20 | #} 21 | -------------------------------------------------------------------------------- /sample/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /sample/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion "23.0.3" 6 | 7 | defaultConfig { 8 | applicationId "com.demotest.testapp" 9 | minSdkVersion 14 10 | targetSdkVersion 23 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | compile 'com.android.support:appcompat-v7:23.1.0' 25 | compile project(':mrecyclerview') 26 | // compile 'com.daimajia.swipelayout:library:1.2.0@aar' 27 | } 28 | -------------------------------------------------------------------------------- /sample/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\SDK/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /sample/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /sample/src/main/java/com/demotest/testapp/ChooseAnimatorsAdapter.java: -------------------------------------------------------------------------------- 1 | package com.demotest.testapp; 2 | 3 | import android.animation.Animator; 4 | import android.animation.ObjectAnimator; 5 | import android.animation.PropertyValuesHolder; 6 | import android.support.v7.widget.RecyclerView; 7 | import android.view.View; 8 | 9 | import com.marshon.adapters.AnimationAdapter; 10 | 11 | 12 | /** 13 | * //自定义动画管理类 14 | * Created by Administrator on 2016/4/25. 15 | */ 16 | public class ChooseAnimatorsAdapter extends AnimationAdapter { 17 | 18 | public static final int ANIMATORFLAG_ALPHA = 1; 19 | public static final int ANIMATORFLAG_TRANSLATION = 3; 20 | public static final int ANIMATORFLAG_SCALE = 2; 21 | 22 | private PropertyValuesHolder[] animators; 23 | private int flag = 2; 24 | 25 | 26 | public ChooseAnimatorsAdapter(RecyclerView.Adapter adapter) { 27 | super(adapter); 28 | } 29 | 30 | @Override 31 | protected Animator[] getAnimators(View view) { 32 | if (animators != null) { 33 | ObjectAnimator valueAnimator = ObjectAnimator.ofPropertyValuesHolder(view,animators); 34 | return new Animator[]{valueAnimator}; 35 | } else { 36 | return makeAnimator(view); 37 | 38 | } 39 | } 40 | 41 | private Animator[] makeAnimator(final View view) { 42 | switch (flag) { 43 | case 1: 44 | return new Animator[]{ObjectAnimator.ofFloat(view, "alpha", 0.1f, 1f)}; 45 | case 2: 46 | return new Animator[] { ObjectAnimator.ofFloat(view, "alpha", 0.1f, 1f),ObjectAnimator.ofFloat(view, "scaleX", 0.1f, 1f),ObjectAnimator.ofFloat(view, "scaleY", 0.1f, 1f) }; 47 | // .... 48 | case 3: 49 | return new Animator[] {ObjectAnimator.ofFloat(view, "translationY", view.getMeasuredHeight(), 0) }; 50 | case 4: 51 | return new Animator[] {ObjectAnimator.ofFloat(view, "translationX", view.getRootView().getWidth(), 0) }; 52 | 53 | } 54 | return null; 55 | } 56 | 57 | 58 | public void setAnimator(PropertyValuesHolder[] animators) { 59 | this.animators = animators; 60 | } 61 | 62 | public void setAnimatorFlag(int flag) { 63 | this.flag = flag; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /sample/src/main/java/com/demotest/testapp/MarshonRecyclerViewActivity.java: -------------------------------------------------------------------------------- 1 | package com.demotest.testapp; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.support.v7.widget.LinearLayoutManager; 7 | import android.support.v7.widget.RecyclerView; 8 | import android.view.View; 9 | 10 | import com.demotest.testapp.adapter.MarshonRecyclerAdapter; 11 | import com.marshon.mrecyclerview.MRecyclerView; 12 | import com.marshon.swipe.SwipeWraper; 13 | 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | 17 | 18 | 19 | /** 20 | * Created by Administrator on 2016/4/25. 21 | */ 22 | public class MarshonRecyclerViewActivity extends AppCompatActivity { 23 | private ChooseAnimatorsAdapter animAdapter; 24 | private List datas; 25 | private MRecyclerView mRecyclerView; 26 | 27 | @Override 28 | protected void onCreate(@Nullable Bundle savedInstanceState) { 29 | super.onCreate(savedInstanceState); 30 | setContentView(R.layout.activity_marsreview); 31 | mRecyclerView = (MRecyclerView) findViewById(R.id.mRecyclerView); 32 | mRecyclerView.setPullRefreshEnabled(true); 33 | mRecyclerView.setLoadingMoreEnabled(true); 34 | mRecyclerView.setLayoutManager(new LinearLayoutManager(this)); 35 | 36 | //1.make full data test 37 | datas = makeDatas(); 38 | MarshonRecyclerAdapter adapter= new MarshonRecyclerAdapter(this,R.layout.listitem, datas) { 39 | @Override 40 | public void convert(final RecyclerView.ViewHolder holder, final int position) { 41 | View deleteView = holder.itemView.findViewById(R.id.tv_delete); 42 | final SwipeWraper swipelayout = (SwipeWraper) holder.itemView.findViewById(R.id.swipelayout); 43 | deleteView.setOnClickListener(new View.OnClickListener() { 44 | @Override 45 | public void onClick(View v) { 46 | swipelayout.close(true); 47 | datas.remove(holder.getLayoutPosition()-1); 48 | animAdapter.notifyItemRemoved(holder.getLayoutPosition()); 49 | } 50 | }); 51 | } 52 | }; 53 | 54 | //2.set up recyclerview 55 | final LinearLayoutManager manager=new LinearLayoutManager(this); 56 | //3.给adapter装饰上animAdapter 57 | animAdapter =new ChooseAnimatorsAdapter(adapter); 58 | animAdapter.setAnimatorFlag(ChooseAnimatorsAdapter.ANIMATORFLAG_SCALE); 59 | mRecyclerView.setAdapter(animAdapter); 60 | mRecyclerView.setLayoutManager(manager); 61 | mRecyclerView.setLoadingListener(new MRecyclerView.LoadingListener() { 62 | @Override 63 | public void onRefresh() { 64 | 65 | } 66 | 67 | @Override 68 | public void onLoadMore() { 69 | mRecyclerView.postDelayed(new Runnable() { 70 | @Override 71 | public void run() { 72 | for(int i=0;i<15;i++){ 73 | datas.add(""); 74 | } 75 | animAdapter.notifyDataSetChanged(); 76 | } 77 | },3000); 78 | } 79 | }); 80 | } 81 | 82 | 83 | protected List makeDatas() { 84 | List datas = new ArrayList(); 85 | for(int i=0;i<400;i++){ 86 | datas.add(""+i); 87 | } 88 | return datas; 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /sample/src/main/java/com/demotest/testapp/adapter/MarshonRecyclerAdapter.java: -------------------------------------------------------------------------------- 1 | package com.demotest.testapp.adapter; 2 | 3 | import android.content.Context; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * Created by Marshon.Chen on 2016/7/26. 12 | * DESC: 13 | */ 14 | public abstract class MarshonRecyclerAdapter extends RecyclerView.Adapter { 15 | 16 | private int listitem; 17 | private List mDatas; 18 | private Context mContext; 19 | 20 | public MarshonRecyclerAdapter(Context context, int listitem, List mDatas){ 21 | this.mContext=context; 22 | this.mDatas=mDatas; 23 | this.listitem=listitem; 24 | } 25 | @Override 26 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 27 | 28 | View itemView=View.inflate(mContext, listitem,null); 29 | return new MViewHolder(itemView); 30 | } 31 | 32 | @Override 33 | public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) { 34 | convert(holder,position); 35 | } 36 | 37 | public abstract void convert(RecyclerView.ViewHolder holder, final int position); 38 | 39 | @Override 40 | public int getItemCount() { 41 | return mDatas.size(); 42 | } 43 | 44 | 45 | class MViewHolder extends RecyclerView.ViewHolder{ 46 | 47 | public MViewHolder(View itemView) { 48 | super(itemView); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /sample/src/main/res/drawable/beauty.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenchengyin/MRecyclerView/94a913223534b877428a9b7bfd2740686e1a9a79/sample/src/main/res/drawable/beauty.jpg -------------------------------------------------------------------------------- /sample/src/main/res/drawable/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenchengyin/MRecyclerView/94a913223534b877428a9b7bfd2740686e1a9a79/sample/src/main/res/drawable/ic_launcher.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable/meinv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenchengyin/MRecyclerView/94a913223534b877428a9b7bfd2740686e1a9a79/sample/src/main/res/drawable/meinv.png -------------------------------------------------------------------------------- /sample/src/main/res/layout/activity_marsreview.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 17 | 18 | 19 | 20 | 23 | 27 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/listitem.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 15 | 25 | 26 | 27 | 28 | 29 | 30 | 35 | 36 | -------------------------------------------------------------------------------- /sample/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /sample/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Marshon 4 | -------------------------------------------------------------------------------- /sample/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':sample' 2 | include ':mrecyclerview' 3 | --------------------------------------------------------------------------------