diff --git a/build.gradle b/build.gradle index da1935f..7955a29 100644 --- a/build.gradle +++ b/build.gradle @@ -2,18 +2,28 @@ buildscript { repositories { - jcenter() + google() + maven { + url "https://jitpack.io" + } } dependencies { - classpath 'com.android.tools.build:gradle:1.1.0' classpath 'com.github.dcendents:android-maven-plugin:1.2' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } } +plugins { + id 'com.android.application' version '7.2.1' apply false + id 'com.android.library' version '7.2.1' apply false +} + allprojects { repositories { - jcenter() + google() + maven { + url "https://jitpack.io" + } } -} +} \ No newline at end of file diff --git a/example/build.gradle b/example/build.gradle index ce08e1c..53279ff 100644 --- a/example/build.gradle +++ b/example/build.gradle @@ -1,14 +1,15 @@ -apply plugin: 'com.android.application' +plugins { + id 'com.android.application' +} android { - compileSdkVersion 22 - buildToolsVersion "22.0.1" + compileSdk 32 defaultConfig { applicationId "com.poliveira.apps.parallaxrecycleradapter" - minSdkVersion 7 - targetSdkVersion 22 - versionCode 1 + minSdkVersion 14 + targetSdkVersion 32 + versionCode 2 versionName "1.0" } buildTypes { @@ -20,7 +21,8 @@ android { } dependencies { - compile fileTree(dir: 'libs', include: ['*.jar']) - compile project (':library') - compile 'com.android.support:cardview-v7:22.2.1' + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation project(path: ':library') + implementation 'androidx.recyclerview:recyclerview:1.2.1' + implementation "androidx.cardview:cardview:1.0.0" } diff --git a/example/src/main/AndroidManifest.xml b/example/src/main/AndroidManifest.xml index e4f0e95..51fb2f1 100644 --- a/example/src/main/AndroidManifest.xml +++ b/example/src/main/AndroidManifest.xml @@ -6,7 +6,7 @@ android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:theme="@style/AppTheme"> - + diff --git a/example/src/main/java/com/poliveira/apps/parallaxrecycleradapter/MainActivity.java b/example/src/main/java/com/poliveira/apps/parallaxrecycleradapter/MainActivity.java index b02ac45..02d42aa 100644 --- a/example/src/main/java/com/poliveira/apps/parallaxrecycleradapter/MainActivity.java +++ b/example/src/main/java/com/poliveira/apps/parallaxrecycleradapter/MainActivity.java @@ -2,8 +2,6 @@ import android.app.Activity; import android.os.Bundle; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; import android.view.Menu; import android.view.MenuItem; import android.view.View; @@ -11,6 +9,10 @@ import android.widget.TextView; import android.widget.Toast; +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + import com.poliveira.parallaxrecyclerview.HeaderLayoutManagerFixed; import com.poliveira.parallaxrecyclerview.ParallaxRecyclerAdapter; @@ -22,12 +24,11 @@ public class MainActivity extends Activity { private boolean isNormalAdapter = false; private RecyclerView mRecyclerView; - @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); - mRecyclerView = (RecyclerView) findViewById(R.id.recycler); + mRecyclerView = (RecyclerView) findViewById(R.id.recyclerX); createAdapter(mRecyclerView); } @@ -56,7 +57,7 @@ private void createCardAdapter(RecyclerView recyclerView) { final ParallaxRecyclerAdapter adapter = new ParallaxRecyclerAdapter(content) { @Override - public void onBindViewHolderImpl(RecyclerView.ViewHolder viewHolder, ParallaxRecyclerAdapter adapter, int i) { + public void onBindViewHolderImpl(RecyclerView.ViewHolder viewHolder, @NonNull ParallaxRecyclerAdapter adapter, int i) { ((ViewHolder) viewHolder).textView.setText(adapter.getData().get(i)); } @@ -71,12 +72,8 @@ public int getItemCountImpl(ParallaxRecyclerAdapter adapter) { } }; - adapter.setOnClickEvent(new ParallaxRecyclerAdapter.OnClickEvent() { - @Override - public void onClick(View v, int position) { - Toast.makeText(MainActivity.this, "You clicked '" + position + "'", Toast.LENGTH_SHORT).show(); - } - }); + adapter.setOnClickEvent((v, position) -> + Toast.makeText(MainActivity.this, "You clicked '" + position + "'", Toast.LENGTH_SHORT).show()); HeaderLayoutManagerFixed layoutManagerFixed = new HeaderLayoutManagerFixed(this); recyclerView.setLayoutManager(layoutManagerFixed); @@ -96,7 +93,7 @@ private void createAdapter(RecyclerView recyclerView) { final ParallaxRecyclerAdapter adapter = new ParallaxRecyclerAdapter(content) { @Override - public void onBindViewHolderImpl(RecyclerView.ViewHolder viewHolder, ParallaxRecyclerAdapter adapter, int i) { + public void onBindViewHolderImpl(RecyclerView.ViewHolder viewHolder, @NonNull ParallaxRecyclerAdapter adapter, int i) { ((ViewHolder) viewHolder).textView.setText(adapter.getData().get(i)); } @@ -111,12 +108,8 @@ public int getItemCountImpl(ParallaxRecyclerAdapter adapter) { } }; - adapter.setOnClickEvent(new ParallaxRecyclerAdapter.OnClickEvent() { - @Override - public void onClick(View v, int position) { - Toast.makeText(MainActivity.this, "You clicked '" + position + "'", Toast.LENGTH_SHORT).show(); - } - }); + adapter.setOnClickEvent((v, position) -> + Toast.makeText(MainActivity.this, "You clicked '" + position + "'", Toast.LENGTH_SHORT).show()); recyclerView.setLayoutManager(new LinearLayoutManager(this)); View header = getLayoutInflater().inflate(R.layout.header, recyclerView, false); @@ -125,7 +118,6 @@ public void onClick(View v, int position) { recyclerView.setAdapter(adapter); } - static class ViewHolder extends RecyclerView.ViewHolder { public TextView textView; @@ -134,4 +126,4 @@ public ViewHolder(View itemView) { textView = (TextView) itemView.findViewById(R.id.textView); } } -} +} \ No newline at end of file diff --git a/example/src/main/res/layout/activity_main.xml b/example/src/main/res/layout/activity_main.xml index 8081284..19e40d8 100644 --- a/example/src/main/res/layout/activity_main.xml +++ b/example/src/main/res/layout/activity_main.xml @@ -1,12 +1,13 @@ - + android:id="@+id/recyclerX" + android:layout_gravity="left|top" + tools:ignore="RtlHardcoded" /> \ No newline at end of file diff --git a/example/src/main/res/layout/row_recyclerview_cards.xml b/example/src/main/res/layout/row_recyclerview_cards.xml index fc66f27..b1d5cf8 100644 --- a/example/src/main/res/layout/row_recyclerview_cards.xml +++ b/example/src/main/res/layout/row_recyclerview_cards.xml @@ -3,7 +3,7 @@ android:layout_width="match_parent" android:layout_height="250dp"> - - - + \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 1d3591c..dab7c28 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,18 +1,21 @@ # Project-wide Gradle settings. - # IDE (e.g. Android Studio) users: # Gradle settings configured through the IDE *will override* # any settings specified in this file. - # For more details on how to configure your build environment visit # http://www.gradle.org/docs/current/userguide/build_environment.html - # Specifies the JVM arguments used for the daemon process. # The setting is particularly useful for tweaking memory settings. -# Default value: -Xmx10248m -XX:MaxPermSize=256m -# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 - +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects -# org.gradle.parallel=true \ No newline at end of file +# org.gradle.parallel=true +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app"s APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true +# Enables namespacing of each library's R class so that its R class includes only the +# resources declared in the library itself and none from the library's dependencies, +# thereby reducing the size of the R class for that library +android.nonTransitiveRClass=true \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 8c0fb64..e708b1c 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 0c71e76..55936d6 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Wed Apr 10 15:27:10 PDT 2013 +#Sat Jun 04 12:44:44 CST 2022 distributionBase=GRADLE_USER_HOME +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip +zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 91a7e26..4f906e0 100644 --- a/gradlew +++ b/gradlew @@ -1,4 +1,20 @@ -#!/usr/bin/env bash +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ############################################################################## ## @@ -6,20 +22,38 @@ ## ############################################################################## -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" -warn ( ) { +warn () { echo "$*" } -die ( ) { +die () { echo echo "$*" echo @@ -30,6 +64,7 @@ die ( ) { cygwin=false msys=false darwin=false +nonstop=false case "`uname`" in CYGWIN* ) cygwin=true @@ -40,33 +75,14 @@ case "`uname`" in MINGW* ) msys=true ;; + NONSTOP* ) + nonstop=true + ;; esac -# For Cygwin, ensure paths are in UNIX format before anything is touched. -if $cygwin ; then - [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` -fi - -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >&- -APP_HOME="`pwd -P`" -cd "$SAVED" >&- - CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then @@ -90,7 +106,7 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then MAX_FD_LIMIT=`ulimit -H -n` if [ $? -eq 0 ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then @@ -110,11 +126,13 @@ if $darwin; then GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" fi -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + # We build the pattern for arguments to be converted via cygpath ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` SEP="" @@ -138,27 +156,30 @@ if $cygwin ; then else eval `echo args$i`="\"$arg\"" fi - i=$((i+1)) + i=`expr $i + 1` done case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; esac fi -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " } -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index 8a0b282..107acd3 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,3 +1,19 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + @if "%DEBUG%" == "" @echo off @rem ########################################################################## @rem @@ -8,20 +24,23 @@ @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - set DIRNAME=%~dp0 if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if "%ERRORLEVEL%" == "0" goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -35,7 +54,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -45,34 +64,14 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windowz variants - -if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ - :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell diff --git a/library/build.gradle b/library/build.gradle index 582a179..3b6382f 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -1,15 +1,13 @@ apply plugin: 'com.android.library' -apply plugin: 'android-maven' android { - compileSdkVersion 22 - buildToolsVersion "22.0.1" + compileSdk 32 defaultConfig { - minSdkVersion 7 - targetSdkVersion 22 + minSdkVersion 14 + targetSdkVersion 32 versionCode 3 - versionName "1.2" + versionName "1.3" } buildTypes { release { @@ -17,9 +15,13 @@ android { proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } } dependencies { - compile fileTree(dir: 'libs', include: ['*.jar']) - compile 'com.android.support:recyclerview-v7:22.2.1' + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation 'androidx.recyclerview:recyclerview:1.2.1' } \ No newline at end of file diff --git a/library/src/main/java/com/poliveira/parallaxrecyclerview/HeaderLayoutManagerFixed.java b/library/src/main/java/com/poliveira/parallaxrecyclerview/HeaderLayoutManagerFixed.java index 4ac2da4..b6cfa97 100644 --- a/library/src/main/java/com/poliveira/parallaxrecyclerview/HeaderLayoutManagerFixed.java +++ b/library/src/main/java/com/poliveira/parallaxrecyclerview/HeaderLayoutManagerFixed.java @@ -5,19 +5,23 @@ import android.os.Build; import android.os.Parcel; import android.os.Parcelable; -import android.support.v4.view.ViewCompat; -import android.support.v7.widget.LinearSmoothScroller; -import android.support.v7.widget.RecyclerView; import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.widget.LinearLayout; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.core.view.ViewCompat; +import androidx.recyclerview.widget.LinearSmoothScroller; +import androidx.recyclerview.widget.RecyclerView; + import java.util.List; +import java.util.Objects; /** - * A {@link android.support.v7.widget.RecyclerView.LayoutManager} implementation which provides + * A {@link androidx.recyclerview.widget.RecyclerView.LayoutManager} implementation which provides * similar functionality to {@link android.widget.ListView}. */ public class HeaderLayoutManagerFixed extends RecyclerView.LayoutManager { @@ -224,7 +228,7 @@ public int getOrientation() { } /** - * Sets the orientation of the layout. {@link android.support.v7.widget.LinearLayoutManager} + * Sets the orientation of the layout. {@link androidx.recyclerview.widget.LinearLayoutManager} * will do its best to keep scroll position. * * @param orientation {@link #HORIZONTAL} or {@link #VERTICAL} @@ -275,8 +279,8 @@ public boolean getReverseLayout() { * rendered at the end of the UI, second item is render before it etc. *

* For horizontal layouts, it depends on the layout direction. - * When set to true, If {@link android.support.v7.widget.RecyclerView} is LTR, than it will - * render from RTL, if {@link android.support.v7.widget.RecyclerView}} is RTL, it will render + * When set to true, If {@link RecyclerView} is LTR, than it will + * render from RTL, if {@link RecyclerView}} is RTL, it will render * from LTR. *

* If you are looking for the exact same behavior of @@ -304,7 +308,7 @@ public View findViewByPosition(int position) { if (childCount == 0) { return null; } - final int firstChild = getPosition(getChildAt(0)); + final int firstChild = getPosition(Objects.requireNonNull(getChildAt(0))); final int viewPosition = position - firstChild; if (viewPosition >= 0 && viewPosition < childCount) { return getChildAt(viewPosition); @@ -314,7 +318,7 @@ public View findViewByPosition(int position) { /** *

Returns the amount of extra space that should be rendered by LinearLayoutManager. - * By default, {@link android.support.v7.widget.LinearLayoutManager} lays out 1 extra page of + * By default, {@link androidx.recyclerview.widget.LinearLayoutManager} lays out 1 extra page of * items while smooth scrolling and 0 otherwise. You can override this method to implement your * custom layout pre-cache logic.

*

Laying out invisible elements will eventually come with performance cost. On the other @@ -324,7 +328,7 @@ public View findViewByPosition(int position) { * * @return The extra space that should be laid out (in pixels). */ - protected int getExtraLayoutSpace(RecyclerView.State state) { + protected int getExtraLayoutSpace(@NonNull RecyclerView.State state) { if (state.hasTargetScrollPosition()) { return mOrientationHelper.getTotalSpace(); } else { @@ -333,7 +337,7 @@ protected int getExtraLayoutSpace(RecyclerView.State state) { } @Override - public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, + public void smoothScrollToPosition(@NonNull RecyclerView recyclerView, RecyclerView.State state, int position) { LinearSmoothScroller linearSmoothScroller = new LinearSmoothScroller(recyclerView.getContext()) { @@ -351,7 +355,7 @@ public PointF computeScrollVectorForPosition(int targetPosition) { if (getChildCount() == 0) { return null; } - final int firstChildPos = getPosition(getChildAt(0)); + final int firstChildPos = getPosition(Objects.requireNonNull(getChildAt(0))); final int direction = targetPosition < firstChildPos != mShouldReverseLayout ? -1 : 1; if (mOrientation == HORIZONTAL) { return new PointF(direction, 0); @@ -444,7 +448,7 @@ public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State } else { // item is not visible. if (getChildCount() > 0) { // get position of any child, does not matter - int pos = getPosition(getChildAt(0)); + int pos = getPosition(Objects.requireNonNull(getChildAt(0))); if (mPendingScrollPosition < pos == mShouldReverseLayout) { anchorCoordinate = mOrientationHelper.getEndAfterPadding(); layoutFromEnd = true; @@ -544,10 +548,10 @@ public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State int scrapExtraStart = 0, scrapExtraEnd = 0; final List scrapList = recycler.getScrapList(); final int scrapSize = scrapList.size(); - final int firstChildPos = getPosition(getChildAt(0)); + final int firstChildPos = getPosition(Objects.requireNonNull(getChildAt(0))); for (int i = 0; i < scrapSize; i++) { RecyclerView.ViewHolder scrap = scrapList.get(i); - final int position = scrap.getPosition(); + final int position = scrap.getBindingAdapterPosition(); final int direction = position < firstChildPos != mShouldReverseLayout ? RenderState.LAYOUT_START : RenderState.LAYOUT_END; if (direction == RenderState.LAYOUT_START) { @@ -599,7 +603,7 @@ public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State private int fixLayoutEndGap(int endOffset, RecyclerView.Recycler recycler, RecyclerView.State state, boolean canOffsetChildren) { int gap = mOrientationHelper.getEndAfterPadding() - endOffset; - int fixOffset = 0; + int fixOffset; if (gap > 0) { fixOffset = -scrollBy(-gap, recycler, state); } else { @@ -624,7 +628,7 @@ private int fixLayoutEndGap(int endOffset, RecyclerView.Recycler recycler, private int fixLayoutStartGap(int startOffset, RecyclerView.Recycler recycler, RecyclerView.State state, boolean canOffsetChildren) { int gap = startOffset - mOrientationHelper.getStartAfterPadding(); - int fixOffset = 0; + int fixOffset; if (gap > 0) { // check if we should fix this gap. fixOffset = -scrollBy(gap, recycler, state); @@ -746,7 +750,7 @@ public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, } @Override - public int computeHorizontalScrollOffset(RecyclerView.State state) { + public int computeHorizontalScrollOffset(@NonNull RecyclerView.State state) { if (getChildCount() == 0) { return 0; } @@ -755,7 +759,7 @@ public int computeHorizontalScrollOffset(RecyclerView.State state) { } @Override - public int computeVerticalScrollOffset(RecyclerView.State state) { + public int computeVerticalScrollOffset(@NonNull RecyclerView.State state) { if (getChildCount() == 0) { return 0; } @@ -764,22 +768,22 @@ public int computeVerticalScrollOffset(RecyclerView.State state) { } @Override - public int computeHorizontalScrollExtent(RecyclerView.State state) { + public int computeHorizontalScrollExtent(@NonNull RecyclerView.State state) { return getChildCount(); } @Override - public int computeVerticalScrollExtent(RecyclerView.State state) { + public int computeVerticalScrollExtent(@NonNull RecyclerView.State state) { return getChildCount(); } @Override - public int computeHorizontalScrollRange(RecyclerView.State state) { + public int computeHorizontalScrollRange(@NonNull RecyclerView.State state) { return state.getItemCount(); } @Override - public int computeVerticalScrollRange(RecyclerView.State state) { + public int computeVerticalScrollRange(@NonNull RecyclerView.State state) { return state.getItemCount(); } @@ -867,7 +871,7 @@ private void recycleChildren(RecyclerView.Recycler recycler, int startIndex, int /** * Recycles views that went out of bounds after scrolling towards the end of the layout. * - * @param recycler Recycler instance of {@link android.support.v7.widget.RecyclerView} + * @param recycler Recycler instance of {@link RecyclerView} * @param dt This can be used to add additional padding to the visible area. This is used * to * detect children that will go out of bounds after scrolling, without actually @@ -906,7 +910,7 @@ private void recycleViewsFromStart(RecyclerView.Recycler recycler, int dt) { /** * Recycles views that went out of bounds after scrolling towards the start of the layout. * - * @param recycler Recycler instance of {@link android.support.v7.widget.RecyclerView} + * @param recycler Recycler instance of {@link RecyclerView} * @param dt This can be used to add additional padding to the visible area. This is used * to detect children that will go out of bounds after scrolling, without * actually moving them. @@ -949,10 +953,10 @@ private void recycleViewsFromEnd(RecyclerView.Recycler recycler, int dt) { * @param renderState Current render state. Right now, this object does not change but * we may consider moving it out of this view so passing around as a * parameter for now, rather than accessing {@link #mRenderState} - * @see #recycleViewsFromStart(android.support.v7.widget.RecyclerView.Recycler, int) - * @see #recycleViewsFromEnd(android.support.v7.widget.RecyclerView.Recycler, int) + * @see #recycleViewsFromStart(RecyclerView.Recycler, int) + * @see #recycleViewsFromEnd(RecyclerView.Recycler, int) */ - private void recycleByRenderState(RecyclerView.Recycler recycler, RenderState renderState) { + private void recycleByRenderState(RecyclerView.Recycler recycler, @NonNull RenderState renderState) { if (renderState.mLayoutDirection == RenderState.LAYOUT_START) { recycleViewsFromEnd(recycler, renderState.mScrollingOffset); } else { @@ -962,7 +966,7 @@ private void recycleByRenderState(RecyclerView.Recycler recycler, RenderState re /** * The magic functions :). Fills the given layout, defined by the renderState. This is fairly - * independent from the rest of the {@link android.support.v7.widget.LinearLayoutManager} + * independent from the rest of the {@link androidx.recyclerview.widget.LinearLayoutManager} * and with little change, can be made publicly available as a helper class. * * @param recycler Current recycler that is attached to RecyclerView @@ -971,7 +975,7 @@ private void recycleByRenderState(RecyclerView.Recycler recycler, RenderState re * @param stopOnFocusable If true, filling stops in the first focusable new child * @return Number of pixels that it added. Useful for scoll functions. */ - private int fill(RecyclerView.Recycler recycler, RenderState renderState, + private int fill(RecyclerView.Recycler recycler, @NonNull RenderState renderState, RecyclerView.State state, boolean stopOnFocusable) { // max offset we should set is mFastScroll + available @@ -1211,9 +1215,11 @@ int findOneVisibleChild(int fromIndex, int toIndex, boolean completelyVisible) { if (childStart < end && childEnd > start) { if (completelyVisible) { if (childStart >= start && childEnd <= end) { + assert child != null; return getPosition(child); } } else { + assert child != null; return getPosition(child); } } @@ -1222,9 +1228,9 @@ int findOneVisibleChild(int fromIndex, int toIndex, boolean completelyVisible) { } @Override - public View onFocusSearchFailed(View focused, int focusDirection, - RecyclerView.Recycler recycler, - RecyclerView.State state) { + public View onFocusSearchFailed(@NonNull View focused, int focusDirection, + @NonNull RecyclerView.Recycler recycler, + @NonNull RecyclerView.State state) { resolveShouldLayoutReverse(); if (getChildCount() == 0) { return null; @@ -1266,6 +1272,7 @@ private void logChildren() { Log.d(TAG, "internal representation of views on the screen"); for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); + assert child != null; Log.d(TAG, "item " + getPosition(child) + ", coord:" + mOrientationHelper.getDecoratedStart(child)); } @@ -1287,11 +1294,12 @@ private void validateChildOrder() { if (getChildCount() < 1) { return; } - int lastPos = getPosition(getChildAt(0)); + int lastPos = getPosition(Objects.requireNonNull(getChildAt(0))); int lastScreenLoc = mOrientationHelper.getDecoratedStart(getChildAt(0)); if (mShouldReverseLayout) { for (int i = 1; i < getChildCount(); i++) { View child = getChildAt(i); + assert child != null; int pos = getPosition(child); int screenLoc = mOrientationHelper.getDecoratedStart(child); if (pos < lastPos) { @@ -1307,6 +1315,7 @@ private void validateChildOrder() { } else { for (int i = 1; i < getChildCount(); i++) { View child = getChildAt(i); + assert child != null; int pos = getPosition(child); int screenLoc = mOrientationHelper.getDecoratedStart(child); if (pos < lastPos) { @@ -1423,13 +1432,14 @@ View next(RecyclerView.Recycler recycler) { * * @return View if an item in the current position or direction exists if not null. */ + @Nullable private View nextFromLimitedList() { int size = mScrapList.size(); RecyclerView.ViewHolder closest = null; int closestDistance = Integer.MAX_VALUE; for (int i = 0; i < size; i++) { RecyclerView.ViewHolder viewHolder = mScrapList.get(i); - final int distance = (viewHolder.getPosition() - mCurrentPosition) * mItemDirection; + final int distance = (viewHolder.getBindingAdapterPosition() - mCurrentPosition) * mItemDirection; if (distance < 0) { continue; // item is not in current direction } @@ -1443,7 +1453,7 @@ private View nextFromLimitedList() { } if (closest != null) { - mCurrentPosition = closest.getPosition() + mItemDirection; + mCurrentPosition = closest.getBindingAdapterPosition() + mItemDirection; return closest.itemView; } return null; @@ -1456,7 +1466,7 @@ public int getHeaderIncrementFixer() { return mHeaderIncrementFixer; } - public void setHeaderIncrementFixer(final View headerIncrementFixer) { + public void setHeaderIncrementFixer(@NonNull final View headerIncrementFixer) { headerIncrementFixer.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { @@ -1579,7 +1589,7 @@ public int getTotalSpace() { /** * Helper interface to offload orientation based decisions */ - static interface OrientationHelper { + interface OrientationHelper { /** * @param view The view element to check @@ -1651,7 +1661,7 @@ public SavedState() { } - SavedState(Parcel in) { + SavedState(@NonNull Parcel in) { mOrientation = in.readInt(); mAnchorPosition = in.readInt(); mAnchorOffset = in.readInt(); @@ -1660,7 +1670,7 @@ public SavedState() { mAnchorLayoutFromEnd = in.readInt() == 1; } - public SavedState(SavedState other) { + public SavedState(@NonNull SavedState other) { mOrientation = other.mOrientation; mAnchorPosition = other.mAnchorPosition; mAnchorOffset = other.mAnchorOffset; @@ -1675,7 +1685,7 @@ public int describeContents() { } @Override - public void writeToParcel(Parcel dest, int flags) { + public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeInt(mOrientation); dest.writeInt(mAnchorPosition); dest.writeInt(mAnchorOffset); diff --git a/library/src/main/java/com/poliveira/parallaxrecyclerview/ParallaxRecyclerAdapter.java b/library/src/main/java/com/poliveira/parallaxrecyclerview/ParallaxRecyclerAdapter.java index 4726a0e..6e68838 100644 --- a/library/src/main/java/com/poliveira/parallaxrecyclerview/ParallaxRecyclerAdapter.java +++ b/library/src/main/java/com/poliveira/parallaxrecyclerview/ParallaxRecyclerAdapter.java @@ -1,16 +1,20 @@ package com.poliveira.parallaxrecyclerview; +import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Canvas; import android.graphics.Rect; import android.os.Build; -import android.support.v7.widget.RecyclerView; import android.view.View; import android.view.ViewGroup; import android.view.animation.TranslateAnimation; import android.widget.RelativeLayout; +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + import java.util.List; +import java.util.Objects; public abstract class ParallaxRecyclerAdapter extends RecyclerView.Adapter { private float mScrollMultiplier = 0.5f; @@ -58,7 +62,7 @@ public interface OnParallaxScroll { */ public void translateHeader(float of) { float ofCalculated = of * mScrollMultiplier; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB && of < mHeader.getHeight()) { + if (of < mHeader.getHeight()) { mHeader.setTranslationY(ofCalculated); } else if (of < mHeader.getHeight()) { TranslateAnimation anim = new TranslateAnimation(0, 0, ofCalculated, ofCalculated); @@ -85,17 +89,17 @@ public void translateHeader(float of) { * @param header The inflated header * @param view The RecyclerView to set scroll listeners */ - public void setParallaxHeader(View header, final RecyclerView view) { + public void setParallaxHeader(@NonNull View header, @NonNull final RecyclerView view) { mRecyclerView = view; mHeader = new CustomRelativeWrapper(header.getContext(), mShouldClipView); mHeader.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); mHeader.addView(header, new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); - view.setOnScrollListener(new RecyclerView.OnScrollListener() { + view.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override - public void onScrolled(RecyclerView recyclerView, int dx, int dy) { + public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); if (mHeader != null) { - translateHeader(mRecyclerView.getLayoutManager().getChildAt(0) == mHeader ? + translateHeader(Objects.requireNonNull(mRecyclerView.getLayoutManager()).getChildAt(0) == mHeader ? mRecyclerView.computeVerticalScrollOffset() : mHeader.getHeight()); } @@ -104,7 +108,7 @@ public void onScrolled(RecyclerView recyclerView, int dx, int dy) { } @Override - public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, final int i) { + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, final int i) { if (mHeader != null) { if (i == 0) { return; @@ -115,8 +119,9 @@ public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, final int i) { } } + @NonNull @Override - public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, final int i) { + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, final int i) { if (i == VIEW_TYPES.HEADER && mHeader != null) { return new ViewHolder(mHeader); } @@ -128,12 +133,8 @@ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, final int } final RecyclerView.ViewHolder holder = onCreateViewHolderImpl(viewGroup, this, i); if (mOnClickEvent != null) { - holder.itemView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - mOnClickEvent.onClick(v, holder.getAdapterPosition() - (mHeader == null ? 0 : 1)); - } - }); + holder.itemView.setOnClickListener(v -> + mOnClickEvent.onClick(v, holder.getBindingAdapterPosition() - (mHeader == null ? 0 : 1))); } return holder; } @@ -155,8 +156,8 @@ public boolean isShouldClipView() { } /** - * Defines if we will clip the layout or not. MUST BE CALLED BEFORE {@link - * #setParallaxHeader(android.view.View, android.support.v7.widget.RecyclerView)} + * Defines if we will clip the layout or not. MUST BE CALLED BEFORE + * {@link #setParallaxHeader(View, RecyclerView)} */ public void setShouldClipView(boolean shouldClickView) { mShouldClipView = shouldClickView; @@ -175,6 +176,7 @@ public List getData() { return mData; } + @SuppressLint("NotifyDataSetChanged") public void setData(List data) { mData = data; notifyDataSetChanged(); @@ -211,10 +213,12 @@ public ViewHolder(View itemView) { } } + + @SuppressLint("ViewConstructor") static class CustomRelativeWrapper extends RelativeLayout { private int mOffset; - private boolean mShouldClip; + private final boolean mShouldClip; public CustomRelativeWrapper(Context context, boolean shouldClick) { super(context); diff --git a/settings.gradle b/settings.gradle index e162734..d01c692 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1,9 @@ +pluginManagement { + repositories { + gradlePluginPortal() + google() + mavenCentral() + } +} + include ':example', ':library'