├── app ├── .gitignore ├── src │ └── main │ │ ├── res │ │ ├── values │ │ │ ├── strings.xml │ │ │ ├── colors.xml │ │ │ ├── dimens.xml │ │ │ └── styles.xml │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ │ └── ic_launcher.png │ │ ├── values-w820dp │ │ │ └── dimens.xml │ │ └── layout │ │ │ └── activity_main.xml │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── com │ │ └── bosphere │ │ └── demo │ │ └── MainActivity.java ├── proguard-rules.pro └── build.gradle ├── fadingedgelayout ├── .gitignore ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ ├── res │ │ └── values │ │ │ └── attrs.xml │ │ └── java │ │ └── com │ │ └── bosphere │ │ └── fadingedgelayout │ │ └── FadingEdgeLayout.java ├── proguard-rules.pro └── build.gradle ├── settings.gradle ├── art ├── anim.gif └── screenshot.png ├── .gitignore ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradle.properties ├── README.md ├── gradlew.bat └── gradlew /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /fadingedgelayout/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':fadingedgelayout' 2 | -------------------------------------------------------------------------------- /art/anim.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bosphere/Android-FadingEdgeLayout/HEAD/art/anim.gif -------------------------------------------------------------------------------- /art/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bosphere/Android-FadingEdgeLayout/HEAD/art/screenshot.png -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Android Fade Demo 3 | 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | .idea/ 5 | .DS_Store 6 | /build 7 | /captures 8 | .externalNativeBuild 9 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bosphere/Android-FadingEdgeLayout/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /fadingedgelayout/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bosphere/Android-FadingEdgeLayout/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bosphere/Android-FadingEdgeLayout/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bosphere/Android-FadingEdgeLayout/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bosphere/Android-FadingEdgeLayout/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bosphere/Android-FadingEdgeLayout/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Dec 28 10:00:20 PST 2015 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-4.6-all.zip 7 | -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /fadingedgelayout/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /app/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 /Volumes/Data/Users/bo/Library/Android/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 | -------------------------------------------------------------------------------- /fadingedgelayout/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 /Volumes/Data/Users/bo/Library/Android/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 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /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 | android.enableJetifier=true 13 | android.useAndroidX=true 14 | org.gradle.jvmargs=-Xmx1536m 15 | 16 | # When configured, Gradle will run in incubating parallel mode. 17 | # This option should only be used with decoupled projects. More details, visit 18 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 19 | # org.gradle.parallel=true 20 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 28 5 | buildToolsVersion "28.0.3" 6 | defaultConfig { 7 | applicationId "com.bosphere.fadingedgelayout" 8 | minSdkVersion 14 9 | targetSdkVersion 28 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 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 'androidx.appcompat:appcompat:1.0.0' 25 | compile 'androidx.recyclerview:recyclerview:1.0.0' 26 | compile 'androidx.gridlayout:gridlayout:1.0.0' 27 | compile project(':fadingedgelayout') 28 | // compile 'com.github.bosphere.android-fadingedgelayout:fadingedgelayout:1.0.0' 29 | } 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | Android-FadingEdgeLayout 3 | ============================ 4 | 5 | A versatile layout that fades its edges regardless of child view type. 6 | 7 | #### What is available: 8 | * Four fading edges that are individually configurable 9 | * Length of fading edge is adjustable 10 | * Supports any type of child `View` 11 | 12 | 13 | 14 | 15 | 16 | Usage 17 | ----- 18 | ```gradle 19 | dependencies { 20 | compile 'com.github.bosphere.android-fadingedgelayout:fadingedgelayout:1.0.0' 21 | } 22 | ``` 23 | 24 | ```xml 25 | 34 | 35 | 39 | 40 | 41 | ``` 42 | 43 | ```java 44 | FadingEdgeLayout mFadingEdgeLayout = ...; 45 | mFadingEdgeLayout.setFadeEdges(mEnableTop, mEnableLeft, mEnableBottom, mEnableRight); 46 | mFadingEdgeLayout.setFadeSizes(lenPx, lenPx, lenPx, lenPx); 47 | ``` 48 | 49 | The fading edges are not implemented as color overlay but rather linear gradient alpha mask of the content. So it'll naturally follow the color of the background. 50 | 51 | Compatibility 52 | ------------- 53 | 54 | API 7 (Android 2.1) and up 55 | 56 | License 57 | ------- 58 | 59 | Copyright 2017 Yang Bo 60 | 61 | Licensed under the Apache License, Version 2.0 (the "License"); 62 | you may not use this file except in compliance with the License. 63 | You may obtain a copy of the License at 64 | 65 | http://www.apache.org/licenses/LICENSE-2.0 66 | 67 | Unless required by applicable law or agreed to in writing, software 68 | distributed under the License is distributed on an "AS IS" BASIS, 69 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 70 | See the License for the specific language governing permissions and 71 | limitations under the License. -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /fadingedgelayout/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | /* 4 | define in local.properties these variables: 5 | bintray.user=[BINTRAY_USERNAME] 6 | bintray.apikey=[BINTRAY_API_KEY] 7 | bintray.gpg.password=[DEPENDS_WHETHER_GPG_AUTO_SIGNING_KEY_HAS_A_PASSPHRASE] 8 | developer.id=[USERNAME] 9 | developer.name=[FULL_NAME] 10 | developer.email=[EMAIL] 11 | */ 12 | 13 | ext { 14 | LIB_VERSION = '1.0.0' 15 | 16 | bintrayRepo = 'maven' 17 | bintrayName = 'android-fading-edge-layout' 18 | 19 | publishedGroupId = 'com.github.bosphere.android-fadingedgelayout' 20 | libraryName = 'Android-FadingEdgeLayout' 21 | artifact = 'fadingedgelayout' 22 | 23 | libraryDescription = 'A versatile layout that fades its edges regardless of child view type.' 24 | 25 | siteUrl = 'https://github.com/bosphere/Android-FadingEdgeLayout' 26 | gitUrl = 'https://github.com/bosphere/Android-FadingEdgeLayout.git' 27 | 28 | libraryVersion = "$LIB_VERSION" 29 | 30 | Properties properties = new Properties() 31 | properties.load(project.rootProject.file('local.properties').newDataInputStream()) 32 | developerId = properties.getProperty('developer.id') 33 | developerName = properties.getProperty('developer.name') 34 | developerEmail = properties.getProperty('developer.email') 35 | 36 | licenseName = 'The Apache Software License, Version 2.0' 37 | licenseUrl = 'http://www.apache.org/licenses/LICENSE-2.0.txt' 38 | allLicenses = ["Apache-2.0"] 39 | } 40 | 41 | android { 42 | compileSdkVersion 28 43 | buildToolsVersion "28.0.3" 44 | 45 | defaultConfig { 46 | minSdkVersion 9 47 | } 48 | } 49 | 50 | dependencies { 51 | } 52 | 53 | /////////////////////////////////////////////////////////////////////////////////////////// 54 | 55 | apply plugin: 'com.github.dcendents.android-maven' 56 | 57 | group = publishedGroupId // Maven Group ID for the artifact 58 | 59 | install { 60 | repositories.mavenInstaller { 61 | // This generates POM.xml with proper parameters 62 | pom { 63 | project { 64 | packaging 'aar' 65 | groupId publishedGroupId 66 | artifactId artifact 67 | 68 | // Add your description here 69 | name libraryName 70 | description libraryDescription 71 | url siteUrl 72 | 73 | // Set your license 74 | licenses { 75 | license { 76 | name licenseName 77 | url licenseUrl 78 | } 79 | } 80 | developers { 81 | developer { 82 | id developerId 83 | name developerName 84 | email developerEmail 85 | } 86 | } 87 | scm { 88 | connection gitUrl 89 | developerConnection gitUrl 90 | url siteUrl 91 | 92 | } 93 | } 94 | } 95 | } 96 | } 97 | 98 | /////////////////////////////////////////////////////////////////////////////////////////// 99 | 100 | apply plugin: 'com.jfrog.bintray' 101 | 102 | version = libraryVersion 103 | 104 | task sourcesJar(type: Jar) { 105 | from android.sourceSets.main.java.srcDirs 106 | classifier = 'sources' 107 | } 108 | 109 | task javadoc(type: Javadoc) { 110 | source = android.sourceSets.main.java.srcDirs 111 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) 112 | } 113 | 114 | task javadocJar(type: Jar, dependsOn: javadoc) { 115 | classifier = 'javadoc' 116 | from javadoc.destinationDir 117 | } 118 | artifacts { 119 | archives javadocJar 120 | archives sourcesJar 121 | } 122 | 123 | // Bintray 124 | Properties properties = new Properties() 125 | properties.load(project.rootProject.file('local.properties').newDataInputStream()) 126 | 127 | bintray { 128 | user = properties.getProperty("bintray.user") 129 | key = properties.getProperty("bintray.apikey") 130 | 131 | configurations = ['archives'] 132 | pkg { 133 | repo = bintrayRepo 134 | name = bintrayName 135 | desc = libraryDescription 136 | websiteUrl = siteUrl 137 | vcsUrl = gitUrl 138 | licenses = allLicenses 139 | publish = true 140 | publicDownloadNumbers = true 141 | version { 142 | desc = libraryDescription 143 | gpg { 144 | sign = true //Determines whether to GPG sign the files. The default is false 145 | passphrase = properties.getProperty("bintray.gpg.password") 146 | //Optional. The passphrase for GPG signing' 147 | } 148 | } 149 | } 150 | } 151 | 152 | /////////////////////////////////////////////////////////////////////////////////////////// 153 | -------------------------------------------------------------------------------- /app/src/main/java/com/bosphere/demo/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.bosphere.demo; 2 | 3 | import android.graphics.Color; 4 | import android.os.Bundle; 5 | import androidx.appcompat.app.AppCompatActivity; 6 | import androidx.recyclerview.widget.GridLayoutManager; 7 | import androidx.recyclerview.widget.RecyclerView; 8 | import androidx.appcompat.widget.SwitchCompat; 9 | import android.util.TypedValue; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | import android.widget.SeekBar; 13 | 14 | import com.bosphere.fadingedgelayout.FadingEdgeLayout; 15 | 16 | public class MainActivity extends AppCompatActivity { 17 | 18 | private static final int MAX_FADE_LENGTH = 400; // dp 19 | 20 | private FadingEdgeLayout mFadingEdgeLayout; 21 | private RecyclerView mRecyclerView; 22 | private GridLayoutManager mLayoutManager; 23 | private Adapter mAdapter; 24 | private boolean mEnableTop = false; 25 | private boolean mEnableLeft = false; 26 | private boolean mEnableBottom = false; 27 | private boolean mEnableRight = false; 28 | 29 | @Override 30 | protected void onCreate(Bundle savedInstanceState) { 31 | super.onCreate(savedInstanceState); 32 | setContentView(R.layout.activity_main); 33 | 34 | mFadingEdgeLayout = (FadingEdgeLayout) findViewById(R.id.fading_edge_layout); 35 | mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view); 36 | mLayoutManager = new GridLayoutManager(this, 4); 37 | mRecyclerView.setLayoutManager(mLayoutManager); 38 | mAdapter = new Adapter(); 39 | mRecyclerView.setAdapter(mAdapter); 40 | 41 | SeekBar sb = (SeekBar) findViewById(R.id.sb_size); 42 | sb.setProgress(20); 43 | sb.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { 44 | @Override 45 | public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { 46 | float percent = progress / 100f; 47 | int len = (int) (MAX_FADE_LENGTH * percent); 48 | int lenPx = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, len, 49 | getResources().getDisplayMetrics()); 50 | mFadingEdgeLayout.setFadeSizes(lenPx, lenPx, lenPx, lenPx); 51 | } 52 | 53 | @Override 54 | public void onStartTrackingTouch(SeekBar seekBar) { } 55 | 56 | @Override 57 | public void onStopTrackingTouch(SeekBar seekBar) { } 58 | }); 59 | } 60 | 61 | public void onClickedOrientation(View view) { 62 | switch (view.getId()) { 63 | case R.id.rb_horizontal: 64 | mLayoutManager.setOrientation(GridLayoutManager.HORIZONTAL); 65 | break; 66 | case R.id.rb_vertical: 67 | mLayoutManager.setOrientation(GridLayoutManager.VERTICAL); 68 | break; 69 | } 70 | } 71 | 72 | public void onClickedSwitch(View view) { 73 | SwitchCompat sw = (SwitchCompat) view; 74 | switch (sw.getId()) { 75 | case R.id.sw_top: 76 | mEnableTop = sw.isChecked(); 77 | mFadingEdgeLayout.setFadeEdges(mEnableTop, mEnableLeft, mEnableBottom, mEnableRight); 78 | break; 79 | case R.id.sw_left: 80 | mEnableLeft = sw.isChecked(); 81 | mFadingEdgeLayout.setFadeEdges(mEnableTop, mEnableLeft, mEnableBottom, mEnableRight); 82 | break; 83 | case R.id.sw_bottom: 84 | mEnableBottom = sw.isChecked(); 85 | mFadingEdgeLayout.setFadeEdges(mEnableTop, mEnableLeft, mEnableBottom, mEnableRight); 86 | break; 87 | case R.id.sw_right: 88 | mEnableRight = sw.isChecked(); 89 | mFadingEdgeLayout.setFadeEdges(mEnableTop, mEnableLeft, mEnableBottom, mEnableRight); 90 | break; 91 | } 92 | } 93 | 94 | private static class Adapter extends RecyclerView.Adapter { 95 | 96 | @Override 97 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 98 | View square = new View(parent.getContext()); 99 | square.setBackgroundColor(Color.MAGENTA); 100 | RecyclerView.LayoutParams params = new RecyclerView.LayoutParams(200, 200); 101 | params.leftMargin = params.topMargin = params.rightMargin = params.bottomMargin = 20; 102 | square.setLayoutParams(params); 103 | return new ViewHolder(square); 104 | } 105 | 106 | @Override 107 | public void onBindViewHolder(ViewHolder holder, int position) { 108 | } 109 | 110 | @Override 111 | public int getItemCount() { 112 | return 80; 113 | } 114 | } 115 | 116 | private static class ViewHolder extends RecyclerView.ViewHolder { 117 | 118 | public ViewHolder(View itemView) { 119 | super(itemView); 120 | } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 17 | 18 | 22 | 23 | 24 | 25 | 34 | 35 | 40 | 41 | 46 | 47 | 54 | 55 | 61 | 62 | 63 | 64 | 67 | 68 | 75 | 76 | 77 | 80 | 81 | 88 | 89 | 90 | 93 | 94 | 101 | 102 | 103 | 106 | 107 | 114 | 115 | 116 | 121 | 122 | 127 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /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 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /fadingedgelayout/src/main/java/com/bosphere/fadingedgelayout/FadingEdgeLayout.java: -------------------------------------------------------------------------------- 1 | package com.bosphere.fadingedgelayout; 2 | 3 | import android.content.Context; 4 | import android.content.res.TypedArray; 5 | import android.graphics.Canvas; 6 | import android.graphics.Color; 7 | import android.graphics.LinearGradient; 8 | import android.graphics.Paint; 9 | import android.graphics.PorterDuff; 10 | import android.graphics.PorterDuffXfermode; 11 | import android.graphics.Rect; 12 | import android.graphics.Shader; 13 | import android.util.AttributeSet; 14 | import android.util.TypedValue; 15 | import android.widget.FrameLayout; 16 | 17 | /** 18 | * Created by yangbo on 9/1/17. 19 | */ 20 | 21 | public class FadingEdgeLayout extends FrameLayout { 22 | 23 | private static final int DEFAULT_GRADIENT_SIZE_DP = 80; 24 | 25 | public static final int FADE_EDGE_TOP = 1; 26 | public static final int FADE_EDGE_BOTTOM = 2; 27 | public static final int FADE_EDGE_LEFT = 4; 28 | public static final int FADE_EDGE_RIGHT = 8; 29 | 30 | private static final int DIRTY_FLAG_TOP = 1; 31 | private static final int DIRTY_FLAG_BOTTOM = 2; 32 | private static final int DIRTY_FLAG_LEFT = 4; 33 | private static final int DIRTY_FLAG_RIGHT = 8; 34 | 35 | private static final int[] FADE_COLORS = new int[]{Color.TRANSPARENT, Color.BLACK}; 36 | private static final int[] FADE_COLORS_REVERSE = new int[]{Color.BLACK, Color.TRANSPARENT}; 37 | 38 | private boolean fadeTop, fadeBottom, fadeLeft, fadeRight; 39 | private int gradientSizeTop, gradientSizeBottom, gradientSizeLeft, gradientSizeRight; 40 | private Paint gradientPaintTop, gradientPaintBottom, gradientPaintLeft, gradientPaintRight; 41 | private Rect gradientRectTop, gradientRectBottom, gradientRectLeft, gradientRectRight; 42 | private int gradientDirtyFlags; 43 | 44 | public FadingEdgeLayout(Context context) { 45 | super(context); 46 | init(null, 0); 47 | } 48 | 49 | public FadingEdgeLayout(Context context, AttributeSet attrs) { 50 | super(context, attrs); 51 | init(attrs, 0); 52 | } 53 | 54 | public FadingEdgeLayout(Context context, AttributeSet attrs, int defStyleAttr) { 55 | super(context, attrs, defStyleAttr); 56 | init(attrs, 0); 57 | } 58 | 59 | private void init(AttributeSet attrs, int defStyleAttr) { 60 | int defaultSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, DEFAULT_GRADIENT_SIZE_DP, 61 | getResources().getDisplayMetrics()); 62 | 63 | if (attrs != null) { 64 | TypedArray arr = getContext().obtainStyledAttributes(attrs, R.styleable.FadingEdgeLayout, defStyleAttr, 0); 65 | int flags = arr.getInt(R.styleable.FadingEdgeLayout_fel_edge, 0); 66 | 67 | fadeTop = (flags & FADE_EDGE_TOP) == FADE_EDGE_TOP; 68 | fadeBottom = (flags & FADE_EDGE_BOTTOM) == FADE_EDGE_BOTTOM; 69 | fadeLeft = (flags & FADE_EDGE_LEFT) == FADE_EDGE_LEFT; 70 | fadeRight = (flags & FADE_EDGE_RIGHT) == FADE_EDGE_RIGHT; 71 | 72 | gradientSizeTop = arr.getDimensionPixelSize(R.styleable.FadingEdgeLayout_fel_size_top, defaultSize); 73 | gradientSizeBottom = arr.getDimensionPixelSize(R.styleable.FadingEdgeLayout_fel_size_bottom, defaultSize); 74 | gradientSizeLeft = arr.getDimensionPixelSize(R.styleable.FadingEdgeLayout_fel_size_left, defaultSize); 75 | gradientSizeRight = arr.getDimensionPixelSize(R.styleable.FadingEdgeLayout_fel_size_right, defaultSize); 76 | 77 | if (fadeTop && gradientSizeTop > 0) { 78 | gradientDirtyFlags |= DIRTY_FLAG_TOP; 79 | } 80 | if (fadeLeft && gradientSizeLeft > 0) { 81 | gradientDirtyFlags |= DIRTY_FLAG_LEFT; 82 | } 83 | if (fadeBottom && gradientSizeBottom > 0) { 84 | gradientDirtyFlags |= DIRTY_FLAG_BOTTOM; 85 | } 86 | if (fadeRight && gradientSizeRight > 0) { 87 | gradientDirtyFlags |= DIRTY_FLAG_RIGHT; 88 | } 89 | 90 | arr.recycle(); 91 | } else { 92 | gradientSizeTop = gradientSizeBottom = gradientSizeLeft = gradientSizeRight = defaultSize; 93 | } 94 | 95 | PorterDuffXfermode mode = new PorterDuffXfermode(PorterDuff.Mode.DST_IN); 96 | gradientPaintTop = new Paint(Paint.ANTI_ALIAS_FLAG); 97 | gradientPaintTop.setXfermode(mode); 98 | gradientPaintBottom = new Paint(Paint.ANTI_ALIAS_FLAG); 99 | gradientPaintBottom.setXfermode(mode); 100 | gradientPaintLeft = new Paint(Paint.ANTI_ALIAS_FLAG); 101 | gradientPaintLeft.setXfermode(mode); 102 | gradientPaintRight = new Paint(Paint.ANTI_ALIAS_FLAG); 103 | gradientPaintRight.setXfermode(mode); 104 | 105 | gradientRectTop = new Rect(); 106 | gradientRectLeft = new Rect(); 107 | gradientRectBottom = new Rect(); 108 | gradientRectRight = new Rect(); 109 | } 110 | 111 | public void setFadeSizes(int top, int left, int bottom, int right) { 112 | if (gradientSizeTop != top) { 113 | gradientSizeTop = top; 114 | gradientDirtyFlags |= DIRTY_FLAG_TOP; 115 | } 116 | if (gradientSizeLeft != left) { 117 | gradientSizeLeft = left; 118 | gradientDirtyFlags |= DIRTY_FLAG_LEFT; 119 | } 120 | if (gradientSizeBottom != bottom) { 121 | gradientSizeBottom = bottom; 122 | gradientDirtyFlags |= DIRTY_FLAG_BOTTOM; 123 | } 124 | if (gradientSizeRight != right) { 125 | gradientSizeRight = right; 126 | gradientDirtyFlags |= DIRTY_FLAG_RIGHT; 127 | } 128 | if (gradientDirtyFlags != 0) { 129 | invalidate(); 130 | } 131 | } 132 | 133 | public void setFadeEdges(boolean fadeTop, boolean fadeLeft, boolean fadeBottom, boolean fadeRight) { 134 | if (this.fadeTop != fadeTop) { 135 | this.fadeTop = fadeTop; 136 | gradientDirtyFlags |= DIRTY_FLAG_TOP; 137 | } 138 | if (this.fadeLeft != fadeLeft) { 139 | this.fadeLeft = fadeLeft; 140 | gradientDirtyFlags |= DIRTY_FLAG_LEFT; 141 | } 142 | if (this.fadeBottom != fadeBottom) { 143 | this.fadeBottom = fadeBottom; 144 | gradientDirtyFlags |= DIRTY_FLAG_BOTTOM; 145 | } 146 | if (this.fadeRight != fadeRight) { 147 | this.fadeRight = fadeRight; 148 | gradientDirtyFlags |= DIRTY_FLAG_RIGHT; 149 | } 150 | if (gradientDirtyFlags != 0) { 151 | invalidate(); 152 | } 153 | } 154 | 155 | @Override 156 | public void setPadding(int left, int top, int right, int bottom) { 157 | if (getPaddingLeft() != left) { 158 | gradientDirtyFlags |= DIRTY_FLAG_LEFT; 159 | } 160 | if (getPaddingTop() != top) { 161 | gradientDirtyFlags |= DIRTY_FLAG_TOP; 162 | } 163 | if (getPaddingRight() != right) { 164 | gradientDirtyFlags |= DIRTY_FLAG_RIGHT; 165 | } 166 | if (getPaddingBottom() != bottom) { 167 | gradientDirtyFlags |= DIRTY_FLAG_BOTTOM; 168 | } 169 | super.setPadding(left, top, right, bottom); 170 | } 171 | 172 | @Override 173 | protected void onSizeChanged(int w, int h, int oldw, int oldh) { 174 | super.onSizeChanged(w, h, oldw, oldh); 175 | if (w != oldw) { 176 | gradientDirtyFlags |= DIRTY_FLAG_LEFT; 177 | gradientDirtyFlags |= DIRTY_FLAG_RIGHT; 178 | } 179 | if (h != oldh) { 180 | gradientDirtyFlags |= DIRTY_FLAG_TOP; 181 | gradientDirtyFlags |= DIRTY_FLAG_BOTTOM; 182 | } 183 | } 184 | 185 | @Override 186 | protected void dispatchDraw(Canvas canvas) { 187 | int newWidth = getWidth(), newHeight = getHeight(); 188 | boolean fadeAnyEdge = fadeTop || fadeBottom || fadeLeft || fadeRight; 189 | if (getVisibility() == GONE || newWidth == 0 || newHeight == 0 || !fadeAnyEdge) { 190 | super.dispatchDraw(canvas); 191 | return; 192 | } 193 | 194 | if ((gradientDirtyFlags & DIRTY_FLAG_TOP) == DIRTY_FLAG_TOP) { 195 | gradientDirtyFlags &= ~DIRTY_FLAG_TOP; 196 | initTopGradient(); 197 | } 198 | if ((gradientDirtyFlags & DIRTY_FLAG_LEFT) == DIRTY_FLAG_LEFT) { 199 | gradientDirtyFlags &= ~DIRTY_FLAG_LEFT; 200 | initLeftGradient(); 201 | } 202 | if ((gradientDirtyFlags & DIRTY_FLAG_BOTTOM) == DIRTY_FLAG_BOTTOM) { 203 | gradientDirtyFlags &= ~DIRTY_FLAG_BOTTOM; 204 | initBottomGradient(); 205 | } 206 | if ((gradientDirtyFlags & DIRTY_FLAG_RIGHT) == DIRTY_FLAG_RIGHT) { 207 | gradientDirtyFlags &= ~DIRTY_FLAG_RIGHT; 208 | initRightGradient(); 209 | } 210 | 211 | int count = canvas.saveLayer(0.0f, 0.0f, (float) getWidth(), (float) getHeight(), null, Canvas.ALL_SAVE_FLAG); 212 | super.dispatchDraw(canvas); 213 | if (fadeTop && gradientSizeTop > 0) { 214 | canvas.drawRect(gradientRectTop, gradientPaintTop); 215 | } 216 | if (fadeBottom && gradientSizeBottom > 0) { 217 | canvas.drawRect(gradientRectBottom, gradientPaintBottom); 218 | } 219 | if (fadeLeft && gradientSizeLeft > 0) { 220 | canvas.drawRect(gradientRectLeft, gradientPaintLeft); 221 | } 222 | if (fadeRight && gradientSizeRight > 0) { 223 | canvas.drawRect(gradientRectRight, gradientPaintRight); 224 | } 225 | canvas.restoreToCount(count); 226 | } 227 | 228 | private void initTopGradient() { 229 | int actualHeight = getHeight() - getPaddingTop() - getPaddingBottom(); 230 | int size = Math.min(gradientSizeTop, actualHeight); 231 | int l = getPaddingLeft(); 232 | int t = getPaddingTop(); 233 | int r = getWidth() - getPaddingRight(); 234 | int b = t + size; 235 | gradientRectTop.set(l, t, r, b); 236 | LinearGradient gradient = new LinearGradient(l, t, l, b, FADE_COLORS, null, Shader.TileMode.CLAMP); 237 | gradientPaintTop.setShader(gradient); 238 | } 239 | 240 | private void initLeftGradient() { 241 | int actualWidth = getWidth() - getPaddingLeft() - getPaddingRight(); 242 | int size = Math.min(gradientSizeLeft, actualWidth); 243 | int l = getPaddingLeft(); 244 | int t = getPaddingTop(); 245 | int r = l + size; 246 | int b = getHeight() - getPaddingBottom(); 247 | gradientRectLeft.set(l, t, r, b); 248 | LinearGradient gradient = new LinearGradient(l, t, r, t, FADE_COLORS, null, Shader.TileMode.CLAMP); 249 | gradientPaintLeft.setShader(gradient); 250 | } 251 | 252 | private void initBottomGradient() { 253 | int actualHeight = getHeight() - getPaddingTop() - getPaddingBottom(); 254 | int size = Math.min(gradientSizeBottom, actualHeight); 255 | int l = getPaddingLeft(); 256 | int t = getPaddingTop() + actualHeight - size; 257 | int r = getWidth() - getPaddingRight(); 258 | int b = t + size; 259 | gradientRectBottom.set(l, t, r, b); 260 | LinearGradient gradient = new LinearGradient(l, t, l, b, FADE_COLORS_REVERSE, null, Shader.TileMode.CLAMP); 261 | gradientPaintBottom.setShader(gradient); 262 | } 263 | 264 | private void initRightGradient() { 265 | int actualWidth = getWidth() - getPaddingLeft() - getPaddingRight(); 266 | int size = Math.min(gradientSizeRight, actualWidth); 267 | int l = getPaddingLeft() + actualWidth - size; 268 | int t = getPaddingTop(); 269 | int r = l + size; 270 | int b = getHeight() - getPaddingBottom(); 271 | gradientRectRight.set(l, t, r, b); 272 | LinearGradient gradient = new LinearGradient(l, t, r, t, FADE_COLORS_REVERSE, null, Shader.TileMode.CLAMP); 273 | gradientPaintRight.setShader(gradient); 274 | } 275 | } 276 | --------------------------------------------------------------------------------