diff --git a/README.md b/README.md index 26631ec..5c6bfb6 100644 --- a/README.md +++ b/README.md @@ -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) @@ -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 @@ -39,20 +34,21 @@ You can try the demo yourself in one of two ways: pom - ### Ivy +## 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. @@ -21,8 +21,6 @@ - - diff --git a/app/src/main/java/uk/co/markormesher/android_fab/app/ClickDemoActivity.java b/app/src/main/java/uk/co/markormesher/android_fab/app/ClickDemoActivity.java deleted file mode 100644 index 33c5de5..0000000 --- a/app/src/main/java/uk/co/markormesher/android_fab/app/ClickDemoActivity.java +++ /dev/null @@ -1,36 +0,0 @@ -package uk.co.markormesher.android_fab.app; - -import android.content.Intent; -import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; -import android.widget.Button; -import android.widget.ImageView; -import android.widget.Toast; -import uk.co.markormesher.android_fab.FloatingActionButton; - -public class ClickDemoActivity extends AppCompatActivity { - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.fab_activity); - setTitle(R.string.click_demo); - - // switch button - Button switchDemoButton = (Button) findViewById(R.id.switch_demo); - switchDemoButton.setText(R.string.goto_speed_dial_demo); - switchDemoButton.setOnClickListener(v -> { - startActivity(new Intent(ClickDemoActivity.this, SpeedDialDemoActivity.class)); - finish(); - }); - - // initialise fab - FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); - ImageView icon = new ImageView(this); - icon.setImageResource(R.mipmap.ic_add); - fab.setIcon(icon); - - // clicks - fab.setOnClickListener(v -> Toast.makeText(ClickDemoActivity.this, R.string.click_simple, Toast.LENGTH_SHORT).show()); - } -} \ No newline at end of file diff --git a/app/src/main/java/uk/co/markormesher/android_fab/app/DemoActivity.java b/app/src/main/java/uk/co/markormesher/android_fab/app/DemoActivity.java new file mode 100644 index 0000000..e72e314 --- /dev/null +++ b/app/src/main/java/uk/co/markormesher/android_fab/app/DemoActivity.java @@ -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; + } + } +} \ No newline at end of file diff --git a/app/src/main/java/uk/co/markormesher/android_fab/app/SpeedDialDemoActivity.java b/app/src/main/java/uk/co/markormesher/android_fab/app/SpeedDialDemoActivity.java deleted file mode 100644 index 253ae85..0000000 --- a/app/src/main/java/uk/co/markormesher/android_fab/app/SpeedDialDemoActivity.java +++ /dev/null @@ -1,122 +0,0 @@ -package uk.co.markormesher.android_fab.app; - -import android.content.Context; -import android.content.Intent; -import android.os.Bundle; -import android.support.v7.app.AlertDialog; -import android.support.v7.app.AppCompatActivity; -import android.view.View; -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; - -public class SpeedDialDemoActivity extends AppCompatActivity { - - private FloatingActionButton fab; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.fab_activity); - setTitle(R.string.speed_dial_demo); - - // switch button - Button switchDemoButton = (Button) findViewById(R.id.switch_demo); - switchDemoButton.setText(R.string.goto_click_demo); - switchDemoButton.setOnClickListener(v -> { - startActivity(new Intent(SpeedDialDemoActivity.this, ClickDemoActivity.class)); - finish(); - }); - - // initialise fab - fab = (FloatingActionButton) findViewById(R.id.fab); - ImageView icon = new ImageView(this); - icon.setImageResource(R.mipmap.ic_add); - fab.setIcon(icon); - fab.setBackgroundColour(0xffff4081); - - // set up speed-dial - fab.setMenuAdapter(new DemoAdapter()); - } - - private class DemoAdapter extends SpeedDialMenuAdapter { - - @Override - protected int getCount() { - return 4; - } - - @Override - protected View[] getViews(Context context, int position) { - // make views - ImageView icon = new ImageView(context); - TextView label = new TextView(context); - - // set content - switch (position) { - case 0: - icon.setImageResource(R.mipmap.ic_cloud); - label.setText(R.string.label_optional_close); - break; - - case 1: - icon.setImageResource(R.mipmap.ic_done); - label.setText(R.string.label_done); - break; - - case 2: - icon.setImageResource(R.mipmap.ic_swap_horiz); - label.setText(R.string.label_swap_h); - break; - - case 3: - icon.setImageResource(R.mipmap.ic_swap_vert); - label.setText(R.string.label_swap_v); - break; - - } - - View[] output = new View[2]; - output[0] = icon; - output[1] = label; - return output; - } - - @Override - protected int getBackgroundColour(int position) { - if (position == 0) return 0xffff9900; - - return super.getBackgroundColour(position); - } - - @Override - protected boolean onMenuItemClick(int position) { - // possibly keep the menu open - if (position == 0) { - AlertDialog.Builder builder = new AlertDialog.Builder(SpeedDialDemoActivity.this); - builder - .setTitle(R.string.menu_close_dialog_title) - .setMessage(R.string.menu_close_dialog_text) - .setPositiveButton(R.string.yes, null) - .setNegativeButton(R.string.no, (dialog, which) -> fab.closeSpeedDialMenu()) - .setCancelable(false); - builder.create().show(); - return false; - } - - // otherwise, show a message... - Toast.makeText(SpeedDialDemoActivity.this, getString(R.string.click_with_item, position), Toast.LENGTH_SHORT).show(); - - // ...and close the menu - return true; - } - - @Override - protected boolean rotateFab() { - return true; - } - } -} \ No newline at end of file diff --git a/app/src/main/res/layout/fab_activity.xml b/app/src/main/res/layout/fab_activity.xml index ede97fa..b3c30f4 100644 --- a/app/src/main/res/layout/fab_activity.xml +++ b/app/src/main/res/layout/fab_activity.xml @@ -5,12 +5,60 @@ android:layout_width="match_parent" android:layout_height="match_parent"> -