diff --git a/README.md b/README.md index ac2fc50..69c524e 100644 --- a/README.md +++ b/README.md @@ -18,14 +18,14 @@ You can try the demo in one of two ways: ### Gradle - compile 'uk.co.markormesher:android-fab:2.0.0' + compile 'uk.co.markormesher:android-fab:2.3.1' ### Maven uk.co.markormesher android-fab - 2.0.0 + 2.3.1 pom @@ -43,7 +43,7 @@ See [app/proguard-rules.pro](app/proguard-rules.pro) for an example. // Java FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); - + // Kotlin (without Android extensions) val fab = findViewById(R.id.fab) as FloatingActionButton @@ -63,17 +63,17 @@ The FAB can be positioned in any of the four corners of the activity via XML or // Java fab.setButtonPosition(POSITION_BOTTOM | POSITION_END); - + // Kotlin fab.setButtonPosition(POSITION_BOTTOM.or(POSITION_END)) - + // XML - + The FAB is aware of text-direction (right-to-left or left-to-right) and adjusts the meaning of "start" and "end" positions accordingly. This functionality can be overridden using the named constants for left and right. ### FAB Icon @@ -82,10 +82,10 @@ The icon displayed in the centre of the FAB can be set via XML using a `Drawable // Java fab.setButtonIconResource(R.drawable.ic_add); - + // Kotlin fab.setButtonIconResource(R.drawable.ic_add) - + // XML // ... @@ -129,7 +129,7 @@ A click listener can be added to the FAB in the same way as any other button. Th ### Speed-Dial Menu -The speed-dial menu is enabled by creating a class that extends `SpeedDialMenuAdapter` and passing it to `fab.setSpeedDialMenuAdapter(...)`. The adapter class methods are [documented in-situ](fab/src/main/java/uk/co/markormesher/android_fab/SpeedDialMenuAdapter.kt). +The speed-dial menu is enabled by creating a class that extends `SpeedDialMenuAdapter` and passing it to `fab.setSpeedDialMenuAdapter(...)`. The adapter class methods are [documented in-situ](fab/src/main/kotlin/uk/co/markormesher/android_fab/SpeedDialMenuAdapter.kt). ### Speed-Dial Menu Content Cover @@ -139,7 +139,7 @@ The colour of the content cover can be set programmatically with `fab.setContent // Java fab.setContentCoverColour(0xffff9900); - + // Kotlin fab.setContentCoverColour(0xffff9900.toInt()) @@ -148,7 +148,7 @@ The cover can be enabled/disabled programmatically with `fab.setContentCoverEnab // Java fab.setContentCoverEnabled(true); fab.setContentCoverEnabled(false); - + // Kotlin fab.setContentCoverEnabled(true) fab.setContentCoverEnabled(false) @@ -164,7 +164,7 @@ State change events are fired when the speed-dial menu opens or closes, which ca // ... } }); - + // Kotlin fab.setOnSpeedDialMenuOpenListener { floatingActionButton -> // ... @@ -172,10 +172,28 @@ State change events are fired when the speed-dial menu opens or closes, which ca ### Show/Hide Controls -The FAB can be hidden and shown with the `fab.hide()` and `fab.show()` methods, and the method `fab.isShown()` will return a boolean indicating the current state. These methods animate the FAB in and out of visibility. If the speed-dial menu is open when `.hide()` is called it will be closed. +The FAB can be hidden and shown with the `fab.hide()` and `fab.show()` methods, and the method `fab.isShown()` will return a boolean indicating the current state. These methods animate the FAB in and out of visibility. If the speed-dial menu is open when `.hide()` is called it will be closed. The speed-dial menu can be manually opened and closed with `fab.openSpeedDialMenu()` and `fab.closeSpeedDialMenu()`. These methods will do nothing if no speed-dial menu adapter is set, if an adapter is set but disabled, if the FAB is hidden, or if they are called when the menu is already in the indicated state (i.e. `fab.openSpeedDialMenu()` will do nothing if the menu is already open). +### Access to Underlying Views + +The FAB's key underlying views can be accessed using the three properties/methods detailed below: + + // Java + fab.getCardView() // the card behind the button itself + fab.getContentCoverView() // the view that obscures content behind the speed-dial menu + fab.getIconWrapper() // the wrapper used to place icons in the button + + // Kotlin + fab.cardView + fab.contentCoverView + fab.iconWrapper + +The card view is implemented as a `CardView` on SDK 21+ and a `LinearLayout` on SDK 20 and below. + +The content cover view and icon wrapper are implemented as a `View` and `LinearLayout` respectively on all SDKs. + ### Note: Click Action Priority As per Material Design specs, the FAB functions as a regular button **or** a trigger for the speed-dial menu, but not both. For this reason, the click listener and the speed-dial menu are never invoked at the same time. @@ -183,7 +201,7 @@ As per Material Design specs, the FAB functions as a regular button **or** a tri The speed-dial menu is given priority: when the FAB is clicked the speed-dial menu will be shown if the speed-dial menu adapter is non-null, the adapter's `isEnabled()` function returns `true` and the adapter's `getCount()` returns a number greater than zero. Otherwise, the FAB's click listener will be called (if it has been set). Setting a speed-dial menu adapter does not remove the click listener, and setting a click listener does not remove the speed-dial menu adapter. For an example of how the two operation modes interact, check the demo app's source code. - + To receive state change updates when the speed-dial menu is opened or closed, use the open/close listeners described above. ### Note: State Preservation diff --git a/app/build.gradle b/app/build.gradle index ec85127..2844f79 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,10 +1,14 @@ buildscript { repositories { jcenter() + maven { + url "https://maven.google.com" + } + google() } dependencies { - classpath 'com.android.tools.build:gradle:2.3.0' + classpath 'com.android.tools.build:gradle:3.1.3' } } @@ -16,14 +20,14 @@ apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' android { - compileSdkVersion 26 - buildToolsVersion "26.0.1" + compileSdkVersion 27 + buildToolsVersion '27.0.3' defaultConfig { applicationId "uk.co.markormesher.android_fab.app" minSdkVersion 14 - targetSdkVersion 26 + targetSdkVersion 27 versionCode properties['version_code'] versionName properties['version_name'] @@ -58,10 +62,6 @@ android { } debug { - // signing - //noinspection GroovyAssignabilityCheck - signingConfig signingConfigs.main - // minify minifyEnabled false @@ -74,12 +74,17 @@ android { repositories { jcenter() + maven { + url "https://maven.google.com" + } + google() } dependencies { - compile fileTree(include: ['*.jar'], dir: 'libs') - compile 'com.android.support:support-v4:26.0.1' - compile 'com.android.support:appcompat-v7:26.0.1' - compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version" - compile project(':fab') + implementation fileTree(include: ['*.jar'], dir: 'libs') + implementation 'com.android.support:support-v4:27.1.1' + implementation 'com.android.support:design:27.1.1' + implementation 'com.android.support:appcompat-v7:27.1.1' + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation project(':fab') } diff --git a/app/src/main/kotlin/uk/co/markormesher/android_fab/app/DemoActivity.kt b/app/src/main/kotlin/uk/co/markormesher/android_fab/app/DemoActivity.kt index 9a5aeb2..fb8b124 100644 --- a/app/src/main/kotlin/uk/co/markormesher/android_fab/app/DemoActivity.kt +++ b/app/src/main/kotlin/uk/co/markormesher/android_fab/app/DemoActivity.kt @@ -1,13 +1,16 @@ package uk.co.markormesher.android_fab.app import android.content.Context +import android.graphics.Typeface import android.os.* import android.support.annotation.StringRes +import android.support.design.widget.Snackbar import android.support.v7.app.AppCompatActivity import android.view.KeyEvent import android.view.Menu import android.view.MenuItem import android.view.MotionEvent +import android.widget.TextView import android.widget.Toast import kotlinx.android.synthetic.main.demo_activity.* import uk.co.markormesher.android_fab.FloatingActionButton @@ -63,14 +66,21 @@ class DemoActivity: AppCompatActivity() { Pair("Faint Orange", 0xccff9900.toInt()) ) + private val snackbarEnabledOptions = arrayOf( + Pair("Off", 0), + Pair("On", 1) + ) + private var buttonShown = 0 private var buttonPosition = 0 private var buttonBackgroundColour = 0 private var buttonIcon = 0 private var speedDialSize = 0 private var contentCoverColour = 0 + private var snackbarEnabled = 0 private var activeToast: Toast? = null + private var snackbar: Snackbar? = null private var clickCounter = 0 private var stressTestActive = false @@ -99,6 +109,14 @@ class DemoActivity: AppCompatActivity() { return true } + override fun onPrepareItemLabel(context: Context, position: Int, label: TextView) { + // make the first item bold if there are multiple items + // (this isn't a design pattern, it's just to demo the functionality) + if (position == 0 && speedDialSize > 1) { + label.setTypeface(label.typeface, Typeface.BOLD) + } + } + // rotate the "+" icon only override fun fabRotationDegrees(): Float = if (buttonIcon == 0) 135F else 0F } @@ -121,6 +139,7 @@ class DemoActivity: AppCompatActivity() { updateButtonIcon() updateSpeedDialSize() updateContentCoverColour() + updateSnackbarEnabled() if (stressTestActive) { startStressTest() @@ -135,6 +154,7 @@ class DemoActivity: AppCompatActivity() { outState.putInt("buttonIcon", buttonIcon) outState.putInt("speedDialSize", speedDialSize) outState.putInt("contentCoverColour", contentCoverColour) + outState.putInt("snackbarEnabled", snackbarEnabled) outState.putBoolean("stressTestActive", stressTestActive) } @@ -147,6 +167,7 @@ class DemoActivity: AppCompatActivity() { buttonIcon = savedInstanceState.getInt("buttonIcon") speedDialSize = savedInstanceState.getInt("speedDialSize") contentCoverColour = savedInstanceState.getInt("contentCoverColour") + snackbarEnabled = savedInstanceState.getInt("snackbarEnabled") stressTestActive = savedInstanceState.getBoolean("stressTestActive") } @@ -229,6 +250,15 @@ class DemoActivity: AppCompatActivity() { contentCoverColour = (contentCoverColour + contentCoverColourOptions.size - 1).rem(contentCoverColourOptions.size) updateContentCoverColour() } + + set_snackbar_enabled_next.setOnClickListener { + snackbarEnabled = (snackbarEnabled + 1).rem(snackbarEnabledOptions.size) + updateSnackbarEnabled() + } + set_snackbar_enabled_prev.setOnClickListener { + snackbarEnabled = (snackbarEnabled + snackbarEnabledOptions.size - 1).rem(snackbarEnabledOptions.size) + updateSnackbarEnabled() + } } private fun toast(@StringRes str: Int) { @@ -275,6 +305,16 @@ class DemoActivity: AppCompatActivity() { fab.setContentCoverColour(contentCoverColourOptions[contentCoverColour].second) } + private fun updateSnackbarEnabled() { + snackbar_enabled.text = snackbarEnabledOptions[snackbarEnabled].first + if (snackbarEnabled == 1) { + snackbar = Snackbar.make(root_view, "Hey there!", Snackbar.LENGTH_INDEFINITE) + snackbar?.show() + } else { + snackbar?.dismiss() + } + } + private fun startStressTest() { stressTestActive = true if (Build.VERSION.SDK_INT < 24) { diff --git a/app/src/main/res/layout/demo_activity.xml b/app/src/main/res/layout/demo_activity.xml index 913c5be..4afbce5 100644 --- a/app/src/main/res/layout/demo_activity.xml +++ b/app/src/main/res/layout/demo_activity.xml @@ -1,5 +1,5 @@ - + + +