├── .gitignore ├── LICENSE.MD ├── README.md ├── art └── demo.gif ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── library ├── .gitignore ├── build.gradle ├── gradle.properties ├── proguard-rules.txt └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── melnykov │ │ └── fab │ │ ├── AbsListViewScrollDetector.java │ │ ├── FloatingActionButton.java │ │ ├── ObservableScrollView.java │ │ ├── RecyclerViewScrollDetector.java │ │ ├── ScrollDirectionListener.java │ │ └── ScrollViewScrollDetector.java │ └── res │ ├── anim-v21 │ └── fab_press_elevation.xml │ ├── drawable-hdpi │ ├── fab_shadow.png │ └── fab_shadow_mini.png │ ├── drawable-mdpi │ ├── fab_shadow.png │ └── fab_shadow_mini.png │ ├── drawable-xhdpi │ ├── fab_shadow.png │ └── fab_shadow_mini.png │ ├── drawable-xxhdpi │ ├── fab_shadow.png │ └── fab_shadow_mini.png │ ├── drawable-xxxhdpi │ ├── fab_shadow.png │ └── fab_shadow_mini.png │ └── values │ ├── attrs.xml │ ├── colors.xml │ ├── dimens.xml │ └── info_strings.xml ├── sample.apk ├── sample ├── .gitignore ├── build.gradle └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── melnykov │ │ └── fab │ │ └── sample │ │ ├── DividerItemDecoration.java │ │ ├── ListViewAdapter.java │ │ ├── MainActivity.java │ │ └── RecyclerViewAdapter.java │ └── res │ ├── drawable-hdpi │ ├── ic_add_white_24dp.png │ └── ic_launcher.png │ ├── drawable-mdpi │ ├── ic_add_white_24dp.png │ └── ic_launcher.png │ ├── drawable-xhdpi │ ├── ic_add_white_24dp.png │ └── ic_launcher.png │ ├── drawable-xxhdpi │ ├── at.png │ ├── au.png │ ├── br.png │ ├── ca.png │ ├── ch.png │ ├── cl.png │ ├── cn.png │ ├── cz.png │ ├── de.png │ ├── dk.png │ ├── ee.png │ ├── fi.png │ ├── fr.png │ ├── gr.png │ ├── hr.png │ ├── hu.png │ ├── ic_add_white_24dp.png │ ├── ic_launcher.png │ ├── ie.png │ ├── in.png │ ├── is.png │ ├── it.png │ ├── lt.png │ ├── lv.png │ ├── nl.png │ ├── no.png │ ├── nz.png │ ├── se.png │ ├── ua.png │ └── us.png │ ├── drawable-xxxhdpi │ ├── ic_add_white_24dp.png │ └── ic_launcher.png │ ├── drawable │ └── divider.xml │ ├── layout │ ├── about_view.xml │ ├── fragment_listview.xml │ ├── fragment_recyclerview.xml │ ├── fragment_scrollview.xml │ └── list_item.xml │ ├── menu │ └── main.xml │ ├── values-v21 │ └── styles.xml │ └── values │ ├── arrays.xml │ ├── colors.xml │ ├── strings.xml │ └── styles.xml └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # Files for the dex VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # Generated files 12 | bin/ 13 | gen/ 14 | 15 | # Local configuration file (sdk path, etc) 16 | local.properties 17 | 18 | # IntelliJ IDEA 19 | .idea/ 20 | *.iml 21 | *.iws 22 | *.ipr 23 | 24 | # Gradle 25 | .gradle 26 | build/ -------------------------------------------------------------------------------- /LICENSE.MD: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Oleksandr Melnykov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | DEPRECATED 2 | ==================== 3 | 4 | Use the [FloatingActionButton](https://developer.android.com/reference/android/support/design/widget/FloatingActionButton.html) from the support library instead. 5 | 6 | FloatingActionButton 7 | ==================== 8 | 9 | [![Android Arsenal](http://img.shields.io/badge/Android%20Arsenal-makovkastar%2FFloatingActionButton-brightgreen.svg?style=flat)](http://android-arsenal.com/details/1/824) 10 | 11 | ### Description 12 | 13 | Android [floating action button] which reacts on scrolling events. Becomes visible when an attached target is scrolled up and invisible when scrolled down. 14 | 15 | ![Demo](art/demo.gif) 16 | 17 | ### Demo 18 | 19 | [![FloatingActionButton Demo on Google Play Store](http://developer.android.com/images/brand/en_generic_rgb_wo_60.png)](https://play.google.com/store/apps/details?id=com.melnykov.fab.sample) 20 | 21 | ### Integration 22 | 23 | **1)** Add as a dependency to your ``build.gradle``: 24 | 25 | ```groovy 26 | dependencies { 27 | compile 'com.melnykov:floatingactionbutton:1.3.0' 28 | } 29 | ``` 30 | 31 | **2)** Add the ``com.melnykov.fab.FloatingActionButton`` to your layout XML file. The button should be placed in the bottom right corner of the screen. The width and height of the floating action button are hardcoded to **56dp** for the normal and **40dp** for the mini button as specified in the [guidelines]. 32 | 33 | ```xml 34 | 38 | 39 | 43 | 44 | 54 | 55 | ``` 56 | 57 | **3)** Attach the FAB to ``AbsListView``, ``RecyclerView`` or ``ScrollView`` : 58 | 59 | ```java 60 | ListView listView = (ListView) findViewById(android.R.id.list); 61 | FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); 62 | fab.attachToListView(listView); 63 | ``` 64 | 65 | Check the sample project to see how to use custom listeners if you need to track scroll events. 66 | 67 | **4)** Add the namespace ``xmlns:fab="http://schemas.android.com/apk/res-auto"`` to your layout file. 68 | 69 | + Set the button type (normal or mini) via the ``fab_type`` xml attribute (default is normal): 70 | 71 | ```xml 72 | fab:fab_type="mini" 73 | ``` 74 | or 75 | ```java 76 | fab.setType(FloatingActionButton.TYPE_MINI); 77 | ``` 78 | + Set the normal and pressed colors via the xml attributes: 79 | 80 | ```xml 81 | fab:fab_colorNormal="@color/primary" 82 | fab:fab_colorPressed="@color/primary_pressed" 83 | ``` 84 | or 85 | ```java 86 | fab.setColorNormal(getResources().getColor(R.color.primary)); 87 | fab.setColorPressed(getResources().getColor(R.color.primary_pressed)); 88 | ``` 89 | 90 | + Enable/disable the button shadow with the ``fab_shadow`` xml attribite (it's enabled by default): 91 | 92 | ```xml 93 | fab:fab_shadow="false" 94 | ``` 95 | or 96 | ```java 97 | fab.setShadow(false); 98 | ``` 99 | 100 | + Show/hide the button expliciltly: 101 | 102 | ```java 103 | fab.show(); 104 | fab.hide(); 105 | 106 | fab.show(false); // Show without an animation 107 | fab.hide(false); // Hide without an animation 108 | ``` 109 | 110 | + Specify the ripple color for API 21+: 111 | 112 | ```xml 113 | fab:fab_colorRipple="@color/ripple" 114 | ``` 115 | 116 | or 117 | ```java 118 | fab.setColorRipple(getResources().getColor(R.color.ripple)); 119 | ``` 120 | 121 | **5)** Set an icon for the ``FloatingActionButton`` using ``android:src`` xml attribute. Use drawables of size **24dp** as specified by [guidelines]. Icons of desired size can be generated with [Android Asset Studio]. 122 | 123 | ### Changelog 124 | 125 | **Version 1.3.0** 126 | + Add the disabled state for the FAB (thanks to [Aleksey Malevaniy](https://github.com/almozavr)); 127 | + Fix shadow assets. Rename shadow drawables with a prefix; 128 | + Generate default pressed and ripple colors (thanks to [Aidan Follestad](https://github.com/afollestad)). 129 | 130 | **Version 1.2.0** 131 | + Respect an elevation set manually for the FAB; 132 | + Don't emit a scroll when the listview is empty; 133 | + Add an ability to attach normal listeners for scroll operations (thanks to [Bill Donahue](https://github.com/bdonahue)). 134 | 135 | **Version 1.1.0:** 136 | + Do not ignore negative margins on pre-Lollipop; 137 | + Disable clicks on the FAB when it's hidden on pre-Honeycomb; 138 | + Some shadow tuning. 139 | 140 | **Version 1.0.9:** 141 | + Support API 7; 142 | + Fixed extra margins on pre-Lollipop devices; 143 | + Fixed mini FAB size; 144 | + Updated shadow assets to more accurately match 8dp elevation. 145 | 146 | **Version 1.0.8:** 147 | + ATTENTION! Breaking changes for custom listeners. Check an updated sample how to use them. 148 | + Added support for the ``ScrollView``; 149 | + Significantly optimized scroll detection for the ``RecyclerView``; 150 | + Fixed laggy animation for a list view with items of different height; 151 | + Added ``isVisible`` getter; 152 | + Deleted deprecated methods. 153 | 154 | **Version 1.0.7:** 155 | + Updated shadow assets to better match material design guidelines; 156 | + Make ``FabOnScrollListener`` and ``FabRecyclerOnViewScrollListener`` implement ``ScrollDirectionListener`` for easier custom listeners usage. 157 | 158 | **Version 1.0.6:** 159 | + Added support for the ``RecyclerView``; 160 | + Added ripple effect and elevation for API level 21. 161 | 162 | Thanks to [Aidan Follestad](https://github.com/afollestad). 163 | 164 | **Version 1.0.5:** 165 | + Updated shadow to more accurately match the material design spec; 166 | 167 | **Version 1.0.4:** 168 | 169 | + Allow a custom ``OnScrollListeners`` to be attached to a list view; 170 | + Work properly with list of different height rows; 171 | + Ignore tiny shakes of fingers. 172 | 173 | **Version 1.0.3:** 174 | + Add methods to show/hide without animation; 175 | + Fix show/hide when a view is not measured yet. 176 | 177 | 178 | ### Applications using FloatingActionButton 179 | 180 | Please [ping](mailto:makovkastar@gmail.com) me or send a pull request if you would like to be added here. 181 | 182 | Icon | Application | Icon | Application 183 | ------------ | ------------- | ------------- | ------------- 184 | | [Finger Gesture Launcher] | | [Vocabletrainer] 185 | | [Lanekeep GPS Mileage Tracker] | | [Score It] 186 | | [Перезвони мне] | | [App Swap] 187 | | [QKSMS - Quick Text Messenger] | | [Uninstaller - Beta Version] 188 | | [Device Control] | | [Confide] 189 | | [Date Night] | | [Jair Player The Music Rainbow] 190 | | [Taskr - Lista de Tareas] | | [Festivos: ¡Conoce el mundo!] 191 | | [nowPaper] | | [Vicious chain - Don't do that!] 192 | | [My Football Stats] | | [The ScoreBoard] 193 | | [NavPoint] | | [Just Reminder] 194 | | [Early Notes] | | [Ranch - Smart Tip Calculator] 195 | | [Thiengo Calopsita] | | [Tinycore - CPU, RAM monitor] | 196 | | [Battery Aid Saver & Manager] | | [GameRaven] 197 | | [Polaris Office] | | [Call Utils] 198 | | [Colorful Note] | | [CallSticker - заметки звонка] 199 | 200 | ### Links 201 | 202 | Country flag icons used in the sample are taken from www.icondrawer.com 203 | 204 | ### License 205 | 206 | ``` 207 | The MIT License (MIT) 208 | 209 | Copyright (c) 2014 Oleksandr Melnykov 210 | 211 | Permission is hereby granted, free of charge, to any person obtaining a copy 212 | of this software and associated documentation files (the "Software"), to deal 213 | in the Software without restriction, including without limitation the rights 214 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 215 | copies of the Software, and to permit persons to whom the Software is 216 | furnished to do so, subject to the following conditions: 217 | 218 | The above copyright notice and this permission notice shall be included in all 219 | copies or substantial portions of the Software. 220 | 221 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 222 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 223 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 224 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 225 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 226 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 227 | SOFTWARE. 228 | ``` 229 | 230 | [floating action button]:http://www.google.com/design/spec/components/buttons-floating-action-button.html 231 | [guidelines]:http://www.google.com/design/spec/patterns/promoted-actions.html#promoted-actions-floating-action-button 232 | [Android Asset Studio]:http://romannurik.github.io/AndroidAssetStudio/icons-generic.html 233 | [Finger Gesture Launcher]:https://play.google.com/store/apps/details?id=com.carlosdelachica.finger 234 | [Vocabletrainer]:https://play.google.com/store/apps/details?id=com.rubengees.vocables 235 | [Lanekeep GPS Mileage Tracker]:https://play.google.com/store/apps/details?id=me.hanx.android.dashio&hl=en 236 | [Score It]:https://play.google.com/store/apps/details?id=com.sbgapps.scoreit 237 | [Перезвони мне]:https://play.google.com/store/apps/details?id=com.melnykov.callmeback 238 | [App Swap]:https://play.google.com/store/apps/details?id=net.ebt.appswitch 239 | [QKSMS - Quick Text Messenger]:https://play.google.com/store/apps/details?id=com.moez.QKSMS 240 | [Uninstaller - Beta Version]:https://play.google.com/store/apps/details?id=com.kimcy92.uninstaller 241 | [Device Control]:https://play.google.com/store/apps/details?id=org.namelessrom.devicecontrol 242 | [Confide]:https://play.google.com/store/apps/details?id=cm.confide.android 243 | [Date Night]:https://play.google.com/store/apps/details?id=com.sababado.datenight 244 | [Jair Player The Music Rainbow]:https://play.google.com/store/apps/details?id=aj.jair.music 245 | [Taskr - Lista de Tareas]:https://play.google.com/store/apps/details?id=es.udc.gestortareas 246 | [Festivos: ¡Conoce el mundo!]:https://play.google.com/store/apps/details?id=com.logicapps.holidays 247 | [nowPaper]:https://play.google.com/store/apps/details?id=com.dunrite.now 248 | [Vicious chain - Don't do that!]:https://play.google.com/store/apps/details?id=com.magratheadesign.viciouschain 249 | [My Football Stats]:https://play.google.com/store/apps/details?id=com.nicorz.futbol5 250 | [The ScoreBoard]:https://play.google.com/store/apps/details?id=it.pagano.sp 251 | [NavPoint]:https://play.google.com/store/apps/details?id=com.abi_khalil.remy.nav_point 252 | [Just Reminder]:https://play.google.com/store/apps/details?id=com.cray.software.justreminder 253 | [Early Notes]:https://play.google.com/store/apps/details?id=com.gmail.earlynotesapp.earlynotes 254 | [Ranch - Smart Tip Calculator]:https://play.google.com/store/apps/details?id=com.andreifedianov.android.ranch 255 | [Thiengo Calopsita]:https://play.google.com/store/apps/details?id=br.thiengocalopsita 256 | [Tinycore - CPU, RAM monitor]:https://play.google.com/store/apps/details?id=org.neotech.app.tinycore 257 | [Battery Aid Saver & Manager]:https://play.google.com/store/apps/details?id=com.battery.plusfree 258 | [GameRaven]:https://play.google.com/store/apps/details?id=com.ioabsoftware.gameraven 259 | [Polaris Office]:https://play.google.com/store/apps/details?id=com.infraware.office.link 260 | [Call Utils]:https://play.google.com/store/apps/details?id=callutils.com.scimet.admin.callutils&hl=en 261 | [Colorful Note]:https://play.google.com/store/apps/details?id=notes.colorful 262 | [CallSticker - заметки звонка]:https://play.google.com/store/apps/details?id=ru.vpsoft.callnotesticker 263 | -------------------------------------------------------------------------------- /art/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makovkastar/FloatingActionButton/06efd32191812222ea567fe8ae133309112e917f/art/demo.gif -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | mavenCentral() 4 | } 5 | dependencies { 6 | classpath 'com.android.tools.build:gradle:1.1.3' 7 | } 8 | } 9 | 10 | allprojects { 11 | version = VERSION_NAME 12 | group = GROUP 13 | 14 | repositories { 15 | mavenCentral() 16 | } 17 | } -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Settings specified in this file will override any Gradle settings 5 | # configured through the IDE. 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 19 | 20 | VERSION_NAME=1.3.0 21 | VERSION_CODE=13 22 | GROUP=com.melnykov 23 | 24 | ANDROID_BUILD_MIN_SDK_VERSION=7 25 | ANDROID_BUILD_TARGET_SDK_VERSION=22 26 | ANDROID_BUILD_SDK_VERSION=22 27 | ANDROID_BUILD_TOOLS_VERSION=22.0.1 28 | 29 | POM_DESCRIPTION=Android floating action button 30 | POM_URL=https://github.com/makovkastar/FloatingActionButton 31 | POM_SCM_URL=https://github.com/makovkastar/FloatingActionButton 32 | POM_SCM_CONNECTION=scm:git@github.com:makovkastar/FloatingActionButton.git 33 | POM_SCM_DEV_CONNECTION=scm:git@github.com:makovkastar/FloatingActionButton.git 34 | POM_LICENCE_NAME=The MIT License (MIT) 35 | POM_LICENCE_URL=https://github.com/makovkastar/FloatingActionButton/blob/master/LICENSE.MD 36 | POM_LICENCE_DIST=repo 37 | POM_DEVELOPER_ID=makovkastar 38 | POM_DEVELOPER_NAME=Oleksandr Melnykov 39 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makovkastar/FloatingActionButton/06efd32191812222ea567fe8ae133309112e917f/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Nov 24 12:24:27 CET 2014 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.2-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 | -------------------------------------------------------------------------------- /library/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /library/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | repositories { 4 | mavenCentral() 5 | } 6 | 7 | android { 8 | compileSdkVersion Integer.parseInt(project.ANDROID_BUILD_SDK_VERSION) 9 | buildToolsVersion project.ANDROID_BUILD_TOOLS_VERSION 10 | 11 | defaultConfig { 12 | minSdkVersion Integer.parseInt(project.ANDROID_BUILD_MIN_SDK_VERSION) 13 | targetSdkVersion Integer.parseInt(project.ANDROID_BUILD_TARGET_SDK_VERSION) 14 | versionName project.VERSION_NAME 15 | versionCode Integer.parseInt(project.VERSION_CODE) 16 | } 17 | 18 | buildTypes { 19 | release { 20 | minifyEnabled false 21 | } 22 | } 23 | } 24 | 25 | dependencies { 26 | compile 'com.android.support:support-annotations:22.1.0' 27 | compile 'com.android.support:recyclerview-v7:22.1.0@aar' 28 | compile 'com.nineoldandroids:library:2.4.0' 29 | compile 'com.android.support:support-v4:22.1.1@aar' 30 | } 31 | 32 | apply from: 'https://raw.github.com/chrisbanes/gradle-mvn-push/master/gradle-mvn-push.gradle' -------------------------------------------------------------------------------- /library/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_NAME=FloatingActionButton 2 | POM_ARTIFACT_ID=floatingactionbutton 3 | POM_PACKAGING=aar -------------------------------------------------------------------------------- /library/proguard-rules.txt: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in C:/Users/mea/Downloads/adt-bundle-windows-x86_64-20131030/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the ProGuard 5 | # include property in project.properties. 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 | #} -------------------------------------------------------------------------------- /library/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /library/src/main/java/com/melnykov/fab/AbsListViewScrollDetector.java: -------------------------------------------------------------------------------- 1 | package com.melnykov.fab; 2 | 3 | import android.support.annotation.NonNull; 4 | import android.view.View; 5 | import android.widget.AbsListView; 6 | 7 | abstract class AbsListViewScrollDetector implements AbsListView.OnScrollListener { 8 | private int mLastScrollY; 9 | private int mPreviousFirstVisibleItem; 10 | private AbsListView mListView; 11 | private int mScrollThreshold; 12 | 13 | abstract void onScrollUp(); 14 | 15 | abstract void onScrollDown(); 16 | 17 | @Override 18 | public void onScrollStateChanged(AbsListView view, int scrollState) { 19 | } 20 | 21 | @Override 22 | public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { 23 | if(totalItemCount == 0) return; 24 | if (isSameRow(firstVisibleItem)) { 25 | int newScrollY = getTopItemScrollY(); 26 | boolean isSignificantDelta = Math.abs(mLastScrollY - newScrollY) > mScrollThreshold; 27 | if (isSignificantDelta) { 28 | if (mLastScrollY > newScrollY) { 29 | onScrollUp(); 30 | } else { 31 | onScrollDown(); 32 | } 33 | } 34 | mLastScrollY = newScrollY; 35 | } else { 36 | if (firstVisibleItem > mPreviousFirstVisibleItem) { 37 | onScrollUp(); 38 | } else { 39 | onScrollDown(); 40 | } 41 | 42 | mLastScrollY = getTopItemScrollY(); 43 | mPreviousFirstVisibleItem = firstVisibleItem; 44 | } 45 | } 46 | 47 | public void setScrollThreshold(int scrollThreshold) { 48 | mScrollThreshold = scrollThreshold; 49 | } 50 | 51 | public void setListView(@NonNull AbsListView listView) { 52 | mListView = listView; 53 | } 54 | 55 | private boolean isSameRow(int firstVisibleItem) { 56 | return firstVisibleItem == mPreviousFirstVisibleItem; 57 | } 58 | 59 | private int getTopItemScrollY() { 60 | if (mListView == null || mListView.getChildAt(0) == null) return 0; 61 | View topChild = mListView.getChildAt(0); 62 | return topChild.getTop(); 63 | } 64 | } -------------------------------------------------------------------------------- /library/src/main/java/com/melnykov/fab/FloatingActionButton.java: -------------------------------------------------------------------------------- 1 | package com.melnykov.fab; 2 | 3 | import android.animation.AnimatorInflater; 4 | import android.animation.StateListAnimator; 5 | import android.annotation.SuppressLint; 6 | import android.content.Context; 7 | import android.content.res.ColorStateList; 8 | import android.content.res.TypedArray; 9 | import android.graphics.Color; 10 | import android.graphics.Outline; 11 | import android.graphics.drawable.Drawable; 12 | import android.graphics.drawable.LayerDrawable; 13 | import android.graphics.drawable.RippleDrawable; 14 | import android.graphics.drawable.ShapeDrawable; 15 | import android.graphics.drawable.StateListDrawable; 16 | import android.graphics.drawable.shapes.OvalShape; 17 | import android.os.Build; 18 | import android.support.annotation.ColorRes; 19 | import android.support.annotation.DimenRes; 20 | import android.support.annotation.IntDef; 21 | import android.support.annotation.NonNull; 22 | import android.support.v7.widget.RecyclerView; 23 | import android.util.AttributeSet; 24 | import android.view.View; 25 | import android.view.ViewGroup; 26 | import android.view.ViewOutlineProvider; 27 | import android.view.ViewTreeObserver; 28 | import android.view.animation.AccelerateDecelerateInterpolator; 29 | import android.view.animation.Interpolator; 30 | import android.widget.AbsListView; 31 | import android.widget.ImageButton; 32 | import android.widget.ScrollView; 33 | 34 | import com.nineoldandroids.view.ViewHelper; 35 | import com.nineoldandroids.view.ViewPropertyAnimator; 36 | 37 | import java.lang.annotation.Retention; 38 | import java.lang.annotation.RetentionPolicy; 39 | 40 | public class FloatingActionButton extends ImageButton { 41 | private static final int TRANSLATE_DURATION_MILLIS = 200; 42 | 43 | @Retention(RetentionPolicy.SOURCE) 44 | @IntDef({TYPE_NORMAL, TYPE_MINI}) 45 | public @interface TYPE { 46 | } 47 | 48 | public static final int TYPE_NORMAL = 0; 49 | public static final int TYPE_MINI = 1; 50 | 51 | private boolean mVisible; 52 | 53 | private int mColorNormal; 54 | private int mColorPressed; 55 | private int mColorRipple; 56 | private int mColorDisabled; 57 | private boolean mShadow; 58 | private int mType; 59 | 60 | private int mShadowSize; 61 | 62 | private int mScrollThreshold; 63 | 64 | private boolean mMarginsSet; 65 | 66 | private final Interpolator mInterpolator = new AccelerateDecelerateInterpolator(); 67 | 68 | public FloatingActionButton(Context context) { 69 | this(context, null); 70 | } 71 | 72 | public FloatingActionButton(Context context, AttributeSet attrs) { 73 | super(context, attrs); 74 | init(context, attrs); 75 | } 76 | 77 | public FloatingActionButton(Context context, AttributeSet attrs, int defStyle) { 78 | super(context, attrs, defStyle); 79 | init(context, attrs); 80 | } 81 | 82 | @Override 83 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 84 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 85 | int size = getDimension( 86 | mType == TYPE_NORMAL ? R.dimen.fab_size_normal : R.dimen.fab_size_mini); 87 | if (mShadow && !hasLollipopApi()) { 88 | size += mShadowSize * 2; 89 | setMarginsWithoutShadow(); 90 | } 91 | setMeasuredDimension(size, size); 92 | } 93 | 94 | @SuppressLint("NewApi") 95 | private void init(Context context, AttributeSet attributeSet) { 96 | mVisible = true; 97 | mColorNormal = getColor(R.color.material_blue_500); 98 | mColorPressed = darkenColor(mColorNormal); 99 | mColorRipple = lightenColor(mColorNormal); 100 | mColorDisabled = getColor(android.R.color.darker_gray); 101 | mType = TYPE_NORMAL; 102 | mShadow = true; 103 | mScrollThreshold = getResources().getDimensionPixelOffset(R.dimen.fab_scroll_threshold); 104 | mShadowSize = getDimension(R.dimen.fab_shadow_size); 105 | if (hasLollipopApi()) { 106 | StateListAnimator stateListAnimator = AnimatorInflater.loadStateListAnimator(context, 107 | R.anim.fab_press_elevation); 108 | setStateListAnimator(stateListAnimator); 109 | } 110 | if (attributeSet != null) { 111 | initAttributes(context, attributeSet); 112 | } 113 | updateBackground(); 114 | } 115 | 116 | private void initAttributes(Context context, AttributeSet attributeSet) { 117 | TypedArray attr = getTypedArray(context, attributeSet, R.styleable.FloatingActionButton); 118 | if (attr != null) { 119 | try { 120 | mColorNormal = attr.getColor(R.styleable.FloatingActionButton_fab_colorNormal, 121 | getColor(R.color.material_blue_500)); 122 | mColorPressed = attr.getColor(R.styleable.FloatingActionButton_fab_colorPressed, 123 | darkenColor(mColorNormal)); 124 | mColorRipple = attr.getColor(R.styleable.FloatingActionButton_fab_colorRipple, 125 | lightenColor(mColorNormal)); 126 | mColorDisabled = attr.getColor(R.styleable.FloatingActionButton_fab_colorDisabled, 127 | mColorDisabled); 128 | mShadow = attr.getBoolean(R.styleable.FloatingActionButton_fab_shadow, true); 129 | mType = attr.getInt(R.styleable.FloatingActionButton_fab_type, TYPE_NORMAL); 130 | } finally { 131 | attr.recycle(); 132 | } 133 | } 134 | } 135 | 136 | private void updateBackground() { 137 | StateListDrawable drawable = new StateListDrawable(); 138 | drawable.addState(new int[]{android.R.attr.state_pressed}, createDrawable(mColorPressed)); 139 | drawable.addState(new int[]{-android.R.attr.state_enabled}, createDrawable(mColorDisabled)); 140 | drawable.addState(new int[]{}, createDrawable(mColorNormal)); 141 | setBackgroundCompat(drawable); 142 | } 143 | 144 | private Drawable createDrawable(int color) { 145 | OvalShape ovalShape = new OvalShape(); 146 | ShapeDrawable shapeDrawable = new ShapeDrawable(ovalShape); 147 | shapeDrawable.getPaint().setColor(color); 148 | 149 | if (mShadow && !hasLollipopApi()) { 150 | Drawable shadowDrawable = getResources().getDrawable(mType == TYPE_NORMAL ? R.drawable.fab_shadow 151 | : R.drawable.fab_shadow_mini); 152 | LayerDrawable layerDrawable = new LayerDrawable(new Drawable[]{shadowDrawable, shapeDrawable}); 153 | layerDrawable.setLayerInset(1, mShadowSize, mShadowSize, mShadowSize, mShadowSize); 154 | return layerDrawable; 155 | } else { 156 | return shapeDrawable; 157 | } 158 | } 159 | 160 | private TypedArray getTypedArray(Context context, AttributeSet attributeSet, int[] attr) { 161 | return context.obtainStyledAttributes(attributeSet, attr, 0, 0); 162 | } 163 | 164 | private int getColor(@ColorRes int id) { 165 | return getResources().getColor(id); 166 | } 167 | 168 | private int getDimension(@DimenRes int id) { 169 | return getResources().getDimensionPixelSize(id); 170 | } 171 | 172 | private void setMarginsWithoutShadow() { 173 | if (!mMarginsSet) { 174 | if (getLayoutParams() instanceof ViewGroup.MarginLayoutParams) { 175 | ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) getLayoutParams(); 176 | int leftMargin = layoutParams.leftMargin - mShadowSize; 177 | int topMargin = layoutParams.topMargin - mShadowSize; 178 | int rightMargin = layoutParams.rightMargin - mShadowSize; 179 | int bottomMargin = layoutParams.bottomMargin - mShadowSize; 180 | layoutParams.setMargins(leftMargin, topMargin, rightMargin, bottomMargin); 181 | 182 | requestLayout(); 183 | mMarginsSet = true; 184 | } 185 | } 186 | } 187 | 188 | @SuppressWarnings("deprecation") 189 | @SuppressLint("NewApi") 190 | private void setBackgroundCompat(Drawable drawable) { 191 | if (hasLollipopApi()) { 192 | float elevation; 193 | if (mShadow) { 194 | elevation = getElevation() > 0.0f ? getElevation() 195 | : getDimension(R.dimen.fab_elevation_lollipop); 196 | } else { 197 | elevation = 0.0f; 198 | } 199 | setElevation(elevation); 200 | RippleDrawable rippleDrawable = new RippleDrawable(new ColorStateList(new int[][]{{}}, 201 | new int[]{mColorRipple}), drawable, null); 202 | setOutlineProvider(new ViewOutlineProvider() { 203 | @Override 204 | public void getOutline(View view, Outline outline) { 205 | int size = getDimension(mType == TYPE_NORMAL ? R.dimen.fab_size_normal 206 | : R.dimen.fab_size_mini); 207 | outline.setOval(0, 0, size, size); 208 | } 209 | }); 210 | setClipToOutline(true); 211 | setBackground(rippleDrawable); 212 | } else if (hasJellyBeanApi()) { 213 | setBackground(drawable); 214 | } else { 215 | setBackgroundDrawable(drawable); 216 | } 217 | } 218 | 219 | private int getMarginBottom() { 220 | int marginBottom = 0; 221 | final ViewGroup.LayoutParams layoutParams = getLayoutParams(); 222 | if (layoutParams instanceof ViewGroup.MarginLayoutParams) { 223 | marginBottom = ((ViewGroup.MarginLayoutParams) layoutParams).bottomMargin; 224 | } 225 | return marginBottom; 226 | } 227 | 228 | public void setColorNormal(int color) { 229 | if (color != mColorNormal) { 230 | mColorNormal = color; 231 | updateBackground(); 232 | } 233 | } 234 | 235 | public void setColorNormalResId(@ColorRes int colorResId) { 236 | setColorNormal(getColor(colorResId)); 237 | } 238 | 239 | public int getColorNormal() { 240 | return mColorNormal; 241 | } 242 | 243 | public void setColorPressed(int color) { 244 | if (color != mColorPressed) { 245 | mColorPressed = color; 246 | updateBackground(); 247 | } 248 | } 249 | 250 | public void setColorPressedResId(@ColorRes int colorResId) { 251 | setColorPressed(getColor(colorResId)); 252 | } 253 | 254 | public int getColorPressed() { 255 | return mColorPressed; 256 | } 257 | 258 | public void setColorRipple(int color) { 259 | if (color != mColorRipple) { 260 | mColorRipple = color; 261 | updateBackground(); 262 | } 263 | } 264 | 265 | public void setColorRippleResId(@ColorRes int colorResId) { 266 | setColorRipple(getColor(colorResId)); 267 | } 268 | 269 | public int getColorRipple() { 270 | return mColorRipple; 271 | } 272 | 273 | public void setShadow(boolean shadow) { 274 | if (shadow != mShadow) { 275 | mShadow = shadow; 276 | updateBackground(); 277 | } 278 | } 279 | 280 | public boolean hasShadow() { 281 | return mShadow; 282 | } 283 | 284 | public void setType(@TYPE int type) { 285 | if (type != mType) { 286 | mType = type; 287 | updateBackground(); 288 | } 289 | } 290 | 291 | @TYPE 292 | public int getType() { 293 | return mType; 294 | } 295 | 296 | public boolean isVisible() { 297 | return mVisible; 298 | } 299 | 300 | public void show() { 301 | show(true); 302 | } 303 | 304 | public void hide() { 305 | hide(true); 306 | } 307 | 308 | public void show(boolean animate) { 309 | toggle(true, animate, false); 310 | } 311 | 312 | public void hide(boolean animate) { 313 | toggle(false, animate, false); 314 | } 315 | 316 | private void toggle(final boolean visible, final boolean animate, boolean force) { 317 | if (mVisible != visible || force) { 318 | mVisible = visible; 319 | int height = getHeight(); 320 | if (height == 0 && !force) { 321 | ViewTreeObserver vto = getViewTreeObserver(); 322 | if (vto.isAlive()) { 323 | vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { 324 | @Override 325 | public boolean onPreDraw() { 326 | ViewTreeObserver currentVto = getViewTreeObserver(); 327 | if (currentVto.isAlive()) { 328 | currentVto.removeOnPreDrawListener(this); 329 | } 330 | toggle(visible, animate, true); 331 | return true; 332 | } 333 | }); 334 | return; 335 | } 336 | } 337 | int translationY = visible ? 0 : height + getMarginBottom(); 338 | if (animate) { 339 | ViewPropertyAnimator.animate(this).setInterpolator(mInterpolator) 340 | .setDuration(TRANSLATE_DURATION_MILLIS) 341 | .translationY(translationY); 342 | } else { 343 | ViewHelper.setTranslationY(this, translationY); 344 | } 345 | 346 | // On pre-Honeycomb a translated view is still clickable, so we need to disable clicks manually 347 | if (!hasHoneycombApi()) { 348 | setClickable(visible); 349 | } 350 | } 351 | } 352 | 353 | public void attachToListView(@NonNull AbsListView listView) { 354 | attachToListView(listView, null, null); 355 | } 356 | 357 | public void attachToListView(@NonNull AbsListView listView, 358 | ScrollDirectionListener scrollDirectionListener) { 359 | attachToListView(listView, scrollDirectionListener, null); 360 | } 361 | 362 | public void attachToRecyclerView(@NonNull RecyclerView recyclerView) { 363 | attachToRecyclerView(recyclerView, null, null); 364 | } 365 | 366 | public void attachToRecyclerView(@NonNull RecyclerView recyclerView, 367 | ScrollDirectionListener scrollDirectionListener) { 368 | attachToRecyclerView(recyclerView, scrollDirectionListener, null); 369 | } 370 | 371 | public void attachToScrollView(@NonNull ObservableScrollView scrollView) { 372 | attachToScrollView(scrollView, null, null); 373 | } 374 | 375 | public void attachToScrollView(@NonNull ObservableScrollView scrollView, 376 | ScrollDirectionListener scrollDirectionListener) { 377 | attachToScrollView(scrollView, scrollDirectionListener, null); 378 | } 379 | 380 | public void attachToListView(@NonNull AbsListView listView, 381 | ScrollDirectionListener scrollDirectionListener, 382 | AbsListView.OnScrollListener onScrollListener) { 383 | AbsListViewScrollDetectorImpl scrollDetector = new AbsListViewScrollDetectorImpl(); 384 | scrollDetector.setScrollDirectionListener(scrollDirectionListener); 385 | scrollDetector.setOnScrollListener(onScrollListener); 386 | scrollDetector.setListView(listView); 387 | scrollDetector.setScrollThreshold(mScrollThreshold); 388 | listView.setOnScrollListener(scrollDetector); 389 | } 390 | 391 | public void attachToRecyclerView(@NonNull RecyclerView recyclerView, 392 | ScrollDirectionListener scrollDirectionlistener, 393 | RecyclerView.OnScrollListener onScrollListener) { 394 | RecyclerViewScrollDetectorImpl scrollDetector = new RecyclerViewScrollDetectorImpl(); 395 | scrollDetector.setScrollDirectionListener(scrollDirectionlistener); 396 | scrollDetector.setOnScrollListener(onScrollListener); 397 | scrollDetector.setScrollThreshold(mScrollThreshold); 398 | recyclerView.addOnScrollListener(scrollDetector); 399 | } 400 | 401 | public void attachToScrollView(@NonNull ObservableScrollView scrollView, 402 | ScrollDirectionListener scrollDirectionListener, 403 | ObservableScrollView.OnScrollChangedListener onScrollChangedListener) { 404 | ScrollViewScrollDetectorImpl scrollDetector = new ScrollViewScrollDetectorImpl(); 405 | scrollDetector.setScrollDirectionListener(scrollDirectionListener); 406 | scrollDetector.setOnScrollChangedListener(onScrollChangedListener); 407 | scrollDetector.setScrollThreshold(mScrollThreshold); 408 | scrollView.setOnScrollChangedListener(scrollDetector); 409 | } 410 | 411 | private boolean hasLollipopApi() { 412 | return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP; 413 | } 414 | 415 | private boolean hasJellyBeanApi() { 416 | return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN; 417 | } 418 | 419 | private boolean hasHoneycombApi() { 420 | return Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB; 421 | } 422 | 423 | private static int darkenColor(int color) { 424 | float[] hsv = new float[3]; 425 | Color.colorToHSV(color, hsv); 426 | hsv[2] *= 0.9f; 427 | return Color.HSVToColor(hsv); 428 | } 429 | 430 | private static int lightenColor(int color) { 431 | float[] hsv = new float[3]; 432 | Color.colorToHSV(color, hsv); 433 | hsv[2] *= 1.1f; 434 | return Color.HSVToColor(hsv); 435 | } 436 | 437 | private class AbsListViewScrollDetectorImpl extends AbsListViewScrollDetector { 438 | private ScrollDirectionListener mScrollDirectionListener; 439 | private AbsListView.OnScrollListener mOnScrollListener; 440 | 441 | private void setScrollDirectionListener(ScrollDirectionListener scrollDirectionListener) { 442 | mScrollDirectionListener = scrollDirectionListener; 443 | } 444 | 445 | public void setOnScrollListener(AbsListView.OnScrollListener onScrollListener) { 446 | mOnScrollListener = onScrollListener; 447 | } 448 | 449 | @Override 450 | public void onScrollDown() { 451 | show(); 452 | if (mScrollDirectionListener != null) { 453 | mScrollDirectionListener.onScrollDown(); 454 | } 455 | } 456 | 457 | @Override 458 | public void onScrollUp() { 459 | hide(); 460 | if (mScrollDirectionListener != null) { 461 | mScrollDirectionListener.onScrollUp(); 462 | } 463 | } 464 | 465 | @Override 466 | public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, 467 | int totalItemCount) { 468 | if (mOnScrollListener != null) { 469 | mOnScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount); 470 | } 471 | 472 | super.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount); 473 | } 474 | 475 | @Override 476 | public void onScrollStateChanged(AbsListView view, int scrollState) { 477 | if (mOnScrollListener != null) { 478 | mOnScrollListener.onScrollStateChanged(view, scrollState); 479 | } 480 | 481 | super.onScrollStateChanged(view, scrollState); 482 | } 483 | } 484 | 485 | private class RecyclerViewScrollDetectorImpl extends RecyclerViewScrollDetector { 486 | private ScrollDirectionListener mScrollDirectionListener; 487 | private RecyclerView.OnScrollListener mOnScrollListener; 488 | 489 | private void setScrollDirectionListener(ScrollDirectionListener scrollDirectionListener) { 490 | mScrollDirectionListener = scrollDirectionListener; 491 | } 492 | 493 | public void setOnScrollListener(RecyclerView.OnScrollListener onScrollListener) { 494 | mOnScrollListener = onScrollListener; 495 | } 496 | 497 | @Override 498 | public void onScrollDown() { 499 | show(); 500 | if (mScrollDirectionListener != null) { 501 | mScrollDirectionListener.onScrollDown(); 502 | } 503 | } 504 | 505 | @Override 506 | public void onScrollUp() { 507 | hide(); 508 | if (mScrollDirectionListener != null) { 509 | mScrollDirectionListener.onScrollUp(); 510 | } 511 | } 512 | 513 | @Override 514 | public void onScrolled(RecyclerView recyclerView, int dx, int dy) { 515 | if (mOnScrollListener != null) { 516 | mOnScrollListener.onScrolled(recyclerView, dx, dy); 517 | } 518 | 519 | super.onScrolled(recyclerView, dx, dy); 520 | } 521 | 522 | @Override 523 | public void onScrollStateChanged(RecyclerView recyclerView, int newState) { 524 | if (mOnScrollListener != null) { 525 | mOnScrollListener.onScrollStateChanged(recyclerView, newState); 526 | } 527 | 528 | super.onScrollStateChanged(recyclerView, newState); 529 | } 530 | } 531 | 532 | private class ScrollViewScrollDetectorImpl extends ScrollViewScrollDetector { 533 | private ScrollDirectionListener mScrollDirectionListener; 534 | 535 | private ObservableScrollView.OnScrollChangedListener mOnScrollChangedListener; 536 | 537 | private void setScrollDirectionListener(ScrollDirectionListener scrollDirectionListener) { 538 | mScrollDirectionListener = scrollDirectionListener; 539 | } 540 | 541 | public void setOnScrollChangedListener(ObservableScrollView.OnScrollChangedListener onScrollChangedListener) { 542 | mOnScrollChangedListener = onScrollChangedListener; 543 | } 544 | 545 | @Override 546 | public void onScrollDown() { 547 | show(); 548 | if (mScrollDirectionListener != null) { 549 | mScrollDirectionListener.onScrollDown(); 550 | } 551 | } 552 | 553 | @Override 554 | public void onScrollUp() { 555 | hide(); 556 | if (mScrollDirectionListener != null) { 557 | mScrollDirectionListener.onScrollUp(); 558 | } 559 | } 560 | 561 | @Override 562 | public void onScrollChanged(ScrollView who, int l, int t, int oldl, int oldt) { 563 | if (mOnScrollChangedListener != null) { 564 | mOnScrollChangedListener.onScrollChanged(who, l, t, oldl, oldt); 565 | } 566 | 567 | super.onScrollChanged(who, l, t, oldl, oldt); 568 | } 569 | } 570 | } -------------------------------------------------------------------------------- /library/src/main/java/com/melnykov/fab/ObservableScrollView.java: -------------------------------------------------------------------------------- 1 | package com.melnykov.fab; 2 | 3 | 4 | import android.content.Context; 5 | import android.util.AttributeSet; 6 | import android.widget.ScrollView; 7 | 8 | public class ObservableScrollView extends ScrollView { 9 | 10 | public interface OnScrollChangedListener { 11 | void onScrollChanged(ScrollView who, int l, int t, int oldl, int oldt); 12 | } 13 | 14 | private OnScrollChangedListener mOnScrollChangedListener; 15 | 16 | public ObservableScrollView(Context context) { 17 | super(context); 18 | } 19 | 20 | public ObservableScrollView(Context context, AttributeSet attrs) { 21 | super(context, attrs); 22 | } 23 | 24 | public ObservableScrollView(Context context, AttributeSet attrs, int defStyle) { 25 | super(context, attrs, defStyle); 26 | } 27 | 28 | @Override 29 | protected void onScrollChanged(int l, int t, int oldl, int oldt) { 30 | super.onScrollChanged(l, t, oldl, oldt); 31 | if (mOnScrollChangedListener != null) { 32 | mOnScrollChangedListener.onScrollChanged(this, l, t, oldl, oldt); 33 | } 34 | } 35 | 36 | public void setOnScrollChangedListener(OnScrollChangedListener listener) { 37 | mOnScrollChangedListener = listener; 38 | } 39 | } -------------------------------------------------------------------------------- /library/src/main/java/com/melnykov/fab/RecyclerViewScrollDetector.java: -------------------------------------------------------------------------------- 1 | package com.melnykov.fab; 2 | 3 | import android.support.v7.widget.RecyclerView; 4 | 5 | abstract class RecyclerViewScrollDetector extends RecyclerView.OnScrollListener { 6 | private int mScrollThreshold; 7 | 8 | abstract void onScrollUp(); 9 | 10 | abstract void onScrollDown(); 11 | 12 | @Override 13 | public void onScrolled(RecyclerView recyclerView, int dx, int dy) { 14 | boolean isSignificantDelta = Math.abs(dy) > mScrollThreshold; 15 | if (isSignificantDelta) { 16 | if (dy > 0) { 17 | onScrollUp(); 18 | } else { 19 | onScrollDown(); 20 | } 21 | } 22 | } 23 | 24 | public void setScrollThreshold(int scrollThreshold) { 25 | mScrollThreshold = scrollThreshold; 26 | } 27 | } -------------------------------------------------------------------------------- /library/src/main/java/com/melnykov/fab/ScrollDirectionListener.java: -------------------------------------------------------------------------------- 1 | package com.melnykov.fab; 2 | 3 | public interface ScrollDirectionListener { 4 | void onScrollDown(); 5 | 6 | void onScrollUp(); 7 | } -------------------------------------------------------------------------------- /library/src/main/java/com/melnykov/fab/ScrollViewScrollDetector.java: -------------------------------------------------------------------------------- 1 | package com.melnykov.fab; 2 | 3 | import android.widget.ScrollView; 4 | 5 | abstract class ScrollViewScrollDetector implements ObservableScrollView.OnScrollChangedListener { 6 | private int mLastScrollY; 7 | private int mScrollThreshold; 8 | 9 | abstract void onScrollUp(); 10 | 11 | abstract void onScrollDown(); 12 | 13 | @Override 14 | public void onScrollChanged(ScrollView who, int l, int t, int oldl, int oldt) { 15 | boolean isSignificantDelta = Math.abs(t - mLastScrollY) > mScrollThreshold; 16 | if (isSignificantDelta) { 17 | if (t > mLastScrollY) { 18 | onScrollUp(); 19 | } else { 20 | onScrollDown(); 21 | } 22 | } 23 | mLastScrollY = t; 24 | } 25 | 26 | public void setScrollThreshold(int scrollThreshold) { 27 | mScrollThreshold = scrollThreshold; 28 | } 29 | } -------------------------------------------------------------------------------- /library/src/main/res/anim-v21/fab_press_elevation.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 13 | 14 | 15 | 16 | 17 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /library/src/main/res/drawable-hdpi/fab_shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makovkastar/FloatingActionButton/06efd32191812222ea567fe8ae133309112e917f/library/src/main/res/drawable-hdpi/fab_shadow.png -------------------------------------------------------------------------------- /library/src/main/res/drawable-hdpi/fab_shadow_mini.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makovkastar/FloatingActionButton/06efd32191812222ea567fe8ae133309112e917f/library/src/main/res/drawable-hdpi/fab_shadow_mini.png -------------------------------------------------------------------------------- /library/src/main/res/drawable-mdpi/fab_shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makovkastar/FloatingActionButton/06efd32191812222ea567fe8ae133309112e917f/library/src/main/res/drawable-mdpi/fab_shadow.png -------------------------------------------------------------------------------- /library/src/main/res/drawable-mdpi/fab_shadow_mini.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makovkastar/FloatingActionButton/06efd32191812222ea567fe8ae133309112e917f/library/src/main/res/drawable-mdpi/fab_shadow_mini.png -------------------------------------------------------------------------------- /library/src/main/res/drawable-xhdpi/fab_shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makovkastar/FloatingActionButton/06efd32191812222ea567fe8ae133309112e917f/library/src/main/res/drawable-xhdpi/fab_shadow.png -------------------------------------------------------------------------------- /library/src/main/res/drawable-xhdpi/fab_shadow_mini.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makovkastar/FloatingActionButton/06efd32191812222ea567fe8ae133309112e917f/library/src/main/res/drawable-xhdpi/fab_shadow_mini.png -------------------------------------------------------------------------------- /library/src/main/res/drawable-xxhdpi/fab_shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makovkastar/FloatingActionButton/06efd32191812222ea567fe8ae133309112e917f/library/src/main/res/drawable-xxhdpi/fab_shadow.png -------------------------------------------------------------------------------- /library/src/main/res/drawable-xxhdpi/fab_shadow_mini.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makovkastar/FloatingActionButton/06efd32191812222ea567fe8ae133309112e917f/library/src/main/res/drawable-xxhdpi/fab_shadow_mini.png -------------------------------------------------------------------------------- /library/src/main/res/drawable-xxxhdpi/fab_shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makovkastar/FloatingActionButton/06efd32191812222ea567fe8ae133309112e917f/library/src/main/res/drawable-xxxhdpi/fab_shadow.png -------------------------------------------------------------------------------- /library/src/main/res/drawable-xxxhdpi/fab_shadow_mini.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makovkastar/FloatingActionButton/06efd32191812222ea567fe8ae133309112e917f/library/src/main/res/drawable-xxxhdpi/fab_shadow_mini.png -------------------------------------------------------------------------------- /library/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /library/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | #5677fc 6 | -------------------------------------------------------------------------------- /library/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 56dp 5 | 40dp 6 | 12dp 7 | 8 | 4dp 9 | 8dp 10 | 6dp 11 | 12 | -------------------------------------------------------------------------------- /library/src/main/res/values/info_strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Oleksandr Melnykov 7 | https://github.com/makovkastar/FloatingActionButton 8 | 9 | FloatingActionButton 10 | Android Google+ like floating action button which reacts on the list view scrolling events. Becomes visible when the list view is scrolled up and invisible when scrolled down. 11 | https://github.com/makovkastar/FloatingActionButton 12 | 1.0.0 13 | 14 | true 15 | https://github.com/makovkastar/FloatingActionButton 16 | 17 | mit 18 | 19 | -------------------------------------------------------------------------------- /sample.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makovkastar/FloatingActionButton/06efd32191812222ea567fe8ae133309112e917f/sample.apk -------------------------------------------------------------------------------- /sample/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /sample/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion Integer.parseInt(project.ANDROID_BUILD_SDK_VERSION) 5 | buildToolsVersion project.ANDROID_BUILD_TOOLS_VERSION 6 | 7 | defaultConfig { 8 | applicationId 'com.melnykov.fab.sample' 9 | minSdkVersion Integer.parseInt(project.ANDROID_BUILD_MIN_SDK_VERSION) 10 | targetSdkVersion Integer.parseInt(project.ANDROID_BUILD_TARGET_SDK_VERSION) 11 | versionName project.VERSION_NAME 12 | versionCode Integer.parseInt(project.VERSION_CODE) 13 | } 14 | 15 | buildTypes { 16 | release { 17 | minifyEnabled false 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile project(':library') 24 | compile 'com.android.support:appcompat-v7:22.1.0@aar' 25 | compile 'com.android.support:recyclerview-v7:22.1.0@aar' 26 | compile 'com.android.support:support-v4:22.1.0@aar' 27 | } -------------------------------------------------------------------------------- /sample/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 11 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /sample/src/main/java/com/melnykov/fab/sample/DividerItemDecoration.java: -------------------------------------------------------------------------------- 1 | package com.melnykov.fab.sample; 2 | 3 | import android.content.Context; 4 | import android.content.res.TypedArray; 5 | import android.graphics.Canvas; 6 | import android.graphics.Rect; 7 | import android.graphics.drawable.Drawable; 8 | import android.support.v7.widget.LinearLayoutManager; 9 | import android.support.v7.widget.RecyclerView; 10 | import android.view.View; 11 | 12 | /* 13 | * Copyright (C) 2014 The Android Open Source Project 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 class DividerItemDecoration extends RecyclerView.ItemDecoration { 28 | 29 | private static final int[] ATTRS = new int[]{ 30 | android.R.attr.listDivider 31 | }; 32 | 33 | public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL; 34 | 35 | public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL; 36 | 37 | private Drawable mDivider; 38 | 39 | private int mOrientation; 40 | 41 | public DividerItemDecoration(Context context, int orientation) { 42 | final TypedArray a = context.obtainStyledAttributes(ATTRS); 43 | mDivider = a.getDrawable(0); 44 | a.recycle(); 45 | setOrientation(orientation); 46 | } 47 | 48 | public void setOrientation(int orientation) { 49 | if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) { 50 | throw new IllegalArgumentException("invalid orientation"); 51 | } 52 | mOrientation = orientation; 53 | } 54 | 55 | @Override 56 | public void onDraw(Canvas c, RecyclerView parent) { 57 | if (mOrientation == VERTICAL_LIST) { 58 | drawVertical(c, parent); 59 | } else { 60 | drawHorizontal(c, parent); 61 | } 62 | } 63 | 64 | public void drawVertical(Canvas c, RecyclerView parent) { 65 | final int left = parent.getPaddingLeft(); 66 | final int right = parent.getWidth() - parent.getPaddingRight(); 67 | 68 | final int childCount = parent.getChildCount(); 69 | for (int i = 0; i < childCount; i++) { 70 | final View child = parent.getChildAt(i); 71 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child 72 | .getLayoutParams(); 73 | final int top = child.getBottom() + params.bottomMargin; 74 | final int bottom = top + mDivider.getIntrinsicHeight(); 75 | mDivider.setBounds(left, top, right, bottom); 76 | mDivider.draw(c); 77 | } 78 | } 79 | 80 | public void drawHorizontal(Canvas c, RecyclerView parent) { 81 | final int top = parent.getPaddingTop(); 82 | final int bottom = parent.getHeight() - parent.getPaddingBottom(); 83 | 84 | final int childCount = parent.getChildCount(); 85 | for (int i = 0; i < childCount; i++) { 86 | final View child = parent.getChildAt(i); 87 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child 88 | .getLayoutParams(); 89 | final int left = child.getRight() + params.rightMargin; 90 | final int right = left + mDivider.getIntrinsicHeight(); 91 | mDivider.setBounds(left, top, right, bottom); 92 | mDivider.draw(c); 93 | } 94 | } 95 | 96 | @Override 97 | public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) { 98 | if (mOrientation == VERTICAL_LIST) { 99 | outRect.set(0, 0, 0, mDivider.getIntrinsicHeight()); 100 | } else { 101 | outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0); 102 | } 103 | } 104 | } -------------------------------------------------------------------------------- /sample/src/main/java/com/melnykov/fab/sample/ListViewAdapter.java: -------------------------------------------------------------------------------- 1 | package com.melnykov.fab.sample; 2 | 3 | import android.content.Context; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.BaseAdapter; 8 | import android.widget.TextView; 9 | 10 | public class ListViewAdapter extends BaseAdapter { 11 | private final Context mContext; 12 | private final String[] mDataset; 13 | 14 | public ListViewAdapter(Context context, String[] dataset) { 15 | mContext = context; 16 | mDataset = dataset; 17 | } 18 | 19 | @Override 20 | public int getCount() { 21 | return mDataset.length; 22 | } 23 | 24 | @Override 25 | public String getItem(int position) { 26 | return mDataset[position]; 27 | } 28 | 29 | @Override 30 | public long getItemId(int position) { 31 | return position; 32 | } 33 | 34 | @Override 35 | public View getView(int position, View convertView, ViewGroup parent) { 36 | ViewHolder viewHolder; 37 | if (convertView == null) { 38 | convertView = LayoutInflater.from(mContext).inflate(R.layout.list_item, parent, false); 39 | viewHolder = new ViewHolder(); 40 | viewHolder.mTextView = (TextView) convertView.findViewById(android.R.id.text1); 41 | convertView.setTag(viewHolder); 42 | } else { 43 | viewHolder = (ViewHolder) convertView.getTag(); 44 | } 45 | 46 | String[] values = mDataset[position].split(","); 47 | String countryName = values[0]; 48 | int flagResId = mContext.getResources().getIdentifier(values[1], "drawable", mContext.getPackageName()); 49 | viewHolder.mTextView.setText(countryName); 50 | viewHolder.mTextView.setCompoundDrawablesWithIntrinsicBounds(flagResId, 0, 0, 0); 51 | 52 | return convertView; 53 | } 54 | 55 | private static class ViewHolder { 56 | public TextView mTextView; 57 | } 58 | } -------------------------------------------------------------------------------- /sample/src/main/java/com/melnykov/fab/sample/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.melnykov.fab.sample; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.app.AlertDialog; 5 | import android.content.DialogInterface; 6 | import android.os.Bundle; 7 | import android.support.v4.app.Fragment; 8 | import android.support.v4.app.FragmentTransaction; 9 | import android.support.v7.app.ActionBar; 10 | import android.support.v7.app.AppCompatActivity; 11 | import android.support.v7.widget.DefaultItemAnimator; 12 | import android.support.v7.widget.LinearLayoutManager; 13 | import android.support.v7.widget.RecyclerView; 14 | import android.text.Html; 15 | import android.text.method.LinkMovementMethod; 16 | import android.util.Log; 17 | import android.view.LayoutInflater; 18 | import android.view.Menu; 19 | import android.view.MenuItem; 20 | import android.view.View; 21 | import android.view.ViewGroup; 22 | import android.widget.AbsListView; 23 | import android.widget.LinearLayout; 24 | import android.widget.ListView; 25 | import android.widget.TextView; 26 | 27 | import com.melnykov.fab.FloatingActionButton; 28 | import com.melnykov.fab.ObservableScrollView; 29 | import com.melnykov.fab.ScrollDirectionListener; 30 | 31 | public class MainActivity extends AppCompatActivity { 32 | 33 | @Override 34 | protected void onCreate(Bundle savedInstanceState) { 35 | super.onCreate(savedInstanceState); 36 | initActionBar(); 37 | } 38 | 39 | @SuppressWarnings("deprecation") 40 | private void initActionBar() { 41 | if (getSupportActionBar() != null) { 42 | ActionBar actionBar = getSupportActionBar(); 43 | actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); 44 | actionBar.addTab(actionBar.newTab() 45 | .setText("ListView") 46 | .setTabListener(new ActionBar.TabListener() { 47 | @Override 48 | public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) { 49 | fragmentTransaction.replace(android.R.id.content, new ListViewFragment()); 50 | } 51 | 52 | @Override 53 | public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) { 54 | } 55 | 56 | @Override 57 | public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) { 58 | } 59 | })); 60 | actionBar.addTab(actionBar.newTab() 61 | .setText("RecyclerView") 62 | .setTabListener(new ActionBar.TabListener() { 63 | @Override 64 | public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) { 65 | fragmentTransaction.replace(android.R.id.content, new RecyclerViewFragment()); 66 | } 67 | 68 | @Override 69 | public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) { 70 | } 71 | 72 | @Override 73 | public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) { 74 | } 75 | })); 76 | actionBar.addTab(actionBar.newTab() 77 | .setText("ScrollView") 78 | .setTabListener(new ActionBar.TabListener() { 79 | @Override 80 | public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) { 81 | fragmentTransaction.replace(android.R.id.content, new ScrollViewFragment()); 82 | } 83 | 84 | @Override 85 | public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) { 86 | } 87 | 88 | @Override 89 | public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) { 90 | } 91 | })); 92 | } 93 | } 94 | 95 | @Override 96 | public boolean onCreateOptionsMenu(Menu menu) { 97 | getMenuInflater().inflate(R.menu.main, menu); 98 | return super.onCreateOptionsMenu(menu); 99 | } 100 | 101 | @Override 102 | public boolean onOptionsItemSelected(MenuItem item) { 103 | if (item.getItemId() == R.id.about) { 104 | TextView content = (TextView) getLayoutInflater().inflate(R.layout.about_view, null); 105 | content.setMovementMethod(LinkMovementMethod.getInstance()); 106 | content.setText(Html.fromHtml(getString(R.string.about_body))); 107 | new AlertDialog.Builder(this) 108 | .setTitle(R.string.about) 109 | .setView(content) 110 | .setInverseBackgroundForced(true) 111 | .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { 112 | @Override 113 | public void onClick(DialogInterface dialog, int which) { 114 | dialog.dismiss(); 115 | } 116 | }).create().show(); 117 | } 118 | return super.onOptionsItemSelected(item); 119 | } 120 | 121 | public static class ListViewFragment extends Fragment { 122 | 123 | @SuppressLint("InflateParams") 124 | @Override 125 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 126 | View root = inflater.inflate(R.layout.fragment_listview, container, false); 127 | 128 | ListView list = (ListView) root.findViewById(android.R.id.list); 129 | ListViewAdapter listAdapter = new ListViewAdapter(getActivity(), 130 | getResources().getStringArray(R.array.countries)); 131 | list.setAdapter(listAdapter); 132 | 133 | FloatingActionButton fab = (FloatingActionButton) root.findViewById(R.id.fab); 134 | fab.attachToListView(list, new ScrollDirectionListener() { 135 | @Override 136 | public void onScrollDown() { 137 | Log.d("ListViewFragment", "onScrollDown()"); 138 | } 139 | 140 | @Override 141 | public void onScrollUp() { 142 | Log.d("ListViewFragment", "onScrollUp()"); 143 | } 144 | }, new AbsListView.OnScrollListener() { 145 | @Override 146 | public void onScrollStateChanged(AbsListView view, int scrollState) { 147 | Log.d("ListViewFragment", "onScrollStateChanged()"); 148 | } 149 | 150 | @Override 151 | public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { 152 | Log.d("ListViewFragment", "onScroll()"); 153 | } 154 | }); 155 | 156 | return root; 157 | } 158 | } 159 | 160 | public static class RecyclerViewFragment extends Fragment { 161 | @Override 162 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 163 | View root = inflater.inflate(R.layout.fragment_recyclerview, container, false); 164 | 165 | RecyclerView recyclerView = (RecyclerView) root.findViewById(R.id.recycler_view); 166 | recyclerView.setHasFixedSize(true); 167 | recyclerView.setItemAnimator(new DefaultItemAnimator()); 168 | recyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); 169 | recyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), DividerItemDecoration.VERTICAL_LIST)); 170 | 171 | RecyclerViewAdapter adapter = new RecyclerViewAdapter(getActivity(), getResources() 172 | .getStringArray(R.array.countries)); 173 | recyclerView.setAdapter(adapter); 174 | 175 | FloatingActionButton fab = (FloatingActionButton) root.findViewById(R.id.fab); 176 | fab.attachToRecyclerView(recyclerView); 177 | 178 | return root; 179 | } 180 | } 181 | 182 | public static class ScrollViewFragment extends Fragment { 183 | @Override 184 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 185 | View root = inflater.inflate(R.layout.fragment_scrollview, container, false); 186 | 187 | ObservableScrollView scrollView = (ObservableScrollView) root.findViewById(R.id.scroll_view); 188 | LinearLayout list = (LinearLayout) root.findViewById(R.id.list); 189 | 190 | String[] countries = getResources().getStringArray(R.array.countries); 191 | for (String country : countries) { 192 | TextView textView = (TextView) inflater.inflate(R.layout.list_item, container, false); 193 | String[] values = country.split(","); 194 | String countryName = values[0]; 195 | int flagResId = getResources().getIdentifier(values[1], "drawable", getActivity().getPackageName()); 196 | textView.setText(countryName); 197 | textView.setCompoundDrawablesWithIntrinsicBounds(flagResId, 0, 0, 0); 198 | 199 | list.addView(textView); 200 | } 201 | 202 | FloatingActionButton fab = (FloatingActionButton) root.findViewById(R.id.fab); 203 | fab.attachToScrollView(scrollView); 204 | 205 | return root; 206 | } 207 | } 208 | } -------------------------------------------------------------------------------- /sample/src/main/java/com/melnykov/fab/sample/RecyclerViewAdapter.java: -------------------------------------------------------------------------------- 1 | package com.melnykov.fab.sample; 2 | 3 | import android.content.Context; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.view.LayoutInflater; 6 | import android.view.ViewGroup; 7 | import android.widget.TextView; 8 | 9 | public class RecyclerViewAdapter extends RecyclerView.Adapter { 10 | private final Context mContext; 11 | private final String[] mDataset; 12 | 13 | public RecyclerViewAdapter(Context context, String[] dataset) { 14 | mContext = context; 15 | mDataset = dataset; 16 | } 17 | 18 | @Override 19 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 20 | TextView view = (TextView) LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item, parent, false); 21 | return new ViewHolder(view); 22 | } 23 | 24 | @Override 25 | public void onBindViewHolder(ViewHolder viewHolder, int position) { 26 | String[] values = mDataset[position].split(","); 27 | String countryName = values[0]; 28 | int flagResId = mContext.getResources().getIdentifier(values[1], "drawable", mContext.getPackageName()); 29 | viewHolder.mTextView.setText(countryName); 30 | viewHolder.mTextView.setCompoundDrawablesWithIntrinsicBounds(flagResId, 0, 0, 0); 31 | } 32 | 33 | @Override 34 | public int getItemCount() { 35 | return mDataset.length; 36 | } 37 | 38 | public static class ViewHolder extends RecyclerView.ViewHolder { 39 | public TextView mTextView; 40 | 41 | public ViewHolder(TextView v) { 42 | super(v); 43 | mTextView = v; 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /sample/src/main/res/drawable-hdpi/ic_add_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makovkastar/FloatingActionButton/06efd32191812222ea567fe8ae133309112e917f/sample/src/main/res/drawable-hdpi/ic_add_white_24dp.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makovkastar/FloatingActionButton/06efd32191812222ea567fe8ae133309112e917f/sample/src/main/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-mdpi/ic_add_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makovkastar/FloatingActionButton/06efd32191812222ea567fe8ae133309112e917f/sample/src/main/res/drawable-mdpi/ic_add_white_24dp.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makovkastar/FloatingActionButton/06efd32191812222ea567fe8ae133309112e917f/sample/src/main/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-xhdpi/ic_add_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makovkastar/FloatingActionButton/06efd32191812222ea567fe8ae133309112e917f/sample/src/main/res/drawable-xhdpi/ic_add_white_24dp.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makovkastar/FloatingActionButton/06efd32191812222ea567fe8ae133309112e917f/sample/src/main/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-xxhdpi/at.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makovkastar/FloatingActionButton/06efd32191812222ea567fe8ae133309112e917f/sample/src/main/res/drawable-xxhdpi/at.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-xxhdpi/au.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makovkastar/FloatingActionButton/06efd32191812222ea567fe8ae133309112e917f/sample/src/main/res/drawable-xxhdpi/au.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-xxhdpi/br.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makovkastar/FloatingActionButton/06efd32191812222ea567fe8ae133309112e917f/sample/src/main/res/drawable-xxhdpi/br.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-xxhdpi/ca.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makovkastar/FloatingActionButton/06efd32191812222ea567fe8ae133309112e917f/sample/src/main/res/drawable-xxhdpi/ca.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-xxhdpi/ch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makovkastar/FloatingActionButton/06efd32191812222ea567fe8ae133309112e917f/sample/src/main/res/drawable-xxhdpi/ch.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-xxhdpi/cl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makovkastar/FloatingActionButton/06efd32191812222ea567fe8ae133309112e917f/sample/src/main/res/drawable-xxhdpi/cl.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-xxhdpi/cn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makovkastar/FloatingActionButton/06efd32191812222ea567fe8ae133309112e917f/sample/src/main/res/drawable-xxhdpi/cn.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-xxhdpi/cz.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makovkastar/FloatingActionButton/06efd32191812222ea567fe8ae133309112e917f/sample/src/main/res/drawable-xxhdpi/cz.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-xxhdpi/de.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makovkastar/FloatingActionButton/06efd32191812222ea567fe8ae133309112e917f/sample/src/main/res/drawable-xxhdpi/de.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-xxhdpi/dk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makovkastar/FloatingActionButton/06efd32191812222ea567fe8ae133309112e917f/sample/src/main/res/drawable-xxhdpi/dk.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-xxhdpi/ee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makovkastar/FloatingActionButton/06efd32191812222ea567fe8ae133309112e917f/sample/src/main/res/drawable-xxhdpi/ee.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-xxhdpi/fi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makovkastar/FloatingActionButton/06efd32191812222ea567fe8ae133309112e917f/sample/src/main/res/drawable-xxhdpi/fi.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-xxhdpi/fr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makovkastar/FloatingActionButton/06efd32191812222ea567fe8ae133309112e917f/sample/src/main/res/drawable-xxhdpi/fr.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-xxhdpi/gr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makovkastar/FloatingActionButton/06efd32191812222ea567fe8ae133309112e917f/sample/src/main/res/drawable-xxhdpi/gr.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-xxhdpi/hr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makovkastar/FloatingActionButton/06efd32191812222ea567fe8ae133309112e917f/sample/src/main/res/drawable-xxhdpi/hr.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-xxhdpi/hu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makovkastar/FloatingActionButton/06efd32191812222ea567fe8ae133309112e917f/sample/src/main/res/drawable-xxhdpi/hu.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-xxhdpi/ic_add_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makovkastar/FloatingActionButton/06efd32191812222ea567fe8ae133309112e917f/sample/src/main/res/drawable-xxhdpi/ic_add_white_24dp.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makovkastar/FloatingActionButton/06efd32191812222ea567fe8ae133309112e917f/sample/src/main/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-xxhdpi/ie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makovkastar/FloatingActionButton/06efd32191812222ea567fe8ae133309112e917f/sample/src/main/res/drawable-xxhdpi/ie.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-xxhdpi/in.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makovkastar/FloatingActionButton/06efd32191812222ea567fe8ae133309112e917f/sample/src/main/res/drawable-xxhdpi/in.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-xxhdpi/is.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makovkastar/FloatingActionButton/06efd32191812222ea567fe8ae133309112e917f/sample/src/main/res/drawable-xxhdpi/is.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-xxhdpi/it.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makovkastar/FloatingActionButton/06efd32191812222ea567fe8ae133309112e917f/sample/src/main/res/drawable-xxhdpi/it.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-xxhdpi/lt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makovkastar/FloatingActionButton/06efd32191812222ea567fe8ae133309112e917f/sample/src/main/res/drawable-xxhdpi/lt.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-xxhdpi/lv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makovkastar/FloatingActionButton/06efd32191812222ea567fe8ae133309112e917f/sample/src/main/res/drawable-xxhdpi/lv.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-xxhdpi/nl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makovkastar/FloatingActionButton/06efd32191812222ea567fe8ae133309112e917f/sample/src/main/res/drawable-xxhdpi/nl.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-xxhdpi/no.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makovkastar/FloatingActionButton/06efd32191812222ea567fe8ae133309112e917f/sample/src/main/res/drawable-xxhdpi/no.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-xxhdpi/nz.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makovkastar/FloatingActionButton/06efd32191812222ea567fe8ae133309112e917f/sample/src/main/res/drawable-xxhdpi/nz.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-xxhdpi/se.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makovkastar/FloatingActionButton/06efd32191812222ea567fe8ae133309112e917f/sample/src/main/res/drawable-xxhdpi/se.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-xxhdpi/ua.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makovkastar/FloatingActionButton/06efd32191812222ea567fe8ae133309112e917f/sample/src/main/res/drawable-xxhdpi/ua.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-xxhdpi/us.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makovkastar/FloatingActionButton/06efd32191812222ea567fe8ae133309112e917f/sample/src/main/res/drawable-xxhdpi/us.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-xxxhdpi/ic_add_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makovkastar/FloatingActionButton/06efd32191812222ea567fe8ae133309112e917f/sample/src/main/res/drawable-xxxhdpi/ic_add_white_24dp.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makovkastar/FloatingActionButton/06efd32191812222ea567fe8ae133309112e917f/sample/src/main/res/drawable-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable/divider.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/about_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/fragment_listview.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 14 | 15 | 25 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/fragment_recyclerview.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 14 | 15 | 25 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/fragment_scrollview.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 10 | 11 | 18 | 19 | 20 | 30 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/list_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /sample/src/main/res/menu/main.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /sample/src/main/res/values-v21/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | -------------------------------------------------------------------------------- /sample/src/main/res/values/arrays.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Australia,au 5 | Austria,at 6 | Brazil,br 7 | Canada,ca 8 | Chile,cl 9 | China,cn 10 | Croatia,hr 11 | Czech Republic,cz 12 | Denmark,dk 13 | Estonia,ee 14 | Finland,fi 15 | France,fr 16 | Germany,de 17 | Greece,gr 18 | Hungary,hu 19 | Iceland,is 20 | India,in 21 | Ireland,ie 22 | Italy,it 23 | Latvia,lv 24 | Lithuania,lt 25 | Netherlands,nl 26 | New Zealand,nz 27 | Norway,no 28 | Sweden,se 29 | Switzerland,ch 30 | Ukraine,ua 31 | United States,us 32 | 33 | -------------------------------------------------------------------------------- /sample/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3f51b5 4 | #303f9f 5 | #F06292 6 | #E91E63 7 | #C2185B 8 | -------------------------------------------------------------------------------- /sample/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Floating Action Button 4 | About 5 | Oleksandr Melnykov.
7 | https://github.com/makovkastar/FloatingActionButton 8 | ]]>
9 |
-------------------------------------------------------------------------------- /sample/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':library', ':sample' --------------------------------------------------------------------------------