Skip to content

Commit

Permalink
Merge branch 'release-1.0.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
markormesher committed Mar 27, 2016
2 parents f637a88 + 45224e4 commit 02004ff
Show file tree
Hide file tree
Showing 13 changed files with 9,629 additions and 234 deletions.
57 changes: 32 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,13 @@

[ ![Download](https://api.bintray.com/packages/markormesher/maven/android-fab/images/download.svg) ](https://bintray.com/markormesher/maven/android-fab/_latestVersion)

This library provides a view that creates a clickable floating action button (FAB). The FAB can trigger either a standard click listener, or a open a speed-dial menu with further options. All aspects of the FAB and speed-dial menu are customisable.
This library provides a clickable floating action button (FAB). The FAB can trigger either a standard click listener, or a open a speed-dial menu with further options. All aspects of the FAB and speed-dial menu are customisable.

- [Demo](#demo)
- [Installation](#installation)
- [Usage & Customisation](#usage-customisation)
- [Usage & Customisation](#usage--customisation)
- [Links](#links)



## Demo

![Demonstration of the speed-dial menu](misc/demo.gif)
Expand All @@ -21,15 +19,12 @@ You can try the demo yourself in one of two ways:

2. Download the sample app from the Google Play Store: [Floating Action Button Demo](https://play.google.com/store/apps/details?id=uk.co.markormesher.android_fab.app)



## Installation

### Gradle

compile 'uk.co.markormesher:android-fab:**VERSION**'


### Maven

<dependency>
Expand All @@ -39,20 +34,21 @@ You can try the demo yourself in one of two ways:
<type>pom</type>
</dependency>


### Ivy

<dependency org='uk.co.markormesher' name='android-fab' rev='**VERSION**'>
<artifact name='$AID' ext='pom'></artifact>
</dependency>

## Usage & Customisation

**Note:** all of the instructions below assume that the Floating Action Button is reference by the variable `fab`, i.e.

## Usage & Customisation
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);

### Placing the Parent View
### Placing the FAB in Your Layout

The `FloatingActionButton` view must be placed at the root of your layout, above all other views, and with maximum width and height. This allows the semi-transparent layer to cover the entire layout when the speed-dial menu is opened.
The `FloatingActionButton` view must be placed at the **root** of your layout, **above** all other views, and with **maximum width and height**. This allows the semi-transparent layer to expand and cover the entire layout when the speed-dial menu is opened.

<uk.co.markormesher.android_fab.FloatingActionButton
android:id="@+id/fab"
Expand All @@ -61,17 +57,16 @@ The `FloatingActionButton` view must be placed at the root of your layout, above

### FAB Icon

The icon displayed in the FAB should be set with `fab.setIcon(...)`, passing in the view to use. This view will be inserted into a 24dp x 24dp view group, as per the Android Material Design specs.
The icon displayed in the centre of the FAB should be set with `fab.setIcon(...)`, passing in the `View`, `Drawable` or `Drawable` resource ID to use. This `View` will be centred in a 24dp x 24dp view group, as per the Android Material Design specs.

### FAB Background Colour

The background colour to be used in the FAB should be set with `fab.setBackgroundColor(...)`, passing in an RGBa colour value (e.g. `0xffff9900` for a dark orange).
The background colour to be used for the FAB should be set with `fab.setBackgroundColor(...)`, passing in an RGBa colour value (e.g. `0xffff9900` for a dark orange). Note that this method does **not** take a colour resource ID, so passing in `R.color.some_colour_name` will not work.

### FAB Click Listener

A click listener can be added to the FAB in the same way as any other button:

FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Expand All @@ -81,26 +76,38 @@ A click listener can be added to the FAB in the same way as any other button:

### Speed-Dial Menus

The speed-dial menu can be enabled by creating a class that extends `SpeedDialMenuAdapter` and then calling `setAdapter(...)` on the FAB. An example of this can be seen in [SpeedDialDemoActivity.java](/app/src/main/java/uk/co/markormesher/android_fab/app/SpeedDialDemoActivity.java).
The speed-dial menu can be enabled by creating a class that extends `SpeedDialMenuAdapter` and then calling `setAdapter(...)` on the FAB. This will remove any click listener on the FAB and enable the speed-dial menu.

The adapter has several methods that can be overridden to control the menu:
The adapter class has several methods that can be overridden to control the menu:

`int getCount()` **must** be overridden to return the number of menu items.
##### `int getCount()`

`View[] getViews(Context context, int position)` **must** be overridden to return *exactly* two views for the given position: the first view is the icon, the second view is the label. The second view can be returned as `null` to omit the label for that item. Technically the first view may also be returned as `null` - it won't break anything - but an icon should always be set as the bare minimum. Note that the view at position 0 is the furthest away from the FAB; the view at `getCount() - 1` is the closest.
...**must** be overridden to return the number of menu items.

`int getBackgroundColour(int position)` **may** be override to return the background colour that should be used for the disc as the given position. Note that the view at position 0 is the furthest away from the FAB; the view at `getCount() - 1` is the closest.
##### `MenuItem getViews(Context context, int position)`

`boolean onMenuItemClick(int position)` **may** be override to listen for clicks on the individual menu items. Return `true` to close the menu after the click has been handled (the default behaviour) or `false` to leave it open. Note that the view at position 0 is the furthest away from the FAB; the view at `getCount() - 1` is the closest.
...**must** be overridden to return a `MenuItem` wrapper for the given position. This method will be called to create a wrapper once per menu item. The wrapper allows the icon for a menu item to be specified as a `View`, a `Drawable` or a `Drawable` ID, and allows the label to be specified as a `View`, a `String` or a `String` ID.

`boolean rotateFab()` **may** be overridden to specify whether the FAB should rotate by 1/8th of a turn when the speed-dial menu opens. This is useful for smoothly transitioning between a '+' and 'x' icon.
If multiple properties are specified for the icon or label, the first non-null in the order [`View`, `Drawable` or `String`, resource ID] will be applied. No parameters are required: all label fields could be left as `null` to produce an icon-only menu item for example; everything could be left as `null` to produce a blank menu item, but that would be quite useless.

### Controls
##### `int getBackgroundColour(int position)`

...**may** be overridden to return the background colour that should be used for the disc at the given position.

##### `boolean onMenuItemClick(int position)`

The speed-dial menu can be manually opened and closed with `fab.openSpeedDialMenu()` and `fab.closeSpeedDialMenu()`.
...**may** be overridden to listen for clicks on the individual menu items. Return `true` to close the menu after the click has been handled (the default behaviour) or `false` to leave it open

##### `boolean rotateFab()`

...**may** be overridden to specify whether the FAB should rotate by 1/8th of a turn when the speed-dial menu opens. This is useful for smoothly transitioning between a '+' and 'x' icon.

## Links
---

**Note:** for all methods, the view at position `0` is the furthest away from the FAB; the view at `getCount() - 1` is the closest.

If the functionality has changed such that `getCount()` or `getViews(...)` will have a different output, `fab.rebuildSpeedDialMenu()` must be called to regenerate the speed-dial menu item views.

### Controls

* [My Personal Site](http://markormesher.co.uk)
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, 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).
6 changes: 3 additions & 3 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ buildscript {
}

def version = new Properties()
version['code'] = 3
version['name'] = '0.2.1'
version['code'] = 4
version['name'] = '1.0.0'

def secrets = getSecrets()

Expand Down Expand Up @@ -103,5 +103,5 @@ dependencies {
*==============*/

task start(type: Exec) {
commandLine 'adb', 'shell', 'am', 'start', '-n', 'uk.co.markormesher.android_fab.app/.ClickDemoActivity'
commandLine 'adb', 'shell', 'am', 'start', '-n', 'uk.co.markormesher.android_fab.app/.DemoActivity'
}
4 changes: 1 addition & 3 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
tools:ignore="UnusedAttribute">

<activity
android:name="uk.co.markormesher.android_fab.app.ClickDemoActivity"
android:name=".DemoActivity"
android:label="@string/app_name"
android:launchMode="singleInstance">
<intent-filter>
Expand All @@ -21,8 +21,6 @@
</intent-filter>
</activity>

<activity android:name="uk.co.markormesher.android_fab.app.SpeedDialDemoActivity"/>

</application>

</manifest>

This file was deleted.

191 changes: 191 additions & 0 deletions app/src/main/java/uk/co/markormesher/android_fab/app/DemoActivity.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
package uk.co.markormesher.android_fab.app;

import android.content.Context;
import android.os.Bundle;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import uk.co.markormesher.android_fab.FloatingActionButton;
import uk.co.markormesher.android_fab.SpeedDialMenuAdapter;
import uk.co.markormesher.android_fab.constants.C;

public class DemoActivity extends AppCompatActivity {

private FloatingActionButton fab;
private boolean inClickMode = false;
private int iconSelected = -1;
private int fabColourSelected = -1;
private boolean speedDialColoursEnabled = false;
private boolean speedDialOptionalCloseEnabled = false;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fab_activity);
setTitle(R.string.app_name);

// get reference to FAB
fab = (FloatingActionButton) findViewById(R.id.fab);

// get references to buttons
final Button switchModeButton = (Button) findViewById(R.id.switch_mode);
final Button toggleSpeedDialColoursSwitch = (Button) findViewById(R.id.toggle_colours);
final Button toggleSpeedDialOptionalCloseButton = (Button) findViewById(R.id.toggle_optional_close);
final Button openSpeedDialButton = (Button) findViewById(R.id.open_speed_dial);

switchModeButton.setOnClickListener(v -> {
inClickMode = !inClickMode;
if (inClickMode) {
fab.setOnClickListener(iv -> Toast.makeText(DemoActivity.this, R.string.click_simple, Toast.LENGTH_SHORT).show());
switchModeButton.setText(R.string.switch_mode_1);
} else {
fab.setMenuAdapter(new SpeedDialAdapter());
switchModeButton.setText(R.string.switch_mode_2);
}
toggleSpeedDialColoursSwitch.setEnabled(!inClickMode);
toggleSpeedDialOptionalCloseButton.setEnabled(!inClickMode);
openSpeedDialButton.setEnabled(!inClickMode);
});

findViewById(R.id.change_icon).setOnClickListener(v -> {
int[] icons = new int[]{
R.mipmap.ic_add,
R.mipmap.ic_done,
R.mipmap.ic_cloud,
R.mipmap.ic_swap_horiz,
R.mipmap.ic_swap_vert
};
iconSelected = ++iconSelected % icons.length;
fab.setIcon(icons[iconSelected]);
});

findViewById(R.id.change_button_colour).setOnClickListener(v -> {
int[] colours = new int[]{
0xff0099ff,
0xffff9900,
0xffff0099,
0xff9900ff
};
fabColourSelected = ++fabColourSelected % colours.length;
fab.setBackgroundColour(colours[fabColourSelected]);
});

toggleSpeedDialColoursSwitch.setOnClickListener(v -> {
speedDialColoursEnabled = !speedDialColoursEnabled;
if (speedDialColoursEnabled) {
toggleSpeedDialColoursSwitch.setText(R.string.toggle_colours_2);
} else {
toggleSpeedDialColoursSwitch.setText(R.string.toggle_colours_1);
}
fab.rebuildSpeedDialMenu();
});

toggleSpeedDialOptionalCloseButton.setOnClickListener(v -> {
speedDialOptionalCloseEnabled = !speedDialOptionalCloseEnabled;
if (speedDialOptionalCloseEnabled) {
toggleSpeedDialOptionalCloseButton.setText(R.string.toggle_optional_close_2);
} else {
toggleSpeedDialOptionalCloseButton.setText(R.string.toggle_optional_close_1);
}
fab.rebuildSpeedDialMenu();
});

openSpeedDialButton.setOnClickListener(v -> fab.openSpeedDialMenu());

// set stuff going
findViewById(R.id.switch_mode).performClick();
findViewById(R.id.change_icon).performClick();
}

private class SpeedDialAdapter extends SpeedDialMenuAdapter {

@Override
protected int getCount() {
return speedDialOptionalCloseEnabled ? 4 : 3;
}

@Override
protected MenuItem getViews(Context context, int position) {
switch (position) {
case 0:
// example: View and View
ImageView icon0 = new ImageView(context);
icon0.setImageResource(R.mipmap.ic_done);
TextView label0 = new TextView(context);
label0.setText(getString(R.string.speed_dial_label, position));
return new MenuItem() {{
iconView = icon0;
labelView = label0;
}};

case 1:
// example: Drawable and String
return new MenuItem() {{
iconDrawable = ContextCompat.getDrawable(context, R.mipmap.ic_swap_horiz);
labelString = getString(R.string.speed_dial_label, position);
}};

case 2:
// example: Drawable ID and String
return new MenuItem() {{
iconDrawableId = R.mipmap.ic_swap_vert;
labelString = getString(R.string.speed_dial_label, position);
}};

case 3:
// example: Drawable ID and String ID
return new MenuItem() {{
iconDrawableId = R.mipmap.ic_cloud;
labelStringId = R.string.label_optional_close;
}};

default:
Log.wtf(C.LOG_TAG, "Okay, something went *really* wrong.");
return new MenuItem();
}
}

@Override
protected int getBackgroundColour(int position) {
if (speedDialColoursEnabled) {
int[] colours = new int[]{
0xffff9900,
0xff0099ff,
0xffff0099,
0xff9900ff
};
return colours[position];
}

return super.getBackgroundColour(position);
}

@Override
protected boolean onMenuItemClick(int position) {
if (position == 3) {
AlertDialog.Builder builder = new AlertDialog.Builder(DemoActivity.this);
builder
.setTitle(R.string.menu_close_dialog_title)
.setMessage(R.string.menu_close_dialog_text)
.setPositiveButton(R.string.yes, (dialog, which) -> fab.closeSpeedDialMenu())
.setNegativeButton(R.string.no, null)
.setCancelable(false);
builder.create().show();
return false;
} else {
Toast.makeText(DemoActivity.this, getString(R.string.click_with_item, position), Toast.LENGTH_SHORT).show();
return true;
}
}

@Override
protected boolean rotateFab() {
return iconSelected == 0;
}
}
}
Loading

0 comments on commit 02004ff

Please sign in to comment.