├── .gitignore
├── LICENCE
├── README.md
├── assets
├── circularfab.gif
├── customViews.png
└── customizableButtons.png
├── build.gradle
├── gradle-mvn-push.gradle
├── gradle.properties.sample
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── library
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── oguzdev
│ │ └── circularfloatingactionmenu
│ │ └── library
│ │ └── ApplicationTest.java
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── oguzdev
│ │ └── circularfloatingactionmenu
│ │ └── library
│ │ ├── FloatingActionButton.java
│ │ ├── FloatingActionMenu.java
│ │ ├── SubActionButton.java
│ │ └── animation
│ │ ├── DefaultAnimationHandler.java
│ │ └── MenuAnimationHandler.java
│ └── res
│ ├── drawable-hdpi
│ ├── button_action.png
│ ├── button_action_dark.png
│ ├── button_action_dark_touch.png
│ ├── button_action_touch.png
│ ├── button_sub_action.png
│ ├── button_sub_action_dark.png
│ ├── button_sub_action_dark_touch.png
│ └── button_sub_action_touch.png
│ ├── drawable-mdpi
│ ├── button_action.png
│ ├── button_action_dark.png
│ ├── button_action_dark_touch.png
│ ├── button_action_touch.png
│ ├── button_sub_action.png
│ ├── button_sub_action_dark.png
│ ├── button_sub_action_dark_touch.png
│ └── button_sub_action_touch.png
│ ├── drawable-xhdpi
│ ├── button_action.png
│ ├── button_action_dark.png
│ ├── button_action_dark_touch.png
│ ├── button_action_touch.png
│ ├── button_sub_action.png
│ ├── button_sub_action_dark.png
│ ├── button_sub_action_dark_touch.png
│ └── button_sub_action_touch.png
│ ├── drawable-xxhdpi
│ ├── button_action.png
│ ├── button_action_dark.png
│ ├── button_action_dark_touch.png
│ ├── button_action_touch.png
│ ├── button_sub_action.png
│ ├── button_sub_action_dark.png
│ ├── button_sub_action_dark_touch.png
│ └── button_sub_action_touch.png
│ ├── drawable-xxxhdpi
│ ├── button_action.png
│ ├── button_action_dark.png
│ ├── button_action_dark_touch.png
│ ├── button_action_touch.png
│ ├── button_sub_action.png
│ ├── button_sub_action_dark.png
│ ├── button_sub_action_dark_touch.png
│ └── button_sub_action_touch.png
│ ├── drawable
│ ├── button_action_dark_selector.xml
│ ├── button_action_selector.xml
│ ├── button_sub_action_dark_selector.xml
│ └── button_sub_action_selector.xml
│ └── values
│ └── dimens.xml
├── samples
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── oguzdev
│ │ └── circularfloatingactionmenu
│ │ └── samples
│ │ └── ApplicationTest.java
│ └── main
│ ├── AndroidManifest.xml
│ ├── ic_launcher-web.png
│ ├── java
│ └── com
│ │ └── oguzdev
│ │ └── circularfloatingactionmenu
│ │ └── samples
│ │ ├── DemoActivity.java
│ │ ├── MenuInScrollViewActivity.java
│ │ ├── MenuWithCustomActionButtonActivity.java
│ │ ├── MenuWithCustomAnimationActivity.java
│ │ ├── MenuWithFABActivity.java
│ │ ├── SlideInAnimationHandler.java
│ │ ├── SystemOverlayMenuActivity.java
│ │ └── SystemOverlayMenuService.java
│ └── res
│ ├── drawable-hdpi
│ └── ic_launcher.png
│ ├── drawable-mdpi
│ └── ic_launcher.png
│ ├── drawable-xhdpi
│ └── ic_launcher.png
│ ├── drawable-xxhdpi
│ ├── button_action_blue.png
│ ├── button_action_blue_touch.png
│ ├── button_action_red.png
│ ├── button_action_red_touch.png
│ ├── ic_action_camera.png
│ ├── ic_action_camera_light.png
│ ├── ic_action_cancel.png
│ ├── ic_action_chat.png
│ ├── ic_action_chat_light.png
│ ├── ic_action_headphones.png
│ ├── ic_action_important.png
│ ├── ic_action_location_found.png
│ ├── ic_action_new.png
│ ├── ic_action_new_light.png
│ ├── ic_action_picture.png
│ ├── ic_action_picture_light.png
│ ├── ic_action_place.png
│ ├── ic_action_place_light.png
│ ├── ic_action_send_now.png
│ ├── ic_action_send_now_light.png
│ ├── ic_action_settings.png
│ ├── ic_action_video.png
│ ├── ic_action_video_light.png
│ └── ic_launcher.png
│ ├── drawable
│ ├── bottom_bar_background.xml
│ ├── button_action_blue_selector.xml
│ └── button_action_red_selector.xml
│ ├── layout
│ ├── activity_demo.xml
│ ├── activity_menu_in_scroll_view.xml
│ ├── activity_menu_with_custom_action_button.xml
│ ├── activity_menu_with_custom_animation.xml
│ ├── activity_menu_with_fab.xml
│ ├── activity_menu_with_overlay.xml
│ ├── fragment_demo.xml
│ ├── fragment_menu_with_custom_action_button.xml
│ ├── fragment_menu_with_custom_animation.xml
│ └── item_scroll_view.xml
│ ├── menu
│ ├── demo.xml
│ ├── menu_in_scroll_view.xml
│ ├── menu_with_custom_action_button.xml
│ ├── menu_with_custom_animation.xml
│ ├── menu_with_fab.xml
│ └── sample.xml
│ ├── values-w820dp
│ └── dimens.xml
│ └── values
│ ├── colors.xml
│ ├── dimens.xml
│ ├── strings.xml
│ └── styles.xml
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by http://www.gitignore.io
2 |
3 | ### Java ###
4 | *.class
5 |
6 | # Mobile Tools for Java (J2ME)
7 | .mtj.tmp/
8 |
9 | # Package Files #
10 | !gradle/*.jar
11 | *.war
12 | *.ear
13 |
14 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
15 | hs_err_pid*
16 |
17 |
18 | ### Android ###
19 | # Built application files
20 | *.apk
21 | *.ap_
22 |
23 | # Files for the Dalvik VM
24 | *.dex
25 |
26 | # Java class files
27 | *.class
28 |
29 | # Generated files
30 | bin/
31 | gen/
32 |
33 | # Gradle files
34 | .gradle/
35 | build/
36 |
37 | # Local configuration file (sdk path, etc)
38 | local.properties
39 |
40 | # Proguard folder generated by Eclipse
41 | proguard/
42 |
43 | #Log Files
44 | *.log
45 |
46 |
47 | ### Maven ###
48 | target/
49 | pom.xml.tag
50 | pom.xml.releaseBackup
51 | pom.xml.versionsBackup
52 | pom.xml.next
53 | release.properties
54 |
55 |
56 | ### Intellij ###
57 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm
58 |
59 | ## Directory-based project format
60 | .idea/
61 | # if you remove the above rule, at least ignore user-specific stuff:
62 | # .idea/workspace.xml
63 | # .idea/tasks.xml
64 | # and these sensitive or high-churn files:
65 | # .idea/dataSources.ids
66 | # .idea/dataSources.xml
67 | # .idea/sqlDataSources.xml
68 | # .idea/dynamic.xml
69 |
70 | ## File-based project format
71 | *.ipr
72 | *.iml
73 | *.iws
74 |
75 | ## Additional for IntelliJ
76 | out/
77 |
78 | # generated by mpeltonen/sbt-idea plugin
79 | .idea_modules/
80 |
81 | # generated by JIRA plugin
82 | atlassian-ide-plugin.xml
83 |
84 | # generated by Crashlytics plugin (for Android Studio and Intellij)
85 | com_crashlytics_export_strings.xml
86 |
87 |
88 | ### OSX ###
89 | .DS_Store
90 | .AppleDouble
91 | .LSOverride
92 |
93 | # Icon must end with two \r
94 | Icon
95 |
96 |
97 | # Thumbnails
98 | ._*
99 |
100 | # Files that might appear on external disk
101 | .Spotlight-V100
102 | .Trashes
103 |
104 | # Directories potentially created on remote AFP share
105 | .AppleDB
106 | .AppleDesktop
107 | Network Trash Folder
108 | Temporary Items
109 | .apdisk
110 |
111 |
112 | ### Gradle ###
113 | .gradle
114 | build/
115 |
116 | # Ignore Gradle GUI config
117 | gradle-app.setting
118 |
119 |
120 | gradle.properties
121 |
--------------------------------------------------------------------------------
/LICENCE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Oğuz Bilgener
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
13 | all 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
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # CircularFloatingActionMenu
2 |
3 |
4 |
5 | An animated, customizable circular floating menu for Android, inspired by Path app.
6 |
7 | ## Getting Started
8 | ### Requirements
9 | - API >= 15
10 |
11 | ### Installation
12 | Grab the AAR from Maven Central by adding it as a dependency in your **build.gradle** file:
13 |
14 | ```groovy
15 | dependencies {
16 | compile 'com.oguzdev:CircularFloatingActionMenu:1.0.2'
17 | }
18 | ```
19 | Alternatively, clone the repo and add `library` as a module to your project.
20 |
21 | ### Usage
22 | CircularFloatingActionMenu can be attached to **any view** in your layout. A Floating Action Button implementation is available in the library, with a similar look to new Material Design's FAB.
23 |
24 | 1 - Create a button to attach the menu:
25 |
26 | ```java
27 | // in Activity Context
28 | ImageView icon = new ImageView(this); // Create an icon
29 | icon.setImageDrawable( ... );
30 |
31 | FloatingActionButton actionButton = new FloatingActionButton.Builder(this)
32 | .setContentView(icon)
33 | .build();
34 |
35 | ```
36 |
37 | 2 - Create menu items:
38 |
39 | ```java
40 | SubActionButton.Builder itemBuilder = new SubActionButton.Builder(this);
41 | // repeat many times:
42 | ImageView itemIcon = new ImageView(this);
43 | itemIcon.setImageDrawable( ... );
44 | SubActionButton button1 = itemBuilder.setContentView(itemIcon).build();
45 |
46 | ```
47 |
48 | 3 - Create the menu with the items:
49 |
50 | ```java
51 | FloatingActionMenu actionMenu = new FloatingActionMenu.Builder(this)
52 | .addSubActionView(button1)
53 | .addSubActionView(button2)
54 | // ...
55 | .attachTo(actionButton)
56 | .build();
57 | ```
58 | And you're ready to go!
59 |
60 | ## Customization
61 | **Animations**, **start angle**, **end angle** and **radius** are customizable via `FloatingActionMenu.Builder`.
62 |
63 | `FloatingActionMenu` is the essential class for the menu. Other two classes, `FloatingActionButton` and `SubActionButton` are just **views** and they can be replaced with any other view. You are completely free to create your own menu button and item views.
64 |
65 | Existing `FloatingActionButton` and `SubActionButton` views are customizable too. These parameters can be changed via Builders of both classes:
66 |
67 | - Theme (Light / Dark)
68 | - Background drawable
69 | - LayoutParams (width & height)
70 | - Content View
71 |
72 | `FloatingActionButton` can be placed to one of **8 predefined positions** on the screen. To place it somewhere else, extend it!
73 |
74 |
75 |
76 |
77 | ### Custom Animations
78 | You can write your own animation handler class by extending from `MenuAnimationHandler` to completely customize menu opening and closing animations.
79 |
80 | Then all you need is to create an instance of your custom animation handler and pass it to `FloatingActionMenu.Builder` via `setAnimationHandler( )` method.
81 |
82 | See `CustomAnimationHandler` in **samples** module for a sample animation handler.
83 |
84 | ## Licence
85 | CircularFloatingActionMenu is released under MIT Licence. See file LICENCE.
86 |
--------------------------------------------------------------------------------
/assets/circularfab.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/assets/circularfab.gif
--------------------------------------------------------------------------------
/assets/customViews.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/assets/customViews.png
--------------------------------------------------------------------------------
/assets/customizableButtons.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/assets/customizableButtons.png
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | mavenCentral()
6 | jcenter()
7 | }
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:1.0.0'
10 |
11 | // NOTE: Do not place your application dependencies here; they belong
12 | // in the individual module build.gradle files
13 | }
14 | }
15 |
16 | allprojects {
17 | repositories {
18 | jcenter()
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/gradle-mvn-push.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Chris Banes
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | apply plugin: 'maven'
18 | apply plugin: 'signing'
19 |
20 | def isReleaseBuild() {
21 | return VERSION_NAME.contains("SNAPSHOT") == false
22 | }
23 |
24 | def getReleaseRepositoryUrl() {
25 | return hasProperty('RELEASE_REPOSITORY_URL') ? RELEASE_REPOSITORY_URL
26 | : "https://oss.sonatype.org/service/local/staging/deploy/maven2/"
27 | }
28 |
29 | def getSnapshotRepositoryUrl() {
30 | return hasProperty('SNAPSHOT_REPOSITORY_URL') ? SNAPSHOT_REPOSITORY_URL
31 | : "https://oss.sonatype.org/content/repositories/snapshots/"
32 | }
33 |
34 | def getRepositoryUsername() {
35 | return hasProperty('NEXUS_USERNAME') ? NEXUS_USERNAME : ""
36 | }
37 |
38 | def getRepositoryPassword() {
39 | return hasProperty('NEXUS_PASSWORD') ? NEXUS_PASSWORD : ""
40 | }
41 |
42 | afterEvaluate { project ->
43 | uploadArchives {
44 | repositories {
45 | mavenDeployer {
46 | beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
47 |
48 | pom.groupId = GROUP
49 | pom.artifactId = POM_ARTIFACT_ID
50 | pom.version = VERSION_NAME
51 |
52 | repository(url: getReleaseRepositoryUrl()) {
53 | authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())
54 | }
55 | snapshotRepository(url: getSnapshotRepositoryUrl()) {
56 | authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())
57 | }
58 |
59 | pom.project {
60 | name POM_NAME
61 | packaging POM_PACKAGING
62 | description POM_DESCRIPTION
63 | url POM_URL
64 |
65 | scm {
66 | url POM_SCM_URL
67 | connection POM_SCM_CONNECTION
68 | developerConnection POM_SCM_DEV_CONNECTION
69 | }
70 |
71 | licenses {
72 | license {
73 | name POM_LICENCE_NAME
74 | url POM_LICENCE_URL
75 | distribution POM_LICENCE_DIST
76 | }
77 | }
78 |
79 | developers {
80 | developer {
81 | id POM_DEVELOPER_ID
82 | name POM_DEVELOPER_NAME
83 | }
84 | }
85 | }
86 | }
87 | }
88 | }
89 |
90 | signing {
91 | required { isReleaseBuild() && gradle.taskGraph.hasTask("uploadArchives") }
92 | sign configurations.archives
93 | }
94 |
95 | task androidJavadocs(type: Javadoc) {
96 | source = android.sourceSets.main.java.getSrcDirs() // source = android.sourceSets.main.allJava
97 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
98 | }
99 |
100 | task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) {
101 | classifier = 'javadoc'
102 | from androidJavadocs.destinationDir
103 | }
104 |
105 | task androidSourcesJar(type: Jar) {
106 | classifier = 'sources'
107 | from android.sourceSets.main.java // from android.sourceSets.main.allSource
108 | }
109 |
110 | artifacts {
111 | archives androidSourcesJar
112 | archives androidJavadocsJar
113 | }
114 | }
--------------------------------------------------------------------------------
/gradle.properties.sample:
--------------------------------------------------------------------------------
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.0
21 | VERSION_CODE=1
22 | GROUP=com.oguzdev
23 | POM_DESCRIPTION=CircularFloatingActionButton
24 | POM_URL=https://github.com/oguzbilgener/CircularFloatingActionMenu
25 | POM_SCM_URL=https://github.com/oguzbilgener/CircularFloatingActionMenu
26 | POM_SCM_CONNECTION=scm:git@github.com:oguzbilgener/CircularFloatingActionMenu.git
27 | POM_SCM_DEV_CONNECTION=scm:git@github.com:oguzbilgener/CircularFloatingActionMenu.git
28 | POM_LICENCE_NAME=The MIT Licence (MIT)
29 | POM_LICENCE_URL=http://opensource.org/licenses/MIT
30 | POM_LICENCE_DIST=repo
31 | POM_DEVELOPER_ID=oguzbilgener
32 | POM_DEVELOPER_NAME=Oguz Bilgener
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Apr 10 15:27:10 PDT 2013
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=http\://services.gradle.org/distributions/gradle-2.2.1-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/library/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/library/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 21
5 | buildToolsVersion "21.1.1"
6 |
7 | defaultConfig {
8 | // applicationId "com.oguzdev.circularfloatingactionmenu.library"
9 | minSdkVersion 15
10 | targetSdkVersion 21
11 | versionCode 3
12 | versionName "1.0.2"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | repositories {
23 | maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
24 | mavenCentral()
25 | }
26 |
27 | dependencies {
28 | compile fileTree(dir: 'libs', include: ['*.jar'])
29 | }
30 |
31 | // apply from: '../gradle-mvn-push.gradle'
32 |
--------------------------------------------------------------------------------
/library/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Applications/Android Studio.app/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/library/src/androidTest/java/com/oguzdev/circularfloatingactionmenu/library/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.oguzdev.circularfloatingactionmenu.library;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/library/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/library/src/main/java/com/oguzdev/circularfloatingactionmenu/library/FloatingActionButton.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Oguz Bilgener
3 | */
4 | package com.oguzdev.circularfloatingactionmenu.library;
5 |
6 | import android.app.Activity;
7 | import android.content.Context;
8 | import android.graphics.PixelFormat;
9 | import android.graphics.drawable.Drawable;
10 | import android.os.Build;
11 | import android.view.Gravity;
12 | import android.view.View;
13 | import android.view.ViewGroup;
14 | import android.view.WindowManager;
15 | import android.widget.FrameLayout;
16 |
17 | /**
18 | * An alternative Floating Action Button implementation that can be independently placed in
19 | * one of 8 different places on the screen.
20 | */
21 | public class FloatingActionButton extends FrameLayout {
22 |
23 | public static final int THEME_LIGHT = 0;
24 | public static final int THEME_DARK = 1;
25 |
26 | public static final int POSITION_TOP_CENTER = 1;
27 | public static final int POSITION_TOP_RIGHT = 2;
28 | public static final int POSITION_RIGHT_CENTER = 3;
29 | public static final int POSITION_BOTTOM_RIGHT = 4;
30 | public static final int POSITION_BOTTOM_CENTER = 5;
31 | public static final int POSITION_BOTTOM_LEFT = 6;
32 | public static final int POSITION_LEFT_CENTER = 7;
33 | public static final int POSITION_TOP_LEFT = 8;
34 |
35 | private View contentView;
36 |
37 | private boolean systemOverlay;
38 |
39 | /**
40 | * Constructor that takes parameters collected using {@link FloatingActionMenu.Builder}
41 | * @param context a reference to the current context
42 | * @param layoutParams
43 | * @param theme
44 | * @param backgroundDrawable
45 | * @param position
46 | * @param contentView
47 | * @param contentParams
48 | */
49 | public FloatingActionButton(Context context, ViewGroup.LayoutParams layoutParams, int theme,
50 | Drawable backgroundDrawable, int position, View contentView,
51 | FrameLayout.LayoutParams contentParams,
52 | boolean systemOverlay) {
53 | super(context);
54 | this.systemOverlay = systemOverlay;
55 |
56 | if(!systemOverlay && !(context instanceof Activity)) {
57 | throw new RuntimeException("Given context must be an instance of Activity, "
58 | +"since this FAB is not a systemOverlay.");
59 | }
60 |
61 | setPosition(position, layoutParams);
62 |
63 | // If no custom backgroundDrawable is specified, use the background drawable of the theme.
64 | if(backgroundDrawable == null) {
65 | if(theme == THEME_LIGHT)
66 | backgroundDrawable = context.getResources().getDrawable(R.drawable.button_action_selector);
67 | else
68 | backgroundDrawable = context.getResources().getDrawable(R.drawable.button_action_dark_selector);
69 | }
70 | setBackgroundResource(backgroundDrawable);
71 | if(contentView != null) {
72 | setContentView(contentView, contentParams);
73 | }
74 | setClickable(true);
75 |
76 | attach(layoutParams);
77 | }
78 |
79 | /**
80 | * Sets the position of the button by calculating its Gravity from the position parameter
81 | * @param position one of 8 specified positions.
82 | * @param layoutParams should be either FrameLayout.LayoutParams or WindowManager.LayoutParams
83 | */
84 | public void setPosition(int position, ViewGroup.LayoutParams layoutParams) {
85 |
86 | boolean setDefaultMargin = false;
87 |
88 | int gravity;
89 | switch (position) {
90 | case POSITION_TOP_CENTER:
91 | gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL;
92 | break;
93 | case POSITION_TOP_RIGHT:
94 | gravity = Gravity.TOP | Gravity.RIGHT;
95 | break;
96 | case POSITION_RIGHT_CENTER:
97 | gravity = Gravity.RIGHT | Gravity.CENTER_VERTICAL;
98 | break;
99 | case POSITION_BOTTOM_CENTER:
100 | gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
101 | break;
102 | case POSITION_BOTTOM_LEFT:
103 | gravity = Gravity.BOTTOM | Gravity.LEFT;
104 | break;
105 | case POSITION_LEFT_CENTER:
106 | gravity = Gravity.LEFT | Gravity.CENTER_VERTICAL;
107 | break;
108 | case POSITION_TOP_LEFT:
109 | gravity = Gravity.TOP | Gravity.LEFT;
110 | break;
111 | case POSITION_BOTTOM_RIGHT:
112 | default:
113 | setDefaultMargin = true;
114 | gravity = Gravity.BOTTOM | Gravity.RIGHT;
115 | break;
116 | }
117 | if(!systemOverlay) {
118 | try {
119 | FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) layoutParams;
120 | lp.gravity = gravity;
121 | setLayoutParams(lp);
122 | } catch (ClassCastException e) {
123 | throw new ClassCastException("layoutParams must be an instance of " +
124 | "FrameLayout.LayoutParams, since this FAB is not a systemOverlay");
125 | }
126 | }
127 | else {
128 | try {
129 | WindowManager.LayoutParams lp = (WindowManager.LayoutParams) layoutParams;
130 | lp.gravity = gravity;
131 | if(setDefaultMargin) {
132 | int margin = getContext().getResources().getDimensionPixelSize(R.dimen.action_button_margin);
133 | lp.x = margin;
134 | lp.y = margin;
135 | }
136 | setLayoutParams(lp);
137 | } catch(ClassCastException e) {
138 | throw new ClassCastException("layoutParams must be an instance of " +
139 | "WindowManager.LayoutParams, since this FAB is a systemOverlay");
140 | }
141 | }
142 | }
143 |
144 | /**
145 | * Sets a content view that will be displayed inside this FloatingActionButton.
146 | * @param contentView
147 | */
148 | public void setContentView(View contentView, FrameLayout.LayoutParams contentParams) {
149 | this.contentView = contentView;
150 | FrameLayout.LayoutParams params;
151 | if(contentParams == null ){
152 | params = new FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, Gravity.CENTER);
153 | final int margin = getResources().getDimensionPixelSize(R.dimen.action_button_content_margin);
154 | params.setMargins(margin, margin, margin, margin);
155 | }
156 | else {
157 | params = contentParams;
158 | }
159 | params.gravity = Gravity.CENTER;
160 |
161 | contentView.setClickable(false);
162 | this.addView(contentView, params);
163 | }
164 |
165 | /**
166 | * Attaches it to the content view with specified LayoutParams.
167 | * @param layoutParams
168 | */
169 | public void attach(ViewGroup.LayoutParams layoutParams) {
170 | if(systemOverlay) {
171 | try {
172 | getWindowManager().addView(this, layoutParams);
173 | }
174 | catch(SecurityException e) {
175 | throw new SecurityException("Your application must have SYSTEM_ALERT_WINDOW " +
176 | "permission to create a system window.");
177 | }
178 | }
179 | else {
180 | ((ViewGroup) getActivityContentView()).addView(this, layoutParams);
181 | }
182 | }
183 |
184 | /**
185 | * Detaches it from the container view.
186 | */
187 | public void detach() {
188 | if(systemOverlay) {
189 | getWindowManager().removeView(this);
190 | }
191 | else {
192 | ((ViewGroup) getActivityContentView()).removeView(this);
193 | }
194 | }
195 |
196 | /**
197 | * Finds and returns the main content view from the Activity context.
198 | * @return the main content view
199 | */
200 | public View getActivityContentView() {
201 | try {
202 | return ((Activity) getContext()).getWindow().getDecorView().findViewById(android.R.id.content);
203 | }
204 | catch(ClassCastException e) {
205 | throw new ClassCastException("Please provide an Activity context for this FloatingActionButton.");
206 | }
207 | }
208 |
209 | public WindowManager getWindowManager() {
210 | return (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
211 | }
212 |
213 | private void setBackgroundResource(Drawable drawable) {
214 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
215 | setBackground(drawable);
216 | }
217 | else {
218 | setBackgroundDrawable(drawable);
219 | }
220 | }
221 |
222 | /**
223 | * A builder for {@link FloatingActionButton} in conventional Java Builder format
224 | */
225 | public static class Builder {
226 |
227 | private Context context;
228 | private ViewGroup.LayoutParams layoutParams;
229 | private int theme;
230 | private Drawable backgroundDrawable;
231 | private int position;
232 | private View contentView;
233 | private LayoutParams contentParams;
234 | private boolean systemOverlay;
235 |
236 | public Builder(Context context) {
237 | this.context = context;
238 |
239 | // Default FloatingActionButton settings
240 | int size = context.getResources().getDimensionPixelSize(R.dimen.action_button_size);
241 | int margin = context.getResources().getDimensionPixelSize(R.dimen.action_button_margin);
242 | FrameLayout.LayoutParams layoutParams = new LayoutParams(size, size, Gravity.BOTTOM | Gravity.RIGHT);
243 | layoutParams.setMargins(margin, margin, margin, margin);
244 | setLayoutParams(layoutParams);
245 | setTheme(FloatingActionButton.THEME_LIGHT);
246 | setPosition(FloatingActionButton.POSITION_BOTTOM_RIGHT);
247 | setSystemOverlay(false);
248 | }
249 |
250 | public Builder setLayoutParams(ViewGroup.LayoutParams params) {
251 | this.layoutParams = params;
252 | return this;
253 | }
254 |
255 | public Builder setTheme(int theme) {
256 | this.theme = theme;
257 | return this;
258 | }
259 |
260 | public Builder setBackgroundDrawable(Drawable backgroundDrawable) {
261 | this.backgroundDrawable = backgroundDrawable;
262 | return this;
263 | }
264 |
265 | public Builder setBackgroundDrawable(int drawableId) {
266 | return setBackgroundDrawable(context.getResources().getDrawable(drawableId));
267 | }
268 |
269 | public Builder setPosition(int position) {
270 | this.position = position;
271 | return this;
272 | }
273 |
274 | public Builder setContentView(View contentView) {
275 | return setContentView(contentView, null);
276 | }
277 |
278 | public Builder setContentView(View contentView, LayoutParams contentParams) {
279 | this.contentView = contentView;
280 | this.contentParams = contentParams;
281 | return this;
282 | }
283 |
284 | public Builder setSystemOverlay(boolean systemOverlay) {
285 | this.systemOverlay = systemOverlay;
286 | return this;
287 | }
288 |
289 | public FloatingActionButton build() {
290 | return new FloatingActionButton(context,
291 | layoutParams,
292 | theme,
293 | backgroundDrawable,
294 | position,
295 | contentView,
296 | contentParams,
297 | systemOverlay);
298 | }
299 |
300 | public static WindowManager.LayoutParams getDefaultSystemWindowParams(Context context) {
301 | int size = context.getResources().getDimensionPixelSize(R.dimen.action_button_size);
302 | WindowManager.LayoutParams params = new WindowManager.LayoutParams(
303 | size,
304 | size,
305 | WindowManager.LayoutParams.TYPE_SYSTEM_ALERT, // z-ordering
306 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
307 | PixelFormat.TRANSLUCENT);
308 | params.format = PixelFormat.RGBA_8888;
309 | params.gravity = Gravity.TOP | Gravity.LEFT;
310 | return params;
311 | }
312 | }
313 | }
314 |
--------------------------------------------------------------------------------
/library/src/main/java/com/oguzdev/circularfloatingactionmenu/library/FloatingActionMenu.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Oguz Bilgener
3 | */
4 | package com.oguzdev.circularfloatingactionmenu.library;
5 |
6 | import android.app.Activity;
7 | import android.content.Context;
8 | import android.graphics.Path;
9 | import android.graphics.PathMeasure;
10 | import android.graphics.PixelFormat;
11 | import android.graphics.Point;
12 | import android.graphics.Rect;
13 | import android.graphics.RectF;
14 | import android.hardware.SensorManager;
15 | import android.view.Display;
16 | import android.view.Gravity;
17 | import android.view.LayoutInflater;
18 | import android.view.OrientationEventListener;
19 | import android.view.View;
20 | import android.view.ViewGroup;
21 | import android.view.WindowManager;
22 | import android.widget.FrameLayout;
23 |
24 | import com.oguzdev.circularfloatingactionmenu.library.animation.DefaultAnimationHandler;
25 | import com.oguzdev.circularfloatingactionmenu.library.animation.MenuAnimationHandler;
26 |
27 | import java.util.ArrayList;
28 | import java.util.List;
29 |
30 | /**
31 | * Provides the main structure of the menu.
32 | */
33 |
34 | public class FloatingActionMenu {
35 |
36 | /** Reference to the view (usually a button) to trigger the menu to show */
37 | private View mainActionView;
38 | /** The angle (in degrees, modulus 360) which the circular menu starts from */
39 | private int startAngle;
40 | /** The angle (in degrees, modulus 360) which the circular menu ends at */
41 | private int endAngle;
42 | /** Distance of menu items from mainActionView */
43 | private int radius;
44 | /** List of menu items */
45 | private List- subActionItems;
46 | /** Reference to the preferred {@link MenuAnimationHandler} object */
47 | private MenuAnimationHandler animationHandler;
48 | /** Reference to a listener that listens open/close actions */
49 | private MenuStateChangeListener stateChangeListener;
50 | /** whether the openings and closings should be animated or not */
51 | private boolean animated;
52 | /** whether the menu is currently open or not */
53 | private boolean open;
54 | /** whether the menu is an overlay for all other activities */
55 | private boolean systemOverlay;
56 | /** a simple layout to contain all the sub action views in the system overlay mode */
57 | private FrameLayout overlayContainer;
58 |
59 | private OrientationEventListener orientationListener;
60 |
61 | /**
62 | * Constructor that takes the parameters collected using {@link FloatingActionMenu.Builder}
63 | * @param mainActionView
64 | * @param startAngle
65 | * @param endAngle
66 | * @param radius
67 | * @param subActionItems
68 | * @param animationHandler
69 | * @param animated
70 | */
71 | public FloatingActionMenu(final View mainActionView,
72 | int startAngle,
73 | int endAngle,
74 | int radius,
75 | List
- subActionItems,
76 | MenuAnimationHandler animationHandler,
77 | boolean animated,
78 | MenuStateChangeListener stateChangeListener,
79 | final boolean systemOverlay) {
80 | this.mainActionView = mainActionView;
81 | this.startAngle = startAngle;
82 | this.endAngle = endAngle;
83 | this.radius = radius;
84 | this.subActionItems = subActionItems;
85 | this.animationHandler = animationHandler;
86 | this.animated = animated;
87 | this.systemOverlay = systemOverlay;
88 | // The menu is initially closed.
89 | this.open = false;
90 |
91 | this.stateChangeListener = stateChangeListener;
92 |
93 | // Listen click events on the main action view
94 | // In the future, touch and drag events could be listened to offer an alternative behaviour
95 | this.mainActionView.setClickable(true);
96 | this.mainActionView.setOnClickListener(new ActionViewClickListener());
97 |
98 | // Do not forget to set the menu as self to our customizable animation handler
99 | if(animationHandler != null) {
100 | animationHandler.setMenu(this);
101 | }
102 |
103 | if(systemOverlay) {
104 | overlayContainer = new FrameLayout(mainActionView.getContext());
105 | }
106 | else {
107 | overlayContainer = null; // beware NullPointerExceptions!
108 | }
109 |
110 | // Find items with undefined sizes
111 | for(final Item item : subActionItems) {
112 | if(item.width == 0 || item.height == 0) {
113 | if(systemOverlay) {
114 | throw new RuntimeException("Sub action views cannot be added without " +
115 | "definite width and height.");
116 | }
117 | // Figure out the size by temporarily adding it to the Activity content view hierarchy
118 | // and ask the size from the system
119 | addViewToCurrentContainer(item.view);
120 | // Make item view invisible, just in case
121 | item.view.setAlpha(0);
122 | // Wait for the right time
123 | item.view.post(new ItemViewQueueListener(item));
124 | }
125 | }
126 |
127 | if(systemOverlay) {
128 | orientationListener = new OrientationEventListener(mainActionView.getContext(), SensorManager.SENSOR_DELAY_UI) {
129 | private int lastState = -1;
130 |
131 | public void onOrientationChanged(int orientation) {
132 |
133 | Display display = getWindowManager().getDefaultDisplay();
134 | if(display.getRotation() != lastState) {
135 | lastState = display.getRotation();
136 |
137 | //
138 | if(isOpen()) {
139 | close(false);
140 | }
141 | }
142 | }
143 | };
144 | orientationListener.enable();
145 | }
146 | }
147 |
148 | /**
149 | * Simply opens the menu by doing necessary calculations.
150 | * @param animated if true, this action is executed by the current {@link MenuAnimationHandler}
151 | */
152 | public void open(boolean animated) {
153 |
154 | // Get the center of the action view from the following function for efficiency
155 | // populate destination x,y coordinates of Items
156 | Point center = calculateItemPositions();
157 |
158 | WindowManager.LayoutParams overlayParams = null;
159 |
160 | if(systemOverlay) {
161 | // If this is a system overlay menu, use the overlay container and place it behind
162 | // the main action button so that all the views will be added into it.
163 | attachOverlayContainer();
164 |
165 | overlayParams = (WindowManager.LayoutParams) overlayContainer.getLayoutParams();
166 | }
167 |
168 | if(animated && animationHandler != null) {
169 | // If animations are enabled and we have a MenuAnimationHandler, let it do the heavy work
170 | if(animationHandler.isAnimating()) {
171 | // Do not proceed if there is an animation currently going on.
172 | return;
173 | }
174 |
175 | for (int i = 0; i < subActionItems.size(); i++) {
176 | // It is required that these Item views are not currently added to any parent
177 | // Because they are supposed to be added to the Activity content view,
178 | // just before the animation starts
179 | if (subActionItems.get(i).view.getParent() != null) {
180 | throw new RuntimeException("All of the sub action items have to be independent from a parent.");
181 | }
182 |
183 | // Initially, place all items right at the center of the main action view
184 | // Because they are supposed to start animating from that point.
185 | final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(subActionItems.get(i).width, subActionItems.get(i).height, Gravity.TOP | Gravity.LEFT);
186 |
187 | if(systemOverlay) {
188 | params.setMargins(center.x - overlayParams.x - subActionItems.get(i).width / 2, center.y - overlayParams.y - subActionItems.get(i).height / 2, 0, 0);
189 | }
190 | else {
191 | params.setMargins(center.x - subActionItems.get(i).width / 2, center.y - subActionItems.get(i).height / 2, 0, 0);
192 | }
193 | addViewToCurrentContainer(subActionItems.get(i).view, params);
194 | }
195 | // Tell the current MenuAnimationHandler to animate from the center
196 | animationHandler.animateMenuOpening(center);
197 | }
198 | else {
199 | // If animations are disabled, just place each of the items to their calculated destination positions.
200 | for (int i = 0; i < subActionItems.size(); i++) {
201 | // This is currently done by giving them large margins
202 |
203 | final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(subActionItems.get(i).width, subActionItems.get(i).height, Gravity.TOP | Gravity.LEFT);
204 | if(systemOverlay) {
205 | params.setMargins(subActionItems.get(i).x - overlayParams.x, subActionItems.get(i).y - overlayParams.y, 0, 0);
206 | subActionItems.get(i).view.setLayoutParams(params);
207 | }
208 | else {
209 | params.setMargins(subActionItems.get(i).x, subActionItems.get(i).y, 0, 0);
210 | subActionItems.get(i).view.setLayoutParams(params);
211 | // Because they are placed into the main content view of the Activity,
212 | // which is itself a FrameLayout
213 | }
214 | addViewToCurrentContainer(subActionItems.get(i).view, params);
215 | }
216 | }
217 | // do not forget to specify that the menu is open.
218 | open = true;
219 |
220 | if(stateChangeListener != null) {
221 | stateChangeListener.onMenuOpened(this);
222 | }
223 |
224 | }
225 |
226 | /**
227 | * Closes the menu.
228 | * @param animated if true, this action is executed by the current {@link MenuAnimationHandler}
229 | */
230 | public void close(boolean animated) {
231 | // If animations are enabled and we have a MenuAnimationHandler, let it do the heavy work
232 | if(animated && animationHandler != null) {
233 | if(animationHandler.isAnimating()) {
234 | // Do not proceed if there is an animation currently going on.
235 | return;
236 | }
237 | animationHandler.animateMenuClosing(getActionViewCenter());
238 | }
239 | else {
240 | // If animations are disabled, just detach each of the Item views from the Activity content view.
241 | for (int i = 0; i < subActionItems.size(); i++) {
242 | removeViewFromCurrentContainer(subActionItems.get(i).view);
243 | }
244 | detachOverlayContainer();
245 | }
246 | // do not forget to specify that the menu is now closed.
247 | open = false;
248 |
249 | if(stateChangeListener != null) {
250 | stateChangeListener.onMenuClosed(this);
251 | }
252 | }
253 |
254 | /**
255 | * Toggles the menu
256 | * @param animated if true, the open/close action is executed by the current {@link MenuAnimationHandler}
257 | */
258 | public void toggle(boolean animated) {
259 | if(open) {
260 | close(animated);
261 | }
262 | else {
263 | open(animated);
264 | }
265 | }
266 |
267 | /**
268 | * @return whether the menu is open or not
269 | */
270 | public boolean isOpen() {
271 | return open;
272 | }
273 |
274 | /**
275 | * @return whether the menu is a system overlay or not
276 | */
277 | public boolean isSystemOverlay() {
278 | return systemOverlay;
279 | }
280 |
281 | public FrameLayout getOverlayContainer() {
282 | return overlayContainer;
283 | }
284 |
285 | /**
286 | * Recalculates the positions of each sub action item on demand.
287 | */
288 | public void updateItemPositions() {
289 | // Only update if the menu is currently open
290 | if(!isOpen()) {
291 | return;
292 | }
293 | // recalculate x,y coordinates of Items
294 | calculateItemPositions();
295 |
296 | // Simply update layout params for each item
297 | for (int i = 0; i < subActionItems.size(); i++) {
298 | // This is currently done by giving them large margins
299 | final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(subActionItems.get(i).width, subActionItems.get(i).height, Gravity.TOP | Gravity.LEFT);
300 | params.setMargins(subActionItems.get(i).x, subActionItems.get(i).y, 0, 0);
301 | subActionItems.get(i).view.setLayoutParams(params);
302 | }
303 | }
304 |
305 | /**
306 | * Gets the coordinates of the main action view
307 | * This method should only be called after the main layout of the Activity is drawn,
308 | * such as when a user clicks the action button.
309 | * @return a Point containing x and y coordinates of the top left corner of action view
310 | */
311 | private Point getActionViewCoordinates() {
312 | int[] coords = new int[2];
313 | // This method returns a x and y values that can be larger than the dimensions of the device screen.
314 | mainActionView.getLocationOnScreen(coords);
315 |
316 | // So, we need to deduce the offsets.
317 | if(systemOverlay) {
318 | coords[1] -= getStatusBarHeight();
319 | }
320 | else {
321 | Rect activityFrame = new Rect();
322 | getActivityContentView().getWindowVisibleDisplayFrame(activityFrame);
323 | coords[0] -= (getScreenSize().x - getActivityContentView().getMeasuredWidth());
324 | coords[1] -= (activityFrame.height() + activityFrame.top - getActivityContentView().getMeasuredHeight());
325 | }
326 | return new Point(coords[0], coords[1]);
327 | }
328 |
329 | /**
330 | * Returns the center point of the main action view
331 | * @return the action view center point
332 | */
333 | public Point getActionViewCenter() {
334 | Point point = getActionViewCoordinates();
335 | point.x += mainActionView.getMeasuredWidth() / 2;
336 | point.y += mainActionView.getMeasuredHeight() / 2;
337 | return point;
338 | }
339 |
340 | /**
341 | * Calculates the desired positions of all items.
342 | * @return getActionViewCenter()
343 | */
344 | private Point calculateItemPositions() {
345 | // Create an arc that starts from startAngle and ends at endAngle
346 | // in an area that is as large as 4*radius^2
347 | final Point center = getActionViewCenter();
348 | RectF area = new RectF(center.x - radius, center.y - radius, center.x + radius, center.y + radius);
349 |
350 | Path orbit = new Path();
351 | orbit.addArc(area, startAngle, endAngle - startAngle);
352 |
353 | PathMeasure measure = new PathMeasure(orbit, false);
354 |
355 | // Prevent overlapping when it is a full circle
356 | int divisor;
357 | if(Math.abs(endAngle - startAngle) >= 360 || subActionItems.size() <= 1) {
358 | divisor = subActionItems.size();
359 | }
360 | else {
361 | divisor = subActionItems.size() -1;
362 | }
363 |
364 | // Measure this path, in order to find points that have the same distance between each other
365 | for(int i=0; i getSubActionItems() {
386 | return subActionItems;
387 | }
388 |
389 | /**
390 | * Finds and returns the main content view from the Activity context.
391 | * @return the main content view
392 | */
393 | public View getActivityContentView() {
394 | try {
395 | return ((Activity) mainActionView.getContext()).getWindow().getDecorView().findViewById(android.R.id.content);
396 | }
397 | catch(ClassCastException e) {
398 | throw new ClassCastException("Please provide an Activity context for this FloatingActionMenu.");
399 | }
400 | }
401 |
402 | /**
403 | * Intended to use for systemOverlay mode.
404 | * @return the WindowManager for the current context.
405 | */
406 | public WindowManager getWindowManager() {
407 | return (WindowManager) mainActionView.getContext().getSystemService(Context.WINDOW_SERVICE);
408 | }
409 |
410 | private void addViewToCurrentContainer(View view, ViewGroup.LayoutParams layoutParams) {
411 | if(systemOverlay) {
412 | overlayContainer.addView(view, layoutParams);
413 | }
414 | else {
415 | try {
416 | if(layoutParams != null) {
417 | FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) layoutParams;
418 | ((ViewGroup) getActivityContentView()).addView(view, lp);
419 | }
420 | else {
421 | ((ViewGroup) getActivityContentView()).addView(view);
422 | }
423 | }
424 | catch(ClassCastException e) {
425 | throw new ClassCastException("layoutParams must be an instance of " +
426 | "FrameLayout.LayoutParams.");
427 | }
428 | }
429 | }
430 |
431 | public void attachOverlayContainer() {
432 | try {
433 | WindowManager.LayoutParams overlayParams = calculateOverlayContainerParams();
434 |
435 | overlayContainer.setLayoutParams(overlayParams);
436 | if(overlayContainer.getParent() == null) {
437 | getWindowManager().addView(overlayContainer, overlayParams);
438 | }
439 | getWindowManager().updateViewLayout(mainActionView, mainActionView.getLayoutParams());
440 | }
441 | catch(SecurityException e) {
442 | throw new SecurityException("Your application must have SYSTEM_ALERT_WINDOW " +
443 | "permission to create a system window.");
444 | }
445 | }
446 |
447 | private WindowManager.LayoutParams calculateOverlayContainerParams() {
448 | // calculate the minimum viable size of overlayContainer
449 | WindowManager.LayoutParams overlayParams = getDefaultSystemWindowParams();
450 | int left = 9999, right = 0, top = 9999, bottom = 0;
451 | for(int i=0; i < subActionItems.size(); i++) {
452 | int lm = subActionItems.get(i).x;
453 | int tm = subActionItems.get(i).y;
454 |
455 | if(lm < left) {
456 | left = lm;
457 | }
458 | if(tm < top) {
459 | top = tm;
460 | }
461 | if(lm + subActionItems.get(i).width > right) {
462 | right = lm + subActionItems.get(i).width;
463 | }
464 | if(tm + subActionItems.get(i).height > bottom) {
465 | bottom = tm + subActionItems.get(i).height;
466 | }
467 | }
468 | overlayParams.width = right - left;
469 | overlayParams.height = bottom - top;
470 | overlayParams.x = left;
471 | overlayParams.y = top;
472 | overlayParams.gravity = Gravity.TOP | Gravity.LEFT;
473 | return overlayParams;
474 | }
475 |
476 | public void detachOverlayContainer() {
477 | getWindowManager().removeView(overlayContainer);
478 | }
479 |
480 | public int getStatusBarHeight() {
481 | int result = 0;
482 | int resourceId = mainActionView.getContext().getResources().getIdentifier("status_bar_height", "dimen", "android");
483 | if (resourceId > 0) {
484 | result = mainActionView.getContext().getResources().getDimensionPixelSize(resourceId);
485 | }
486 | return result;
487 | }
488 |
489 | public void addViewToCurrentContainer(View view) {
490 | addViewToCurrentContainer(view, null);
491 | }
492 |
493 | public void removeViewFromCurrentContainer(View view) {
494 | if(systemOverlay) {
495 | overlayContainer.removeView(view);
496 | }
497 | else {
498 | ((ViewGroup)getActivityContentView()).removeView(view);
499 | }
500 | }
501 |
502 | /**
503 | * Retrieves the screen size from the Activity context
504 | * @return the screen size as a Point object
505 | */
506 | private Point getScreenSize() {
507 | Point size = new Point();
508 | getWindowManager().getDefaultDisplay().getSize(size);
509 | return size;
510 | }
511 |
512 | public void setStateChangeListener(MenuStateChangeListener listener) {
513 | this.stateChangeListener = listener;
514 | }
515 |
516 | /**
517 | * A simple click listener used by the main action view
518 | */
519 | public class ActionViewClickListener implements View.OnClickListener {
520 |
521 | @Override
522 | public void onClick(View v) {
523 | toggle(animated);
524 | }
525 | }
526 |
527 | /**
528 | * This runnable calculates sizes of Item views that are added to the menu.
529 | */
530 | private class ItemViewQueueListener implements Runnable {
531 |
532 | private static final int MAX_TRIES = 10;
533 | private Item item;
534 | private int tries;
535 |
536 | public ItemViewQueueListener(Item item) {
537 | this.item = item;
538 | this.tries = 0;
539 | }
540 |
541 | @Override
542 | public void run() {
543 | // Wait until the the view can be measured but do not push too hard.
544 | if(item.view.getMeasuredWidth() == 0 && tries < MAX_TRIES) {
545 | item.view.post(this);
546 | return;
547 | }
548 | // Measure the size of the item view
549 | item.width = item.view.getMeasuredWidth();
550 | item.height = item.view.getMeasuredHeight();
551 |
552 | // Revert everything back to normal
553 | item.view.setAlpha(item.alpha);
554 | // Remove the item view from view hierarchy
555 | removeViewFromCurrentContainer(item.view);
556 | }
557 | }
558 |
559 | /**
560 | * A simple structure to put a view and its x, y, width and height values together
561 | */
562 | public static class Item {
563 | public int x;
564 | public int y;
565 | public int width;
566 | public int height;
567 |
568 | public float alpha;
569 |
570 | public View view;
571 |
572 | public Item(View view, int width, int height) {
573 | this.view = view;
574 | this.width = width;
575 | this.height = height;
576 | alpha = view.getAlpha();
577 | x = 0;
578 | y = 0;
579 | }
580 | }
581 |
582 | /**
583 | * A listener to listen open/closed state changes of the Menu
584 | */
585 | public static interface MenuStateChangeListener {
586 | public void onMenuOpened(FloatingActionMenu menu);
587 | public void onMenuClosed(FloatingActionMenu menu);
588 | }
589 |
590 | /**
591 | * A builder for {@link FloatingActionMenu} in conventional Java Builder format
592 | */
593 | public static class Builder {
594 |
595 | private int startAngle;
596 | private int endAngle;
597 | private int radius;
598 | private View actionView;
599 | private List
- subActionItems;
600 | private MenuAnimationHandler animationHandler;
601 | private boolean animated;
602 | private MenuStateChangeListener stateChangeListener;
603 | private boolean systemOverlay;
604 |
605 | public Builder(Context context, boolean systemOverlay) {
606 | subActionItems = new ArrayList
- ();
607 | // Default settings
608 | radius = context.getResources().getDimensionPixelSize(R.dimen.action_menu_radius);
609 | startAngle = 180;
610 | endAngle = 270;
611 | animationHandler = new DefaultAnimationHandler();
612 | animated = true;
613 | this.systemOverlay = systemOverlay;
614 | }
615 |
616 | public Builder(Context context) {
617 | this(context, false);
618 | }
619 |
620 | public Builder setStartAngle(int startAngle) {
621 | this.startAngle = startAngle;
622 | return this;
623 | }
624 |
625 | public Builder setEndAngle(int endAngle) {
626 | this.endAngle = endAngle;
627 | return this;
628 | }
629 |
630 | public Builder setRadius(int radius) {
631 | this.radius = radius;
632 | return this;
633 | }
634 |
635 | public Builder addSubActionView(View subActionView, int width, int height) {
636 | subActionItems.add(new Item(subActionView, width, height));
637 | return this;
638 | }
639 |
640 | /**
641 | * Adds a sub action view that is already alive, but not added to a parent View.
642 | * @param subActionView a view for the menu
643 | * @return the builder object itself
644 | */
645 | public Builder addSubActionView(View subActionView) {
646 | if(systemOverlay) {
647 | throw new RuntimeException("Sub action views cannot be added without " +
648 | "definite width and height. Please use " +
649 | "other methods named addSubActionView");
650 | }
651 | return this.addSubActionView(subActionView, 0, 0);
652 | }
653 |
654 | /**
655 | * Inflates a new view from the specified resource id and adds it as a sub action view.
656 | * @param resId the resource id reference for the view
657 | * @param context a valid context
658 | * @return the builder object itself
659 | */
660 | public Builder addSubActionView(int resId, Context context) {
661 | LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
662 | View view = inflater.inflate(resId, null, false);
663 | view.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
664 | return this.addSubActionView(view, view.getMeasuredWidth(), view.getMeasuredHeight());
665 | }
666 |
667 | /**
668 | * Sets the current animation handler to the specified MenuAnimationHandler child
669 | * @param animationHandler a MenuAnimationHandler child
670 | * @return the builder object itself
671 | */
672 | public Builder setAnimationHandler(MenuAnimationHandler animationHandler) {
673 | this.animationHandler = animationHandler;
674 | return this;
675 | }
676 |
677 | public Builder enableAnimations() {
678 | animated = true;
679 | return this;
680 | }
681 |
682 | public Builder disableAnimations() {
683 | animated = false;
684 | return this;
685 | }
686 |
687 | public Builder setStateChangeListener(MenuStateChangeListener listener) {
688 | stateChangeListener = listener;
689 | return this;
690 | }
691 |
692 | public Builder setSystemOverlay(boolean systemOverlay) {
693 | this.systemOverlay = systemOverlay;
694 | return this;
695 | }
696 |
697 | /**
698 | * Attaches the whole menu around a main action view, usually a button.
699 | * All the calculations are made according to this action view.
700 | * @param actionView
701 | * @return the builder object itself
702 | */
703 | public Builder attachTo(View actionView) {
704 | this.actionView = actionView;
705 | return this;
706 | }
707 |
708 | public FloatingActionMenu build() {
709 | return new FloatingActionMenu(actionView,
710 | startAngle,
711 | endAngle,
712 | radius,
713 | subActionItems,
714 | animationHandler,
715 | animated,
716 | stateChangeListener,
717 | systemOverlay);
718 | }
719 | }
720 |
721 | public static WindowManager.LayoutParams getDefaultSystemWindowParams() {
722 | WindowManager.LayoutParams params = new WindowManager.LayoutParams(
723 | WindowManager.LayoutParams.WRAP_CONTENT,
724 | WindowManager.LayoutParams.WRAP_CONTENT,
725 | WindowManager.LayoutParams.TYPE_PHONE,
726 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
727 | PixelFormat.TRANSLUCENT);
728 | params.format = PixelFormat.RGBA_8888;
729 | params.gravity = Gravity.TOP | Gravity.LEFT;
730 | return params;
731 | }
732 |
733 | }
--------------------------------------------------------------------------------
/library/src/main/java/com/oguzdev/circularfloatingactionmenu/library/SubActionButton.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Oguz Bilgener
3 | */
4 | package com.oguzdev.circularfloatingactionmenu.library;
5 |
6 | import android.app.Activity;
7 | import android.content.Context;
8 | import android.graphics.drawable.Drawable;
9 | import android.os.Build;
10 | import android.view.Gravity;
11 | import android.view.View;
12 | import android.widget.FrameLayout;
13 |
14 | /**
15 | * A simple button implementation with a similar look an feel to{@link FloatingActionButton}.
16 | */
17 | public class SubActionButton extends FrameLayout {
18 |
19 | public static final int THEME_LIGHT = 0;
20 | public static final int THEME_DARK = 1;
21 | public static final int THEME_LIGHTER = 2;
22 | public static final int THEME_DARKER = 3;
23 |
24 | public SubActionButton(Context context, FrameLayout.LayoutParams layoutParams, int theme, Drawable backgroundDrawable, View contentView, FrameLayout.LayoutParams contentParams) {
25 | super(context);
26 | setLayoutParams(layoutParams);
27 | // If no custom backgroundDrawable is specified, use the background drawable of the theme.
28 | if(backgroundDrawable == null) {
29 | if(theme == THEME_LIGHT) {
30 | backgroundDrawable = context.getResources().getDrawable(R.drawable.button_sub_action_selector);
31 | }
32 | else if(theme == THEME_DARK) {
33 | backgroundDrawable = context.getResources().getDrawable(R.drawable.button_sub_action_dark_selector);
34 | }
35 | else if(theme == THEME_LIGHTER) {
36 | backgroundDrawable = context.getResources().getDrawable(R.drawable.button_action_selector);
37 | }
38 | else if(theme == THEME_DARKER) {
39 | backgroundDrawable = context.getResources().getDrawable(R.drawable.button_action_dark_selector);
40 | }
41 | else {
42 | throw new RuntimeException("Unknown SubActionButton theme: " + theme);
43 | }
44 | }
45 | else {
46 | backgroundDrawable = backgroundDrawable.mutate().getConstantState().newDrawable();
47 | }
48 | setBackgroundResource(backgroundDrawable);
49 | if(contentView != null) {
50 | setContentView(contentView, contentParams);
51 | }
52 | setClickable(true);
53 | }
54 |
55 | /**
56 | * Sets a content view with custom LayoutParams that will be displayed inside this SubActionButton.
57 | * @param contentView
58 | * @param params
59 | */
60 | public void setContentView(View contentView, FrameLayout.LayoutParams params) {
61 | if(params == null) {
62 | params = new FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, Gravity.CENTER);
63 | final int margin = getResources().getDimensionPixelSize(R.dimen.sub_action_button_content_margin);
64 | params.setMargins(margin, margin, margin, margin);
65 | }
66 |
67 | contentView.setClickable(false);
68 | this.addView(contentView, params);
69 | }
70 |
71 | /**
72 | * Sets a content view with default LayoutParams
73 | * @param contentView
74 | */
75 | public void setContentView(View contentView) {
76 | setContentView(contentView, null);
77 | }
78 |
79 | private void setBackgroundResource(Drawable drawable) {
80 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
81 | setBackground(drawable);
82 | }
83 | else {
84 | setBackgroundDrawable(drawable);
85 | }
86 | }
87 |
88 | /**
89 | * A builder for {@link SubActionButton} in conventional Java Builder format
90 | */
91 | public static class Builder {
92 |
93 | private Context context;
94 | private FrameLayout.LayoutParams layoutParams;
95 | private int theme;
96 | private Drawable backgroundDrawable;
97 | private View contentView;
98 | private FrameLayout.LayoutParams contentParams;
99 |
100 | public Builder(Context context) {
101 | this.context = context;
102 |
103 | // Default SubActionButton settings
104 | int size = context.getResources().getDimensionPixelSize(R.dimen.sub_action_button_size);
105 | FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(size, size, Gravity.TOP | Gravity.LEFT);
106 | setLayoutParams(params);
107 | setTheme(SubActionButton.THEME_LIGHT);
108 | }
109 |
110 | public Builder setLayoutParams(FrameLayout.LayoutParams params) {
111 | this.layoutParams = params;
112 | return this;
113 | }
114 |
115 | public Builder setTheme(int theme) {
116 | this.theme = theme;
117 | return this;
118 | }
119 |
120 | public Builder setBackgroundDrawable(Drawable backgroundDrawable) {
121 | this.backgroundDrawable = backgroundDrawable;
122 | return this;
123 | }
124 |
125 | public Builder setContentView(View contentView) {
126 | this.contentView = contentView;
127 | return this;
128 | }
129 |
130 | public Builder setContentView(View contentView, FrameLayout.LayoutParams contentParams) {
131 | this.contentView = contentView;
132 | this.contentParams = contentParams;
133 | return this;
134 | }
135 |
136 | public SubActionButton build() {
137 | return new SubActionButton(context,
138 | layoutParams,
139 | theme,
140 | backgroundDrawable,
141 | contentView,
142 | contentParams);
143 | }
144 | }
145 | }
146 |
--------------------------------------------------------------------------------
/library/src/main/java/com/oguzdev/circularfloatingactionmenu/library/animation/DefaultAnimationHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Oguz Bilgener
3 | */
4 | package com.oguzdev.circularfloatingactionmenu.library.animation;
5 |
6 | import android.animation.Animator;
7 | import android.animation.ObjectAnimator;
8 | import android.animation.PropertyValuesHolder;
9 | import android.graphics.Point;
10 | import android.view.View;
11 | import android.view.animation.AccelerateDecelerateInterpolator;
12 | import android.view.animation.OvershootInterpolator;
13 |
14 | import com.oguzdev.circularfloatingactionmenu.library.FloatingActionMenu;
15 |
16 | /**
17 | * An example animation handler
18 | * Animates translation, rotation, scale and alpha at the same time using Property Animation APIs.
19 | */
20 | public class DefaultAnimationHandler extends MenuAnimationHandler {
21 |
22 | /** duration of animations, in milliseconds */
23 | protected static final int DURATION = 500;
24 | /** duration to wait between each of */
25 | protected static final int LAG_BETWEEN_ITEMS = 20;
26 | /** holds the current state of animation */
27 | private boolean animating;
28 |
29 | public DefaultAnimationHandler() {
30 | setAnimating(false);
31 | }
32 |
33 | @Override
34 | public void animateMenuOpening(Point center) {
35 | super.animateMenuOpening(center);
36 |
37 | setAnimating(true);
38 |
39 | Animator lastAnimation = null;
40 | for (int i = 0; i < menu.getSubActionItems().size(); i++) {
41 |
42 | menu.getSubActionItems().get(i).view.setScaleX(0);
43 | menu.getSubActionItems().get(i).view.setScaleY(0);
44 | menu.getSubActionItems().get(i).view.setAlpha(0);
45 |
46 | PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat(View.TRANSLATION_X, menu.getSubActionItems().get(i).x - center.x + menu.getSubActionItems().get(i).width / 2);
47 | PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, menu.getSubActionItems().get(i).y - center.y + menu.getSubActionItems().get(i).height / 2);
48 | PropertyValuesHolder pvhR = PropertyValuesHolder.ofFloat(View.ROTATION, 720);
49 | PropertyValuesHolder pvhsX = PropertyValuesHolder.ofFloat(View.SCALE_X, 1);
50 | PropertyValuesHolder pvhsY = PropertyValuesHolder.ofFloat(View.SCALE_Y, 1);
51 | PropertyValuesHolder pvhA = PropertyValuesHolder.ofFloat(View.ALPHA, 1);
52 |
53 | final ObjectAnimator animation = ObjectAnimator.ofPropertyValuesHolder(menu.getSubActionItems().get(i).view, pvhX, pvhY, pvhR, pvhsX, pvhsY, pvhA);
54 | animation.setDuration(DURATION);
55 | animation.setInterpolator(new OvershootInterpolator(0.9f));
56 | animation.addListener(new SubActionItemAnimationListener(menu.getSubActionItems().get(i), ActionType.OPENING));
57 |
58 | if(i == 0) {
59 | lastAnimation = animation;
60 | }
61 |
62 | // Put a slight lag between each of the menu items to make it asymmetric
63 | animation.setStartDelay((menu.getSubActionItems().size() - i) * LAG_BETWEEN_ITEMS);
64 | animation.start();
65 | }
66 | if(lastAnimation != null) {
67 | lastAnimation.addListener(new LastAnimationListener());
68 | }
69 |
70 | }
71 |
72 | @Override
73 | public void animateMenuClosing(Point center) {
74 | super.animateMenuOpening(center);
75 |
76 | setAnimating(true);
77 |
78 | Animator lastAnimation = null;
79 | for (int i = 0; i < menu.getSubActionItems().size(); i++) {
80 | PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat(View.TRANSLATION_X, - (menu.getSubActionItems().get(i).x - center.x + menu.getSubActionItems().get(i).width / 2));
81 | PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, - (menu.getSubActionItems().get(i).y - center.y + menu.getSubActionItems().get(i).height / 2));
82 | PropertyValuesHolder pvhR = PropertyValuesHolder.ofFloat(View.ROTATION, -720);
83 | PropertyValuesHolder pvhsX = PropertyValuesHolder.ofFloat(View.SCALE_X, 0);
84 | PropertyValuesHolder pvhsY = PropertyValuesHolder.ofFloat(View.SCALE_Y, 0);
85 | PropertyValuesHolder pvhA = PropertyValuesHolder.ofFloat(View.ALPHA, 0);
86 |
87 | final ObjectAnimator animation = ObjectAnimator.ofPropertyValuesHolder(menu.getSubActionItems().get(i).view, pvhX, pvhY, pvhR, pvhsX, pvhsY, pvhA);
88 | animation.setDuration(DURATION);
89 | animation.setInterpolator(new AccelerateDecelerateInterpolator());
90 | animation.addListener(new SubActionItemAnimationListener(menu.getSubActionItems().get(i), ActionType.CLOSING));
91 |
92 | if(i == 0) {
93 | lastAnimation = animation;
94 | }
95 |
96 | animation.setStartDelay((menu.getSubActionItems().size() - i) * LAG_BETWEEN_ITEMS);
97 | animation.start();
98 | }
99 | if(lastAnimation != null) {
100 | lastAnimation.addListener(new LastAnimationListener());
101 | }
102 | }
103 |
104 | @Override
105 | public boolean isAnimating() {
106 | return animating;
107 | }
108 |
109 | @Override
110 | protected void setAnimating(boolean animating) {
111 | this.animating = animating;
112 | }
113 |
114 | protected class SubActionItemAnimationListener implements Animator.AnimatorListener {
115 |
116 | private FloatingActionMenu.Item subActionItem;
117 | private ActionType actionType;
118 |
119 | public SubActionItemAnimationListener(FloatingActionMenu.Item subActionItem, ActionType actionType) {
120 | this.subActionItem = subActionItem;
121 | this.actionType = actionType;
122 | }
123 |
124 | @Override
125 | public void onAnimationStart(Animator animation) {
126 |
127 | }
128 |
129 | @Override
130 | public void onAnimationEnd(Animator animation) {
131 | restoreSubActionViewAfterAnimation(subActionItem, actionType);
132 | }
133 |
134 | @Override
135 | public void onAnimationCancel(Animator animation) {
136 | restoreSubActionViewAfterAnimation(subActionItem, actionType);
137 | }
138 |
139 | @Override public void onAnimationRepeat(Animator animation) {}
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/library/src/main/java/com/oguzdev/circularfloatingactionmenu/library/animation/MenuAnimationHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Oguz Bilgener
3 | */
4 | package com.oguzdev.circularfloatingactionmenu.library.animation;
5 |
6 | import android.animation.Animator;
7 | import android.graphics.Point;
8 | import android.view.ViewGroup;
9 | import android.view.WindowManager;
10 | import android.widget.FrameLayout;
11 |
12 | import com.oguzdev.circularfloatingactionmenu.library.FloatingActionMenu;
13 |
14 | /**
15 | * An abstract class that is a prototype for the actual animation handlers
16 | */
17 | public abstract class MenuAnimationHandler {
18 |
19 | // There are only two distinct animations at the moment.
20 | protected enum ActionType {OPENING, CLOSING}
21 |
22 | protected FloatingActionMenu menu;
23 |
24 | public MenuAnimationHandler() {
25 | }
26 |
27 | public void setMenu(FloatingActionMenu menu) {
28 | this.menu = menu;
29 | }
30 |
31 | /**
32 | * Starts the opening animation
33 | * Should be overriden by children
34 | * @param center
35 | */
36 | public void animateMenuOpening(Point center) {
37 | if(menu == null) {
38 | throw new NullPointerException("MenuAnimationHandler cannot animate without a valid FloatingActionMenu.");
39 | }
40 |
41 | }
42 |
43 | /**
44 | * Ends the opening animation
45 | * Should be overriden by children
46 | * @param center
47 | */
48 | public void animateMenuClosing(Point center) {
49 | if(menu == null) {
50 | throw new NullPointerException("MenuAnimationHandler cannot animate without a valid FloatingActionMenu.");
51 | }
52 | }
53 |
54 | /**
55 | * Restores the specified sub action view to its final state, according to the current actionType
56 | * Should be called after an animation finishes.
57 | * @param subActionItem
58 | * @param actionType
59 | */
60 | protected void restoreSubActionViewAfterAnimation(FloatingActionMenu.Item subActionItem, ActionType actionType) {
61 | ViewGroup.LayoutParams params = subActionItem.view.getLayoutParams();
62 | subActionItem.view.setTranslationX(0);
63 | subActionItem.view.setTranslationY(0);
64 | subActionItem.view.setRotation(0);
65 | subActionItem.view.setScaleX(1);
66 | subActionItem.view.setScaleY(1);
67 | subActionItem.view.setAlpha(1);
68 | if(actionType == ActionType.OPENING) {
69 | FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) params;
70 | if(menu.isSystemOverlay()) {
71 | WindowManager.LayoutParams overlayParams = (WindowManager.LayoutParams) menu.getOverlayContainer().getLayoutParams();
72 | lp.setMargins(subActionItem.x - overlayParams.x, subActionItem.y - overlayParams.y, 0, 0);
73 | }
74 | else {
75 | lp.setMargins(subActionItem.x, subActionItem.y, 0, 0);
76 | }
77 | subActionItem.view.setLayoutParams(lp);
78 | }
79 | else if(actionType == ActionType.CLOSING) {
80 | Point center = menu.getActionViewCenter();
81 | FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) params;
82 | if(menu.isSystemOverlay()) {
83 | WindowManager.LayoutParams overlayParams = (WindowManager.LayoutParams) menu.getOverlayContainer().getLayoutParams();
84 | lp.setMargins(center.x - overlayParams.x - subActionItem.width / 2, center.y - overlayParams.y - subActionItem.height / 2, 0, 0);
85 | }
86 | else {
87 | lp.setMargins(center.x - subActionItem.width / 2, center.y - subActionItem.height / 2, 0, 0);
88 | }
89 | subActionItem.view.setLayoutParams(lp);
90 | menu.removeViewFromCurrentContainer(subActionItem.view);
91 |
92 | if(menu.isSystemOverlay()) {
93 | // When all the views are removed from the overlay container,
94 | // we also need to detach it
95 | if (menu.getOverlayContainer().getChildCount() == 0) {
96 | menu.detachOverlayContainer();
97 | }
98 | }
99 | }
100 | }
101 |
102 | /**
103 | * A special animation listener that is intended to listen the last of the sequential animations.
104 | * Changes the animating property of children.
105 | */
106 | public class LastAnimationListener implements Animator.AnimatorListener {
107 |
108 | @Override
109 | public void onAnimationStart(Animator animation) {
110 | setAnimating(true);
111 | }
112 |
113 | @Override
114 | public void onAnimationEnd(Animator animation) {
115 | setAnimating(false);
116 | }
117 |
118 | @Override
119 | public void onAnimationCancel(Animator animation) {
120 | setAnimating(false);
121 | }
122 |
123 | @Override
124 | public void onAnimationRepeat(Animator animation) {
125 | setAnimating(true);
126 | }
127 | }
128 |
129 | public abstract boolean isAnimating();
130 | protected abstract void setAnimating(boolean animating);
131 | }
132 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable-hdpi/button_action.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/library/src/main/res/drawable-hdpi/button_action.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-hdpi/button_action_dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/library/src/main/res/drawable-hdpi/button_action_dark.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-hdpi/button_action_dark_touch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/library/src/main/res/drawable-hdpi/button_action_dark_touch.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-hdpi/button_action_touch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/library/src/main/res/drawable-hdpi/button_action_touch.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-hdpi/button_sub_action.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/library/src/main/res/drawable-hdpi/button_sub_action.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-hdpi/button_sub_action_dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/library/src/main/res/drawable-hdpi/button_sub_action_dark.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-hdpi/button_sub_action_dark_touch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/library/src/main/res/drawable-hdpi/button_sub_action_dark_touch.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-hdpi/button_sub_action_touch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/library/src/main/res/drawable-hdpi/button_sub_action_touch.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-mdpi/button_action.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/library/src/main/res/drawable-mdpi/button_action.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-mdpi/button_action_dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/library/src/main/res/drawable-mdpi/button_action_dark.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-mdpi/button_action_dark_touch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/library/src/main/res/drawable-mdpi/button_action_dark_touch.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-mdpi/button_action_touch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/library/src/main/res/drawable-mdpi/button_action_touch.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-mdpi/button_sub_action.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/library/src/main/res/drawable-mdpi/button_sub_action.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-mdpi/button_sub_action_dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/library/src/main/res/drawable-mdpi/button_sub_action_dark.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-mdpi/button_sub_action_dark_touch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/library/src/main/res/drawable-mdpi/button_sub_action_dark_touch.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-mdpi/button_sub_action_touch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/library/src/main/res/drawable-mdpi/button_sub_action_touch.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xhdpi/button_action.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/library/src/main/res/drawable-xhdpi/button_action.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xhdpi/button_action_dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/library/src/main/res/drawable-xhdpi/button_action_dark.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xhdpi/button_action_dark_touch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/library/src/main/res/drawable-xhdpi/button_action_dark_touch.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xhdpi/button_action_touch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/library/src/main/res/drawable-xhdpi/button_action_touch.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xhdpi/button_sub_action.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/library/src/main/res/drawable-xhdpi/button_sub_action.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xhdpi/button_sub_action_dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/library/src/main/res/drawable-xhdpi/button_sub_action_dark.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xhdpi/button_sub_action_dark_touch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/library/src/main/res/drawable-xhdpi/button_sub_action_dark_touch.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xhdpi/button_sub_action_touch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/library/src/main/res/drawable-xhdpi/button_sub_action_touch.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xxhdpi/button_action.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/library/src/main/res/drawable-xxhdpi/button_action.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xxhdpi/button_action_dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/library/src/main/res/drawable-xxhdpi/button_action_dark.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xxhdpi/button_action_dark_touch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/library/src/main/res/drawable-xxhdpi/button_action_dark_touch.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xxhdpi/button_action_touch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/library/src/main/res/drawable-xxhdpi/button_action_touch.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xxhdpi/button_sub_action.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/library/src/main/res/drawable-xxhdpi/button_sub_action.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xxhdpi/button_sub_action_dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/library/src/main/res/drawable-xxhdpi/button_sub_action_dark.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xxhdpi/button_sub_action_dark_touch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/library/src/main/res/drawable-xxhdpi/button_sub_action_dark_touch.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xxhdpi/button_sub_action_touch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/library/src/main/res/drawable-xxhdpi/button_sub_action_touch.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xxxhdpi/button_action.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/library/src/main/res/drawable-xxxhdpi/button_action.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xxxhdpi/button_action_dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/library/src/main/res/drawable-xxxhdpi/button_action_dark.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xxxhdpi/button_action_dark_touch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/library/src/main/res/drawable-xxxhdpi/button_action_dark_touch.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xxxhdpi/button_action_touch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/library/src/main/res/drawable-xxxhdpi/button_action_touch.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xxxhdpi/button_sub_action.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/library/src/main/res/drawable-xxxhdpi/button_sub_action.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xxxhdpi/button_sub_action_dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/library/src/main/res/drawable-xxxhdpi/button_sub_action_dark.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xxxhdpi/button_sub_action_dark_touch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/library/src/main/res/drawable-xxxhdpi/button_sub_action_dark_touch.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xxxhdpi/button_sub_action_touch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/library/src/main/res/drawable-xxxhdpi/button_sub_action_touch.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable/button_action_dark_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable/button_action_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable/button_sub_action_dark_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable/button_sub_action_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/library/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 | 72dp
3 | 16dp
4 | 12dp
5 | 96dp
6 |
7 | 36dp
8 | 6dp
9 |
10 |
--------------------------------------------------------------------------------
/samples/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/samples/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 21
5 | buildToolsVersion "21.1.1"
6 |
7 | defaultConfig {
8 | applicationId "com.oguzdev.circularfloatingactionmenu.samples"
9 | minSdkVersion 15
10 | targetSdkVersion 21
11 | versionCode 3
12 | versionName "1.0.2"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | compile project(':library')
24 | compile fileTree(dir: 'libs', include: ['*.jar'])
25 | compile 'com.android.support:support-v4:21.+'
26 | compile 'com.android.support:appcompat-v7:+'
27 | }
28 |
--------------------------------------------------------------------------------
/samples/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Applications/Android Studio.app/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/samples/src/androidTest/java/com/oguzdev/circularfloatingactionmenu/samples/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.oguzdev.circularfloatingactionmenu.samples;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/samples/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
13 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
26 |
29 |
30 |
34 |
37 |
38 |
43 |
46 |
47 |
51 |
54 |
55 |
59 |
62 |
63 |
64 |
68 |
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/samples/src/main/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/samples/src/main/ic_launcher-web.png
--------------------------------------------------------------------------------
/samples/src/main/java/com/oguzdev/circularfloatingactionmenu/samples/DemoActivity.java:
--------------------------------------------------------------------------------
1 | package com.oguzdev.circularfloatingactionmenu.samples;
2 |
3 | import android.app.Fragment;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 | import android.support.v7.app.ActionBarActivity;
7 | import android.view.LayoutInflater;
8 | import android.view.Menu;
9 | import android.view.MenuItem;
10 | import android.view.View;
11 | import android.view.ViewGroup;
12 | import android.widget.AdapterView;
13 | import android.widget.ArrayAdapter;
14 | import android.widget.ListView;
15 |
16 | public class DemoActivity extends ActionBarActivity {
17 |
18 | @Override
19 | protected void onCreate(Bundle savedInstanceState) {
20 | super.onCreate(savedInstanceState);
21 | setContentView(R.layout.activity_demo);
22 | if (savedInstanceState == null) {
23 | getFragmentManager().beginTransaction()
24 | .add(R.id.container, new ContentFragment())
25 | .commit();
26 | }
27 | }
28 |
29 |
30 | @Override
31 | public boolean onCreateOptionsMenu(Menu menu) {
32 | // Inflate the menu; this adds items to the action bar if it is present.
33 | getMenuInflater().inflate(R.menu.demo, menu);
34 | return true;
35 | }
36 |
37 | @Override
38 | public boolean onOptionsItemSelected(MenuItem item) {
39 | // Handle action bar item clicks here. The action bar will
40 | // automatically handle clicks on the Home/Up button, so long
41 | // as you specify a parent activity in AndroidManifest.xml.
42 | int id = item.getItemId();
43 | if (id == R.id.action_settings) {
44 | return true;
45 | }
46 | return super.onOptionsItemSelected(item);
47 | }
48 |
49 | /**
50 | * A placeholder fragment containing a simple view.
51 | */
52 | public static class ContentFragment extends Fragment implements AdapterView.OnItemClickListener {
53 |
54 | private ListView demosListView;
55 |
56 | public ContentFragment() {
57 | }
58 |
59 | @Override
60 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
61 | Bundle savedInstanceState) {
62 | View rootView = inflater.inflate(R.layout.fragment_demo, container, false);
63 |
64 | String[] items = { "Menu with FloatingActionButton",
65 | "Menu attached to custom button",
66 | "Menu with custom animation",
67 | "Menu in ScrollView",
68 | "Menu as system overlay"
69 | };
70 | ArrayAdapter simpleAdapter = new ArrayAdapter(getActivity(), android.R.layout.simple_list_item_1, items);
71 | demosListView = (ListView) rootView.findViewById(R.id.demosListView);
72 | demosListView.setAdapter(simpleAdapter);
73 | demosListView.setOnItemClickListener(this);
74 | return rootView;
75 | }
76 |
77 | @Override
78 | public void onItemClick(AdapterView> parent, View view, int position, long id) {
79 | switch (position) {
80 | case 0:
81 | startActivity(new Intent(getActivity(), MenuWithFABActivity.class));
82 | break;
83 | case 1:
84 | startActivity(new Intent(getActivity(), MenuWithCustomActionButtonActivity.class));
85 | break;
86 | case 2:
87 | startActivity(new Intent(getActivity(), MenuWithCustomAnimationActivity.class));
88 | break;
89 | case 3:
90 | startActivity(new Intent(getActivity(), MenuInScrollViewActivity.class));
91 | break;
92 | case 4:
93 | startActivity(new Intent(getActivity(), SystemOverlayMenuActivity.class));
94 | break;
95 | }
96 | }
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/samples/src/main/java/com/oguzdev/circularfloatingactionmenu/samples/MenuInScrollViewActivity.java:
--------------------------------------------------------------------------------
1 | package com.oguzdev.circularfloatingactionmenu.samples;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.os.Bundle;
6 | import android.support.v7.app.ActionBarActivity;
7 | import android.view.LayoutInflater;
8 | import android.view.Menu;
9 | import android.view.MenuItem;
10 | import android.view.View;
11 | import android.view.ViewTreeObserver;
12 | import android.widget.ImageView;
13 | import android.widget.LinearLayout;
14 | import android.widget.ScrollView;
15 |
16 | import com.oguzdev.circularfloatingactionmenu.library.FloatingActionMenu;
17 | import com.oguzdev.circularfloatingactionmenu.library.SubActionButton;
18 |
19 | import java.util.ArrayList;
20 |
21 | public class MenuInScrollViewActivity extends ActionBarActivity implements FloatingActionMenu.MenuStateChangeListener, ViewTreeObserver.OnScrollChangedListener, View.OnLayoutChangeListener {
22 |
23 | private ArrayList menus;
24 | private FloatingActionMenu currentMenu;
25 | private FloatingActionMenu bottomMenu;
26 |
27 | @Override
28 | protected void onCreate(Bundle savedInstanceState) {
29 | super.onCreate(savedInstanceState);
30 | setContentView(R.layout.activity_menu_in_scroll_view);
31 |
32 | LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
33 |
34 | final ScrollView scrollView = (ScrollView) findViewById(R.id.scrollView);
35 | LinearLayout scrollViewBody = (LinearLayout) findViewById(R.id.scrollViewBody);
36 |
37 | menus = new ArrayList();
38 |
39 | // add 20 views into body, each with a menu attached
40 | for(int i=0; i<20; i++) {
41 | LinearLayout item = (LinearLayout) inflater.inflate(R.layout.item_scroll_view, null, false);
42 |
43 | scrollViewBody.addView(item);
44 |
45 | View mainActionView = item.findViewById(R.id.itemActionView);
46 |
47 | SubActionButton.Builder rLSubBuilder = new SubActionButton.Builder(this);
48 | ImageView rlIcon1 = new ImageView(this);
49 | ImageView rlIcon2 = new ImageView(this);
50 | ImageView rlIcon3 = new ImageView(this);
51 |
52 | rlIcon1.setImageDrawable(getResources().getDrawable(R.drawable.ic_action_chat_light));
53 | rlIcon2.setImageDrawable(getResources().getDrawable(R.drawable.ic_action_camera_light));
54 | rlIcon3.setImageDrawable(getResources().getDrawable(R.drawable.ic_action_video_light));
55 |
56 | FloatingActionMenu itemMenu = new FloatingActionMenu.Builder(this)
57 | .setStartAngle(-45)
58 | .setEndAngle(-135)
59 | .setRadius(getResources().getDimensionPixelSize(R.dimen.radius_small))
60 | .addSubActionView(rLSubBuilder.setContentView(rlIcon1).build())
61 | .addSubActionView(rLSubBuilder.setContentView(rlIcon2).build())
62 | .addSubActionView(rLSubBuilder.setContentView(rlIcon3).build())
63 | // listen state changes of each menu
64 | .setStateChangeListener(this)
65 | .attachTo(mainActionView)
66 | .build();
67 |
68 | //
69 | menus.add(itemMenu);
70 | }
71 |
72 | // listen scroll events on root ScrollView
73 | scrollView.getViewTreeObserver().addOnScrollChangedListener(this);
74 |
75 |
76 | findViewById(R.id.buttom_bar_edit_text).clearFocus();
77 |
78 | // Attach a menu to the button in the bottom bar, just to prove that it works.
79 | View bottomActionButton = findViewById(R.id.bottom_bar_action_button);
80 | SubActionButton.Builder rLSubBuilder = new SubActionButton.Builder(this);
81 | ImageView rlIcon1 = new ImageView(this);
82 | ImageView rlIcon2 = new ImageView(this);
83 | ImageView rlIcon3 = new ImageView(this);
84 |
85 | rlIcon1.setImageDrawable(getResources().getDrawable(R.drawable.ic_action_place_light));
86 | rlIcon2.setImageDrawable(getResources().getDrawable(R.drawable.ic_action_picture_light));
87 | rlIcon3.setImageDrawable(getResources().getDrawable(R.drawable.ic_action_camera_light));
88 |
89 | bottomMenu = new FloatingActionMenu.Builder(this)
90 | .addSubActionView(rLSubBuilder.setContentView(rlIcon1).build())
91 | .addSubActionView(rLSubBuilder.setContentView(rlIcon2).build())
92 | .addSubActionView(rLSubBuilder.setContentView(rlIcon3).build())
93 | .setStartAngle(-40)
94 | .setEndAngle(-90)
95 | .setRadius(getResources().getDimensionPixelSize(R.dimen.radius_medium))
96 | .attachTo(bottomActionButton)
97 | .build();
98 |
99 | // Listen layout (size) changes on a main layout so that we could reposition the bottom menu
100 | scrollView.addOnLayoutChangeListener(this);
101 | }
102 |
103 |
104 | @Override
105 | public boolean onCreateOptionsMenu(Menu menu) {
106 | // Inflate the menu; this adds items to the action bar if it is present.
107 | getMenuInflater().inflate(R.menu.menu_in_scroll_view, menu);
108 | return true;
109 | }
110 |
111 | @Override
112 | public boolean onOptionsItemSelected(MenuItem item) {
113 | // Handle action bar item clicks here. The action bar will
114 | // automatically handle clicks on the Home/Up button, so long
115 | // as you specify a parent activity in AndroidManifest.xml.
116 | int id = item.getItemId();
117 | if (id == R.id.action_settings) {
118 | return true;
119 | }
120 | return super.onOptionsItemSelected(item);
121 | }
122 |
123 | @Override
124 | public void onMenuOpened(FloatingActionMenu menu) {
125 | // Only allow one menu to stay open
126 | for(FloatingActionMenu iMenu : menus) {
127 | iMenu.close(true);
128 | }
129 | // update our current menu reference
130 | currentMenu = menu;
131 | }
132 |
133 | @Override
134 | public void onMenuClosed(FloatingActionMenu menu) {
135 | // remove our current menu reference
136 | currentMenu = null;
137 | }
138 |
139 | @Override
140 | public void onScrollChanged() {
141 | // ScrollView is scrolled,
142 | // coordinates of main action view has changed.
143 | // We need to update item coordinates of the current open menu.
144 | if(currentMenu != null) {
145 | currentMenu.updateItemPositions();
146 | }
147 | }
148 |
149 | @Override
150 | public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
151 | // update the position of the menu when the main layout changes size on events like soft keyboard open/close
152 | if(right - left != 0 && bottom - top != 0 &&
153 | (oldLeft != left || oldTop != top || oldRight != right || oldBottom != bottom) && bottomMenu != null) {
154 | bottomMenu.updateItemPositions();
155 | }
156 | }
157 | }
158 |
--------------------------------------------------------------------------------
/samples/src/main/java/com/oguzdev/circularfloatingactionmenu/samples/MenuWithCustomActionButtonActivity.java:
--------------------------------------------------------------------------------
1 | package com.oguzdev.circularfloatingactionmenu.samples;
2 |
3 | import android.app.Activity;
4 | import android.app.Fragment;
5 | import android.os.Bundle;
6 | import android.support.v7.app.ActionBarActivity;
7 | import android.view.LayoutInflater;
8 | import android.view.Menu;
9 | import android.view.MenuItem;
10 | import android.view.View;
11 | import android.view.ViewGroup;
12 | import android.widget.Button;
13 | import android.widget.FrameLayout;
14 | import android.widget.TextView;
15 |
16 | import com.oguzdev.circularfloatingactionmenu.library.FloatingActionMenu;
17 | import com.oguzdev.circularfloatingactionmenu.library.SubActionButton;
18 |
19 | public class MenuWithCustomActionButtonActivity extends ActionBarActivity {
20 |
21 | @Override
22 | protected void onCreate(Bundle savedInstanceState) {
23 | super.onCreate(savedInstanceState);
24 | setContentView(R.layout.activity_menu_with_custom_action_button);
25 | if (savedInstanceState == null) {
26 | getFragmentManager().beginTransaction()
27 | .add(R.id.container, new CustomButtonDemoFragment())
28 | .commit();
29 | }
30 | }
31 |
32 |
33 | @Override
34 | public boolean onCreateOptionsMenu(Menu menu) {
35 | // Inflate the menu; this adds items to the action bar if it is present.
36 | getMenuInflater().inflate(R.menu.menu_with_custom_action_button, menu);
37 | return true;
38 | }
39 |
40 | @Override
41 | public boolean onOptionsItemSelected(MenuItem item) {
42 | // Handle action bar item clicks here. The action bar will
43 | // automatically handle clicks on the Home/Up button, so long
44 | // as you specify a parent activity in AndroidManifest.xml.
45 | int id = item.getItemId();
46 | if (id == R.id.action_settings) {
47 | return true;
48 | }
49 | return super.onOptionsItemSelected(item);
50 | }
51 |
52 | /**
53 | * A placeholder fragment containing a simple view.
54 | */
55 | public static class CustomButtonDemoFragment extends Fragment {
56 |
57 | public CustomButtonDemoFragment() {
58 | }
59 |
60 | @Override
61 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
62 | Bundle savedInstanceState) {
63 | View rootView = inflater.inflate(R.layout.fragment_menu_with_custom_action_button, container, false);
64 |
65 | // Our action button is this time just a regular view!
66 | Button centerActionButton = (Button) rootView.findViewById(R.id.centerActionButton);
67 |
68 | // Add some items to the menu. They are regular views as well!
69 | TextView a = new TextView(getActivity()); a.setText("a"); a.setBackgroundResource(android.R.drawable.btn_default_small);
70 | TextView b = new TextView(getActivity()); b.setText("b"); b.setBackgroundResource(android.R.drawable.btn_default_small);
71 | TextView c = new TextView(getActivity()); c.setText("c"); c.setBackgroundResource(android.R.drawable.btn_default_small);
72 | TextView d = new TextView(getActivity()); d.setText("d"); d.setBackgroundResource(android.R.drawable.btn_default_small);
73 | TextView e = new TextView(getActivity()); e.setText("e"); e.setBackgroundResource(android.R.drawable.btn_default_small);
74 | TextView f = new TextView(getActivity()); f.setText("f"); f.setBackgroundResource(android.R.drawable.btn_default_small);
75 | TextView g = new TextView(getActivity()); g.setText("g"); g.setBackgroundResource(android.R.drawable.btn_default_small);
76 | TextView h = new TextView(getActivity()); h.setText("h"); h.setBackgroundResource(android.R.drawable.btn_default_small);
77 | FrameLayout.LayoutParams tvParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT);
78 | a.setLayoutParams(tvParams);
79 | b.setLayoutParams(tvParams);
80 | c.setLayoutParams(tvParams);
81 | d.setLayoutParams(tvParams);
82 | e.setLayoutParams(tvParams);
83 | f.setLayoutParams(tvParams);
84 | g.setLayoutParams(tvParams);
85 | h.setLayoutParams(tvParams);
86 |
87 | SubActionButton.Builder subBuilder = new SubActionButton.Builder(getActivity());
88 |
89 | FloatingActionMenu circleMenu = new FloatingActionMenu.Builder(getActivity())
90 | .setStartAngle(0) // A whole circle!
91 | .setEndAngle(360)
92 | .setRadius(getResources().getDimensionPixelSize(R.dimen.radius_large))
93 | .addSubActionView(a)
94 | .addSubActionView(b)
95 | .addSubActionView(c)
96 | .addSubActionView(d)
97 | .addSubActionView(e)
98 | .addSubActionView(f)
99 | .addSubActionView(g)
100 | .addSubActionView(h)
101 | .attachTo(centerActionButton)
102 | .build();
103 |
104 | return rootView;
105 | }
106 | }
107 | }
--------------------------------------------------------------------------------
/samples/src/main/java/com/oguzdev/circularfloatingactionmenu/samples/MenuWithCustomAnimationActivity.java:
--------------------------------------------------------------------------------
1 | package com.oguzdev.circularfloatingactionmenu.samples;
2 |
3 | import android.app.Activity;
4 | import android.app.Fragment;
5 | import android.os.Bundle;
6 | import android.support.v7.app.ActionBarActivity;
7 | import android.view.LayoutInflater;
8 | import android.view.Menu;
9 | import android.view.MenuItem;
10 | import android.view.View;
11 | import android.view.ViewGroup;
12 | import android.widget.ImageView;
13 |
14 | import com.oguzdev.circularfloatingactionmenu.library.FloatingActionButton;
15 | import com.oguzdev.circularfloatingactionmenu.library.FloatingActionMenu;
16 | import com.oguzdev.circularfloatingactionmenu.library.SubActionButton;
17 |
18 | public class MenuWithCustomAnimationActivity extends ActionBarActivity {
19 |
20 | @Override
21 | protected void onCreate(Bundle savedInstanceState) {
22 | super.onCreate(savedInstanceState);
23 | setContentView(R.layout.activity_menu_with_custom_animation);
24 | if (savedInstanceState == null) {
25 | getFragmentManager().beginTransaction()
26 | .add(R.id.container, new CustomAnimationDemoFragment())
27 | .commit();
28 | }
29 | }
30 |
31 |
32 | @Override
33 | public boolean onCreateOptionsMenu(Menu menu) {
34 | // Inflate the menu; this adds items to the action bar if it is present.
35 | getMenuInflater().inflate(R.menu.menu_with_custom_animation, menu);
36 | return true;
37 | }
38 |
39 | @Override
40 | public boolean onOptionsItemSelected(MenuItem item) {
41 | // Handle action bar item clicks here. The action bar will
42 | // automatically handle clicks on the Home/Up button, so long
43 | // as you specify a parent activity in AndroidManifest.xml.
44 | int id = item.getItemId();
45 | if (id == R.id.action_settings) {
46 | return true;
47 | }
48 | return super.onOptionsItemSelected(item);
49 | }
50 |
51 | /**
52 | * A placeholder fragment containing a simple view.
53 | */
54 | public static class CustomAnimationDemoFragment extends Fragment {
55 |
56 | public CustomAnimationDemoFragment() {
57 | }
58 |
59 | @Override
60 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
61 | Bundle savedInstanceState) {
62 | View rootView = inflater.inflate(R.layout.fragment_menu_with_custom_animation, container, false);
63 |
64 | ImageView fabContent = new ImageView(getActivity());
65 | fabContent.setImageDrawable(getResources().getDrawable(R.drawable.ic_action_settings));
66 |
67 | FloatingActionButton darkButton = new FloatingActionButton.Builder(getActivity())
68 | .setTheme(FloatingActionButton.THEME_DARK)
69 | .setContentView(fabContent)
70 | .setPosition(FloatingActionButton.POSITION_BOTTOM_CENTER)
71 | .build();
72 |
73 | SubActionButton.Builder rLSubBuilder = new SubActionButton.Builder(getActivity())
74 | .setTheme(SubActionButton.THEME_DARK);
75 | ImageView rlIcon1 = new ImageView(getActivity());
76 | ImageView rlIcon2 = new ImageView(getActivity());
77 | ImageView rlIcon3 = new ImageView(getActivity());
78 | ImageView rlIcon4 = new ImageView(getActivity());
79 | ImageView rlIcon5 = new ImageView(getActivity());
80 |
81 | rlIcon1.setImageDrawable(getResources().getDrawable(R.drawable.ic_action_chat));
82 | rlIcon2.setImageDrawable(getResources().getDrawable(R.drawable.ic_action_camera));
83 | rlIcon3.setImageDrawable(getResources().getDrawable(R.drawable.ic_action_video));
84 | rlIcon4.setImageDrawable(getResources().getDrawable(R.drawable.ic_action_place));
85 | rlIcon5.setImageDrawable(getResources().getDrawable(R.drawable.ic_action_headphones));
86 |
87 | // Set 4 SubActionButtons
88 | FloatingActionMenu centerBottomMenu = new FloatingActionMenu.Builder(getActivity())
89 | .setStartAngle(0)
90 | .setEndAngle(-180)
91 | .setAnimationHandler(new SlideInAnimationHandler())
92 | .addSubActionView(rLSubBuilder.setContentView(rlIcon1).build())
93 | .addSubActionView(rLSubBuilder.setContentView(rlIcon2).build())
94 | .addSubActionView(rLSubBuilder.setContentView(rlIcon3).build())
95 | .addSubActionView(rLSubBuilder.setContentView(rlIcon4).build())
96 | .addSubActionView(rLSubBuilder.setContentView(rlIcon5).build())
97 | .attachTo(darkButton)
98 | .build();
99 |
100 | return rootView;
101 | }
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/samples/src/main/java/com/oguzdev/circularfloatingactionmenu/samples/MenuWithFABActivity.java:
--------------------------------------------------------------------------------
1 | package com.oguzdev.circularfloatingactionmenu.samples;
2 |
3 | import android.animation.ObjectAnimator;
4 | import android.animation.PropertyValuesHolder;
5 | import android.app.Activity;
6 | import android.os.Bundle;
7 | import android.support.v7.app.ActionBarActivity;
8 | import android.view.Menu;
9 | import android.view.MenuItem;
10 | import android.view.View;
11 | import android.widget.FrameLayout;
12 | import android.widget.ImageView;
13 |
14 | import com.oguzdev.circularfloatingactionmenu.library.FloatingActionButton;
15 | import com.oguzdev.circularfloatingactionmenu.library.FloatingActionMenu;
16 | import com.oguzdev.circularfloatingactionmenu.library.SubActionButton;
17 |
18 | public class MenuWithFABActivity extends ActionBarActivity {
19 |
20 | @Override
21 | protected void onCreate(Bundle savedInstanceState) {
22 | super.onCreate(savedInstanceState);
23 | setContentView(R.layout.activity_menu_with_fab);
24 |
25 | // Set up the white button on the lower right corner
26 | // more or less with default parameter
27 | final ImageView fabIconNew = new ImageView(this);
28 | fabIconNew.setImageDrawable(getResources().getDrawable(R.drawable.ic_action_new_light));
29 | final FloatingActionButton rightLowerButton = new FloatingActionButton.Builder(this)
30 | .setContentView(fabIconNew)
31 | .build();
32 |
33 | SubActionButton.Builder rLSubBuilder = new SubActionButton.Builder(this);
34 | ImageView rlIcon1 = new ImageView(this);
35 | ImageView rlIcon2 = new ImageView(this);
36 | ImageView rlIcon3 = new ImageView(this);
37 | ImageView rlIcon4 = new ImageView(this);
38 |
39 | rlIcon1.setImageDrawable(getResources().getDrawable(R.drawable.ic_action_chat_light));
40 | rlIcon2.setImageDrawable(getResources().getDrawable(R.drawable.ic_action_camera_light));
41 | rlIcon3.setImageDrawable(getResources().getDrawable(R.drawable.ic_action_video_light));
42 | rlIcon4.setImageDrawable(getResources().getDrawable(R.drawable.ic_action_place_light));
43 |
44 | // Build the menu with default options: light theme, 90 degrees, 72dp radius.
45 | // Set 4 default SubActionButtons
46 | final FloatingActionMenu rightLowerMenu = new FloatingActionMenu.Builder(this)
47 | .addSubActionView(rLSubBuilder.setContentView(rlIcon1).build())
48 | .addSubActionView(rLSubBuilder.setContentView(rlIcon2).build())
49 | .addSubActionView(rLSubBuilder.setContentView(rlIcon3).build())
50 | .addSubActionView(rLSubBuilder.setContentView(rlIcon4).build())
51 | .attachTo(rightLowerButton)
52 | .build();
53 |
54 | // Listen menu open and close events to animate the button content view
55 | rightLowerMenu.setStateChangeListener(new FloatingActionMenu.MenuStateChangeListener() {
56 | @Override
57 | public void onMenuOpened(FloatingActionMenu menu) {
58 | // Rotate the icon of rightLowerButton 45 degrees clockwise
59 | fabIconNew.setRotation(0);
60 | PropertyValuesHolder pvhR = PropertyValuesHolder.ofFloat(View.ROTATION, 45);
61 | ObjectAnimator animation = ObjectAnimator.ofPropertyValuesHolder(fabIconNew, pvhR);
62 | animation.start();
63 | }
64 |
65 | @Override
66 | public void onMenuClosed(FloatingActionMenu menu) {
67 | // Rotate the icon of rightLowerButton 45 degrees counter-clockwise
68 | fabIconNew.setRotation(45);
69 | PropertyValuesHolder pvhR = PropertyValuesHolder.ofFloat(View.ROTATION, 0);
70 | ObjectAnimator animation = ObjectAnimator.ofPropertyValuesHolder(fabIconNew, pvhR);
71 | animation.start();
72 | }
73 | });
74 |
75 | // Set up the large red button on the center right side
76 | // With custom button and content sizes and margins
77 | int redActionButtonSize = getResources().getDimensionPixelSize(R.dimen.red_action_button_size);
78 | int redActionButtonMargin = getResources().getDimensionPixelOffset(R.dimen.action_button_margin);
79 | int redActionButtonContentSize = getResources().getDimensionPixelSize(R.dimen.red_action_button_content_size);
80 | int redActionButtonContentMargin = getResources().getDimensionPixelSize(R.dimen.red_action_button_content_margin);
81 | int redActionMenuRadius = getResources().getDimensionPixelSize(R.dimen.red_action_menu_radius);
82 | int blueSubActionButtonSize = getResources().getDimensionPixelSize(R.dimen.blue_sub_action_button_size);
83 | int blueSubActionButtonContentMargin = getResources().getDimensionPixelSize(R.dimen.blue_sub_action_button_content_margin);
84 |
85 | ImageView fabIconStar = new ImageView(this);
86 | fabIconStar.setImageDrawable(getResources().getDrawable(R.drawable.ic_action_important));
87 |
88 | FloatingActionButton.LayoutParams starParams = new FloatingActionButton.LayoutParams(redActionButtonSize, redActionButtonSize);
89 | starParams.setMargins(redActionButtonMargin,
90 | redActionButtonMargin,
91 | redActionButtonMargin,
92 | redActionButtonMargin);
93 | fabIconStar.setLayoutParams(starParams);
94 |
95 | FloatingActionButton.LayoutParams fabIconStarParams = new FloatingActionButton.LayoutParams(redActionButtonContentSize, redActionButtonContentSize);
96 | fabIconStarParams.setMargins(redActionButtonContentMargin,
97 | redActionButtonContentMargin,
98 | redActionButtonContentMargin,
99 | redActionButtonContentMargin);
100 |
101 | final FloatingActionButton leftCenterButton = new FloatingActionButton.Builder(this)
102 | .setContentView(fabIconStar, fabIconStarParams)
103 | .setBackgroundDrawable(R.drawable.button_action_red_selector)
104 | .setPosition(FloatingActionButton.POSITION_LEFT_CENTER)
105 | .setLayoutParams(starParams)
106 | .build();
107 |
108 | // Set up customized SubActionButtons for the right center menu
109 | SubActionButton.Builder lCSubBuilder = new SubActionButton.Builder(this);
110 | lCSubBuilder.setBackgroundDrawable(getResources().getDrawable(R.drawable.button_action_blue_selector));
111 |
112 | FrameLayout.LayoutParams blueContentParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
113 | blueContentParams.setMargins(blueSubActionButtonContentMargin,
114 | blueSubActionButtonContentMargin,
115 | blueSubActionButtonContentMargin,
116 | blueSubActionButtonContentMargin);
117 | lCSubBuilder.setLayoutParams(blueContentParams);
118 | // Set custom layout params
119 | FrameLayout.LayoutParams blueParams = new FrameLayout.LayoutParams(blueSubActionButtonSize, blueSubActionButtonSize);
120 | lCSubBuilder.setLayoutParams(blueParams);
121 |
122 | ImageView lcIcon1 = new ImageView(this);
123 | ImageView lcIcon2 = new ImageView(this);
124 | ImageView lcIcon3 = new ImageView(this);
125 | ImageView lcIcon4 = new ImageView(this);
126 | ImageView lcIcon5 = new ImageView(this);
127 |
128 | lcIcon1.setImageDrawable(getResources().getDrawable(R.drawable.ic_action_camera));
129 | lcIcon2.setImageDrawable(getResources().getDrawable(R.drawable.ic_action_picture));
130 | lcIcon3.setImageDrawable(getResources().getDrawable(R.drawable.ic_action_video));
131 | lcIcon4.setImageDrawable(getResources().getDrawable(R.drawable.ic_action_location_found));
132 | lcIcon5.setImageDrawable(getResources().getDrawable(R.drawable.ic_action_headphones));
133 |
134 | // Build another menu with custom options
135 | final FloatingActionMenu leftCenterMenu = new FloatingActionMenu.Builder(this)
136 | .addSubActionView(lCSubBuilder.setContentView(lcIcon1, blueContentParams).build())
137 | .addSubActionView(lCSubBuilder.setContentView(lcIcon2, blueContentParams).build())
138 | .addSubActionView(lCSubBuilder.setContentView(lcIcon3, blueContentParams).build())
139 | .addSubActionView(lCSubBuilder.setContentView(lcIcon4, blueContentParams).build())
140 | .addSubActionView(lCSubBuilder.setContentView(lcIcon5, blueContentParams).build())
141 | .setRadius(redActionMenuRadius)
142 | .setStartAngle(70)
143 | .setEndAngle(-70)
144 | .attachTo(leftCenterButton)
145 | .build();
146 |
147 |
148 | }
149 |
150 |
151 | @Override
152 | public boolean onCreateOptionsMenu(Menu menu) {
153 | // Inflate the menu; this adds items to the action bar if it is present.
154 | getMenuInflater().inflate(R.menu.menu_with_fab, menu);
155 | return true;
156 | }
157 |
158 | @Override
159 | public boolean onOptionsItemSelected(MenuItem item) {
160 | // Handle action bar item clicks here. The action bar will
161 | // automatically handle clicks on the Home/Up button, so long
162 | // as you specify a parent activity in AndroidManifest.xml.
163 | int id = item.getItemId();
164 | if (id == R.id.action_settings) {
165 | return true;
166 | }
167 | return super.onOptionsItemSelected(item);
168 | }
169 | }
170 |
--------------------------------------------------------------------------------
/samples/src/main/java/com/oguzdev/circularfloatingactionmenu/samples/SlideInAnimationHandler.java:
--------------------------------------------------------------------------------
1 | package com.oguzdev.circularfloatingactionmenu.samples;
2 |
3 | import android.animation.Animator;
4 | import android.animation.ObjectAnimator;
5 | import android.animation.PropertyValuesHolder;
6 | import android.graphics.Point;
7 | import android.view.View;
8 | import android.view.animation.AccelerateInterpolator;
9 | import android.view.animation.DecelerateInterpolator;
10 | import android.widget.FrameLayout;
11 |
12 | import com.oguzdev.circularfloatingactionmenu.library.FloatingActionMenu;
13 | import com.oguzdev.circularfloatingactionmenu.library.animation.MenuAnimationHandler;
14 |
15 | /**
16 | * Created by oguzbilgener on 23/07/14.
17 | */
18 | public class SlideInAnimationHandler extends MenuAnimationHandler {
19 | /** duration of animations, in milliseconds */
20 | protected static final int DURATION = 700;
21 | /** duration to wait between each of */
22 | protected static final int LAG_BETWEEN_ITEMS = 100;
23 |
24 | protected static final int DIST_Y = 1000;
25 |
26 | /** holds the current state of animation */
27 |
28 | private boolean animating;
29 |
30 | public SlideInAnimationHandler() {
31 | setAnimating(false);
32 | }
33 |
34 | @Override
35 | public void animateMenuOpening(Point center) {
36 | super.animateMenuOpening(center);
37 |
38 | setAnimating(true);
39 |
40 | Animator lastAnimation = null;
41 | for (int i = 0; i < menu.getSubActionItems().size(); i++) {
42 |
43 | menu.getSubActionItems().get(i).view.setAlpha(0);
44 |
45 | FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) menu.getSubActionItems().get(i).view.getLayoutParams();
46 | params.setMargins(menu.getSubActionItems().get(i).x, menu.getSubActionItems().get(i).y + DIST_Y, 0, 0);
47 | menu.getSubActionItems().get(i).view.setLayoutParams(params);
48 |
49 | // PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat(View.TRANSLATION_X, menu.getSubActionItems().get(i).x/* - center.x + menu.getSubActionItems().get(i).width / 2*/);
50 | PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, -DIST_Y);
51 | // PropertyValuesHolder pvhsX = PropertyValuesHolder.ofFloat(View.SCALE_X, 1);
52 | // PropertyValuesHolder pvhsY = PropertyValuesHolder.ofFloat(View.SCALE_Y, 1);
53 | PropertyValuesHolder pvhA = PropertyValuesHolder.ofFloat(View.ALPHA, 1);
54 |
55 | final ObjectAnimator animation = ObjectAnimator.ofPropertyValuesHolder(menu.getSubActionItems().get(i).view, pvhY, pvhA);
56 | animation.setDuration(DURATION);
57 | animation.setInterpolator(new DecelerateInterpolator());
58 | animation.addListener(new SubActionItemAnimationListener(menu.getSubActionItems().get(i), ActionType.OPENING));
59 |
60 | if(i == 0) {
61 | lastAnimation = animation;
62 | }
63 |
64 | animation.setStartDelay(Math.abs(menu.getSubActionItems().size()/2-i) * LAG_BETWEEN_ITEMS);
65 | animation.start();
66 | }
67 | if(lastAnimation != null) {
68 | lastAnimation.addListener(new LastAnimationListener());
69 | }
70 |
71 | }
72 |
73 | @Override
74 | public void animateMenuClosing(Point center) {
75 | super.animateMenuOpening(center);
76 |
77 | setAnimating(true);
78 |
79 | Animator lastAnimation = null;
80 | for (int i = 0; i < menu.getSubActionItems().size(); i++) {
81 | // PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat(View.TRANSLATION_X, - (menu.getSubActionItems().get(i).x - center.x + menu.getSubActionItems().get(i).width / 2));
82 | PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, DIST_Y);
83 | // PropertyValuesHolder pvhsX = PropertyValuesHolder.ofFloat(View.SCALE_X, 0);
84 | // PropertyValuesHolder pvhsY = PropertyValuesHolder.ofFloat(View.SCALE_Y, 0);
85 | PropertyValuesHolder pvhA = PropertyValuesHolder.ofFloat(View.ALPHA, 0);
86 |
87 | final ObjectAnimator animation = ObjectAnimator.ofPropertyValuesHolder(menu.getSubActionItems().get(i).view, pvhY, pvhA);
88 | animation.setDuration(DURATION);
89 | animation.setInterpolator(new AccelerateInterpolator());
90 | animation.addListener(new SubActionItemAnimationListener(menu.getSubActionItems().get(i), ActionType.CLOSING));
91 |
92 | if(i == 0) {
93 | lastAnimation = animation;
94 | }
95 |
96 | if(i <= menu.getSubActionItems().size()/2) {
97 | animation.setStartDelay(i * LAG_BETWEEN_ITEMS);
98 | }
99 | else {
100 | animation.setStartDelay((menu.getSubActionItems().size() - i) * LAG_BETWEEN_ITEMS);
101 | }
102 | animation.start();
103 | }
104 | if(lastAnimation != null) {
105 | lastAnimation.addListener(new LastAnimationListener());
106 | }
107 | }
108 |
109 | @Override
110 | public boolean isAnimating() {
111 | return animating;
112 | }
113 |
114 | @Override
115 | protected void setAnimating(boolean animating) {
116 | this.animating = animating;
117 | }
118 |
119 | protected class SubActionItemAnimationListener implements Animator.AnimatorListener {
120 |
121 | private FloatingActionMenu.Item subActionItem;
122 | private ActionType actionType;
123 |
124 | public SubActionItemAnimationListener(FloatingActionMenu.Item subActionItem, ActionType actionType) {
125 | this.subActionItem = subActionItem;
126 | this.actionType = actionType;
127 | }
128 |
129 | @Override
130 | public void onAnimationStart(Animator animation) {
131 |
132 | }
133 |
134 | @Override
135 | public void onAnimationEnd(Animator animation) {
136 | restoreSubActionViewAfterAnimation(subActionItem, actionType);
137 | }
138 |
139 | @Override
140 | public void onAnimationCancel(Animator animation) {
141 | restoreSubActionViewAfterAnimation(subActionItem, actionType);
142 | }
143 |
144 | @Override public void onAnimationRepeat(Animator animation) {}
145 | }
146 | }
147 |
--------------------------------------------------------------------------------
/samples/src/main/java/com/oguzdev/circularfloatingactionmenu/samples/SystemOverlayMenuActivity.java:
--------------------------------------------------------------------------------
1 | package com.oguzdev.circularfloatingactionmenu.samples;
2 |
3 | import android.content.ComponentName;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.content.ServiceConnection;
7 | import android.os.Bundle;
8 | import android.os.IBinder;
9 | import android.support.v7.app.ActionBarActivity;
10 | import android.view.Menu;
11 | import android.view.MenuItem;
12 | import android.view.View;
13 | import android.widget.Button;
14 | import android.widget.FrameLayout;
15 | import android.widget.ImageView;
16 |
17 | import com.oguzdev.circularfloatingactionmenu.library.FloatingActionButton;
18 | import com.oguzdev.circularfloatingactionmenu.library.FloatingActionMenu;
19 | import com.oguzdev.circularfloatingactionmenu.library.SubActionButton;
20 |
21 | public class SystemOverlayMenuActivity extends ActionBarActivity {
22 |
23 | @Override
24 | protected void onCreate(Bundle savedInstanceState) {
25 | super.onCreate(savedInstanceState);
26 | setContentView(R.layout.activity_menu_with_overlay);
27 |
28 | Button button = (Button) findViewById(R.id.startOverlayServiceButton);
29 | button.setOnClickListener(new View.OnClickListener() {
30 |
31 | @Override
32 | public void onClick(View v) {
33 | // Start an unbound service.
34 | Intent is = new Intent(SystemOverlayMenuActivity.this, SystemOverlayMenuService.class);
35 | startService(is);
36 | // We need to be able to stop it later though.
37 | // This is currently done by the red button of the topCenterMenu in SystemOverlayMenuService
38 | }
39 | });
40 | }
41 |
42 | @Override
43 | protected void onStop() {
44 | super.onStop();
45 | }
46 |
47 |
48 | @Override
49 | public boolean onCreateOptionsMenu(Menu menu) {
50 | // Inflate the menu; this adds items to the action bar if it is present.
51 | getMenuInflater().inflate(R.menu.menu_with_fab, menu);
52 | return true;
53 | }
54 |
55 | @Override
56 | public boolean onOptionsItemSelected(MenuItem item) {
57 | // Handle action bar item clicks here. The action bar will
58 | // automatically handle clicks on the Home/Up button, so long
59 | // as you specify a parent activity in AndroidManifest.xml.
60 | int id = item.getItemId();
61 | if (id == R.id.action_settings) {
62 | return true;
63 | }
64 | return super.onOptionsItemSelected(item);
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/samples/src/main/java/com/oguzdev/circularfloatingactionmenu/samples/SystemOverlayMenuService.java:
--------------------------------------------------------------------------------
1 | package com.oguzdev.circularfloatingactionmenu.samples;
2 |
3 | import android.app.Service;
4 | import android.content.Intent;
5 | import android.os.Binder;
6 | import android.os.IBinder;
7 | import android.util.Log;
8 | import android.view.View;
9 | import android.view.WindowManager;
10 | import android.widget.FrameLayout;
11 | import android.widget.ImageView;
12 | import android.widget.TextView;
13 |
14 | import com.oguzdev.circularfloatingactionmenu.library.FloatingActionButton;
15 | import com.oguzdev.circularfloatingactionmenu.library.FloatingActionMenu;
16 | import com.oguzdev.circularfloatingactionmenu.library.SubActionButton;
17 |
18 | public class SystemOverlayMenuService extends Service {
19 |
20 | private final IBinder mBinder = new LocalBinder();
21 |
22 | private FloatingActionButton rightLowerButton;
23 | private FloatingActionButton topCenterButton;
24 |
25 | private FloatingActionMenu rightLowerMenu;
26 | private FloatingActionMenu topCenterMenu;
27 |
28 | private boolean serviceWillBeDismissed;
29 |
30 | public SystemOverlayMenuService() {
31 | }
32 |
33 | public class LocalBinder extends Binder {
34 | SystemOverlayMenuService getService() {
35 | // Return this instance of LocalService so clients can call public methods
36 | return SystemOverlayMenuService.this;
37 | }
38 | }
39 |
40 | @Override
41 | public IBinder onBind(Intent intent) {
42 | return mBinder;
43 | }
44 |
45 | @Override
46 | public void onCreate() {
47 | super.onCreate();
48 |
49 | serviceWillBeDismissed = false;
50 |
51 | // Set up the white button on the lower right corner
52 | // more or less with default parameter
53 | ImageView fabIconNew = new ImageView(this);
54 | fabIconNew.setImageDrawable(getResources().getDrawable(R.drawable.ic_action_new_light));
55 | WindowManager.LayoutParams params = FloatingActionButton.Builder.getDefaultSystemWindowParams(this);
56 |
57 | rightLowerButton = new FloatingActionButton.Builder(this)
58 | .setContentView(fabIconNew)
59 | .setSystemOverlay(true)
60 | .setLayoutParams(params)
61 | .build();
62 |
63 | SubActionButton.Builder rLSubBuilder = new SubActionButton.Builder(this);
64 | ImageView rlIcon1 = new ImageView(this);
65 | ImageView rlIcon2 = new ImageView(this);
66 | ImageView rlIcon3 = new ImageView(this);
67 | ImageView rlIcon4 = new ImageView(this);
68 |
69 | rlIcon1.setImageDrawable(getResources().getDrawable(R.drawable.ic_action_chat_light));
70 | rlIcon2.setImageDrawable(getResources().getDrawable(R.drawable.ic_action_camera_light));
71 | rlIcon3.setImageDrawable(getResources().getDrawable(R.drawable.ic_action_video_light));
72 | rlIcon4.setImageDrawable(getResources().getDrawable(R.drawable.ic_action_place_light));
73 |
74 | // Build the menu with default options: light theme, 90 degrees, 72dp radius.
75 | // Set 4 default SubActionButtons
76 | SubActionButton rlSub1 = rLSubBuilder.setContentView(rlIcon1).build();
77 | SubActionButton rlSub2 = rLSubBuilder.setContentView(rlIcon2).build();
78 | SubActionButton rlSub3 = rLSubBuilder.setContentView(rlIcon3).build();
79 | SubActionButton rlSub4 = rLSubBuilder.setContentView(rlIcon4).build();
80 | rightLowerMenu = new FloatingActionMenu.Builder(this, true)
81 | .addSubActionView(rlSub1, rlSub1.getLayoutParams().width, rlSub1.getLayoutParams().height)
82 | .addSubActionView(rlSub2, rlSub2.getLayoutParams().width, rlSub2.getLayoutParams().height)
83 | .addSubActionView(rlSub3, rlSub3.getLayoutParams().width, rlSub3.getLayoutParams().height)
84 | .addSubActionView(rlSub4, rlSub4.getLayoutParams().width, rlSub4.getLayoutParams().height)
85 | .setStartAngle(180)
86 | .setEndAngle(270)
87 | .attachTo(rightLowerButton)
88 | .build();
89 |
90 | ////////////////////////////////////////////////////////
91 |
92 | // Set up the large red button on the top center side
93 | // With custom button and content sizes and margins
94 | int redActionButtonSize = getResources().getDimensionPixelSize(R.dimen.red_action_button_size);
95 | int redActionButtonMargin = getResources().getDimensionPixelOffset(R.dimen.action_button_margin);
96 | int redActionButtonContentSize = getResources().getDimensionPixelSize(R.dimen.red_action_button_content_size);
97 | int redActionButtonContentMargin = getResources().getDimensionPixelSize(R.dimen.red_action_button_content_margin);
98 | int redActionMenuRadius = getResources().getDimensionPixelSize(R.dimen.red_action_menu_radius);
99 | int blueSubActionButtonSize = getResources().getDimensionPixelSize(R.dimen.blue_sub_action_button_size);
100 | int blueSubActionButtonContentMargin = getResources().getDimensionPixelSize(R.dimen.blue_sub_action_button_content_margin);
101 |
102 | ImageView fabIconStar = new ImageView(this);
103 | fabIconStar.setImageDrawable(getResources().getDrawable(R.drawable.ic_action_important));
104 |
105 | FloatingActionButton.LayoutParams fabIconStarParams = new FloatingActionButton.LayoutParams(redActionButtonContentSize, redActionButtonContentSize);
106 | fabIconStarParams.setMargins(redActionButtonContentMargin,
107 | redActionButtonContentMargin,
108 | redActionButtonContentMargin,
109 | redActionButtonContentMargin);
110 |
111 | WindowManager.LayoutParams params2 = FloatingActionButton.Builder.getDefaultSystemWindowParams(this);
112 | params2.width = redActionButtonSize;
113 | params2.height = redActionButtonSize;
114 |
115 | topCenterButton = new FloatingActionButton.Builder(this)
116 | .setSystemOverlay(true)
117 | .setContentView(fabIconStar, fabIconStarParams)
118 | .setBackgroundDrawable(R.drawable.button_action_red_selector)
119 | .setPosition(FloatingActionButton.POSITION_TOP_CENTER)
120 | .setLayoutParams(params2)
121 | .build();
122 |
123 | // Set up customized SubActionButtons for the right center menu
124 | SubActionButton.Builder tCSubBuilder = new SubActionButton.Builder(this);
125 | tCSubBuilder.setBackgroundDrawable(getResources().getDrawable(R.drawable.button_action_blue_selector));
126 |
127 | SubActionButton.Builder tCRedBuilder = new SubActionButton.Builder(this);
128 | tCRedBuilder.setBackgroundDrawable(getResources().getDrawable(R.drawable.button_action_red_selector));
129 |
130 | FrameLayout.LayoutParams blueContentParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
131 | blueContentParams.setMargins(blueSubActionButtonContentMargin,
132 | blueSubActionButtonContentMargin,
133 | blueSubActionButtonContentMargin,
134 | blueSubActionButtonContentMargin);
135 |
136 | // Set custom layout params
137 | FrameLayout.LayoutParams blueParams = new FrameLayout.LayoutParams(blueSubActionButtonSize, blueSubActionButtonSize);
138 | tCSubBuilder.setLayoutParams(blueParams);
139 | tCRedBuilder.setLayoutParams(blueParams);
140 |
141 | ImageView tcIcon1 = new ImageView(this);
142 | ImageView tcIcon2 = new ImageView(this);
143 | ImageView tcIcon3 = new ImageView(this);
144 | ImageView tcIcon4 = new ImageView(this);
145 | ImageView tcIcon5 = new ImageView(this);
146 | ImageView tcIcon6 = new ImageView(this);
147 |
148 | tcIcon1.setImageDrawable(getResources().getDrawable(R.drawable.ic_action_camera));
149 | tcIcon2.setImageDrawable(getResources().getDrawable(R.drawable.ic_action_picture));
150 | tcIcon3.setImageDrawable(getResources().getDrawable(R.drawable.ic_action_video));
151 | tcIcon4.setImageDrawable(getResources().getDrawable(R.drawable.ic_action_location_found));
152 | tcIcon5.setImageDrawable(getResources().getDrawable(R.drawable.ic_action_headphones));
153 | tcIcon6.setImageDrawable(getResources().getDrawable(R.drawable.ic_action_cancel));
154 |
155 | SubActionButton tcSub1 = tCSubBuilder.setContentView(tcIcon1, blueContentParams).build();
156 | SubActionButton tcSub2 = tCSubBuilder.setContentView(tcIcon2, blueContentParams).build();
157 | SubActionButton tcSub3 = tCSubBuilder.setContentView(tcIcon3, blueContentParams).build();
158 | SubActionButton tcSub4 = tCSubBuilder.setContentView(tcIcon4, blueContentParams).build();
159 | SubActionButton tcSub5 = tCSubBuilder.setContentView(tcIcon5, blueContentParams).build();
160 | SubActionButton tcSub6 = tCRedBuilder.setContentView(tcIcon6, blueContentParams).build();
161 |
162 |
163 | // Build another menu with custom options
164 | topCenterMenu = new FloatingActionMenu.Builder(this, true)
165 | .addSubActionView(tcSub1, tcSub1.getLayoutParams().width, tcSub1.getLayoutParams().height)
166 | .addSubActionView(tcSub2, tcSub2.getLayoutParams().width, tcSub2.getLayoutParams().height)
167 | .addSubActionView(tcSub3, tcSub3.getLayoutParams().width, tcSub3.getLayoutParams().height)
168 | .addSubActionView(tcSub4, tcSub4.getLayoutParams().width, tcSub4.getLayoutParams().height)
169 | .addSubActionView(tcSub5, tcSub5.getLayoutParams().width, tcSub5.getLayoutParams().height)
170 | .addSubActionView(tcSub6, tcSub6.getLayoutParams().width, tcSub6.getLayoutParams().height)
171 | .setRadius(redActionMenuRadius)
172 | .setStartAngle(0)
173 | .setEndAngle(180)
174 | .attachTo(topCenterButton)
175 | .build();
176 |
177 | topCenterMenu.setStateChangeListener(new FloatingActionMenu.MenuStateChangeListener() {
178 | @Override
179 | public void onMenuOpened(FloatingActionMenu menu) {
180 |
181 | }
182 |
183 | @Override
184 | public void onMenuClosed(FloatingActionMenu menu) {
185 | if(serviceWillBeDismissed) {
186 | SystemOverlayMenuService.this.stopSelf();
187 | serviceWillBeDismissed = false;
188 | }
189 | }
190 | });
191 |
192 | // make the red button terminate the service
193 | tcSub6.setOnClickListener(new View.OnClickListener() {
194 | @Override
195 | public void onClick(View v) {
196 | serviceWillBeDismissed = true; // the order is important
197 | topCenterMenu.close(true);
198 | }
199 | });
200 | }
201 |
202 | @Override
203 | public void onDestroy() {
204 | if(rightLowerMenu != null && rightLowerMenu.isOpen()) rightLowerMenu.close(false);
205 | if(topCenterMenu != null && topCenterMenu.isOpen()) topCenterMenu.close(false);
206 | if(rightLowerButton != null) rightLowerButton.detach();
207 | if(topCenterButton != null) topCenterButton.detach();
208 |
209 | super.onDestroy();
210 | }
211 | }
212 |
--------------------------------------------------------------------------------
/samples/src/main/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/samples/src/main/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/samples/src/main/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/samples/src/main/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/samples/src/main/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/samples/src/main/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/samples/src/main/res/drawable-xxhdpi/button_action_blue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/samples/src/main/res/drawable-xxhdpi/button_action_blue.png
--------------------------------------------------------------------------------
/samples/src/main/res/drawable-xxhdpi/button_action_blue_touch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/samples/src/main/res/drawable-xxhdpi/button_action_blue_touch.png
--------------------------------------------------------------------------------
/samples/src/main/res/drawable-xxhdpi/button_action_red.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/samples/src/main/res/drawable-xxhdpi/button_action_red.png
--------------------------------------------------------------------------------
/samples/src/main/res/drawable-xxhdpi/button_action_red_touch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/samples/src/main/res/drawable-xxhdpi/button_action_red_touch.png
--------------------------------------------------------------------------------
/samples/src/main/res/drawable-xxhdpi/ic_action_camera.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/samples/src/main/res/drawable-xxhdpi/ic_action_camera.png
--------------------------------------------------------------------------------
/samples/src/main/res/drawable-xxhdpi/ic_action_camera_light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/samples/src/main/res/drawable-xxhdpi/ic_action_camera_light.png
--------------------------------------------------------------------------------
/samples/src/main/res/drawable-xxhdpi/ic_action_cancel.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/samples/src/main/res/drawable-xxhdpi/ic_action_cancel.png
--------------------------------------------------------------------------------
/samples/src/main/res/drawable-xxhdpi/ic_action_chat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/samples/src/main/res/drawable-xxhdpi/ic_action_chat.png
--------------------------------------------------------------------------------
/samples/src/main/res/drawable-xxhdpi/ic_action_chat_light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/samples/src/main/res/drawable-xxhdpi/ic_action_chat_light.png
--------------------------------------------------------------------------------
/samples/src/main/res/drawable-xxhdpi/ic_action_headphones.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/samples/src/main/res/drawable-xxhdpi/ic_action_headphones.png
--------------------------------------------------------------------------------
/samples/src/main/res/drawable-xxhdpi/ic_action_important.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/samples/src/main/res/drawable-xxhdpi/ic_action_important.png
--------------------------------------------------------------------------------
/samples/src/main/res/drawable-xxhdpi/ic_action_location_found.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/samples/src/main/res/drawable-xxhdpi/ic_action_location_found.png
--------------------------------------------------------------------------------
/samples/src/main/res/drawable-xxhdpi/ic_action_new.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/samples/src/main/res/drawable-xxhdpi/ic_action_new.png
--------------------------------------------------------------------------------
/samples/src/main/res/drawable-xxhdpi/ic_action_new_light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/samples/src/main/res/drawable-xxhdpi/ic_action_new_light.png
--------------------------------------------------------------------------------
/samples/src/main/res/drawable-xxhdpi/ic_action_picture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/samples/src/main/res/drawable-xxhdpi/ic_action_picture.png
--------------------------------------------------------------------------------
/samples/src/main/res/drawable-xxhdpi/ic_action_picture_light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/samples/src/main/res/drawable-xxhdpi/ic_action_picture_light.png
--------------------------------------------------------------------------------
/samples/src/main/res/drawable-xxhdpi/ic_action_place.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/samples/src/main/res/drawable-xxhdpi/ic_action_place.png
--------------------------------------------------------------------------------
/samples/src/main/res/drawable-xxhdpi/ic_action_place_light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/samples/src/main/res/drawable-xxhdpi/ic_action_place_light.png
--------------------------------------------------------------------------------
/samples/src/main/res/drawable-xxhdpi/ic_action_send_now.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/samples/src/main/res/drawable-xxhdpi/ic_action_send_now.png
--------------------------------------------------------------------------------
/samples/src/main/res/drawable-xxhdpi/ic_action_send_now_light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/samples/src/main/res/drawable-xxhdpi/ic_action_send_now_light.png
--------------------------------------------------------------------------------
/samples/src/main/res/drawable-xxhdpi/ic_action_settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/samples/src/main/res/drawable-xxhdpi/ic_action_settings.png
--------------------------------------------------------------------------------
/samples/src/main/res/drawable-xxhdpi/ic_action_video.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/samples/src/main/res/drawable-xxhdpi/ic_action_video.png
--------------------------------------------------------------------------------
/samples/src/main/res/drawable-xxhdpi/ic_action_video_light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/samples/src/main/res/drawable-xxhdpi/ic_action_video_light.png
--------------------------------------------------------------------------------
/samples/src/main/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oguzbilgener/CircularFloatingActionMenu/7614a063f326cbd153ead6b06ba979c6cf40796e/samples/src/main/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/samples/src/main/res/drawable/bottom_bar_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
7 |
8 | -
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/samples/src/main/res/drawable/button_action_blue_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/samples/src/main/res/drawable/button_action_red_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/samples/src/main/res/layout/activity_demo.xml:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/samples/src/main/res/layout/activity_menu_in_scroll_view.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
13 |
14 |
22 |
27 |
28 |
29 |
37 |
38 |
47 |
48 |
49 |
50 |
56 |
61 |
62 |
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/samples/src/main/res/layout/activity_menu_with_custom_action_button.xml:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/samples/src/main/res/layout/activity_menu_with_custom_animation.xml:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/samples/src/main/res/layout/activity_menu_with_fab.xml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/samples/src/main/res/layout/activity_menu_with_overlay.xml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/samples/src/main/res/layout/fragment_demo.xml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/samples/src/main/res/layout/fragment_menu_with_custom_action_button.xml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
17 |
18 |
--------------------------------------------------------------------------------
/samples/src/main/res/layout/fragment_menu_with_custom_animation.xml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/samples/src/main/res/layout/item_scroll_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
16 |
17 |
--------------------------------------------------------------------------------
/samples/src/main/res/menu/demo.xml:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/samples/src/main/res/menu/menu_in_scroll_view.xml:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/samples/src/main/res/menu/menu_with_custom_action_button.xml:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/samples/src/main/res/menu/menu_with_custom_animation.xml:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/samples/src/main/res/menu/menu_with_fab.xml:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/samples/src/main/res/menu/sample.xml:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/samples/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/samples/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #333333
4 |
--------------------------------------------------------------------------------
/samples/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 | 108dp
7 | 48dp
8 |
9 | 16dp
10 | 36dp
11 |
12 | 96dp
13 | 48dp
14 | 16dp
15 |
16 | 120dp
17 | 30dp
18 | 72dp
19 |
20 |
--------------------------------------------------------------------------------
/samples/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | CircularFloatingActionMenu Samples
5 | Hello world!
6 | Settings
7 | Items
8 | Demo Detail
9 | CircularFloatingActionMenu
10 | Floating Action Button
11 | Custom Action Button
12 | Custom Animation
13 | Menu in ScrollView Sample
14 | System Overlay Menu Sample
15 |
16 |
17 |
--------------------------------------------------------------------------------
/samples/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
12 |
13 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':library', ':samples'
2 |
--------------------------------------------------------------------------------