Add initial implementation of a FloatingActionMenu for future use
This commit is contained in:
parent
8a1b379b30
commit
975233829a
13 changed files with 323 additions and 26 deletions
|
@ -34,6 +34,7 @@ dependencies {
|
|||
compile 'com.android.support:design:25.3.1'
|
||||
compile 'com.android.support:recyclerview-v7:25.3.1'
|
||||
compile 'com.android.support:cardview-v7:25.3.1'
|
||||
compile 'com.android.support.constraint:constraint-layout:1.0.2'
|
||||
compile 'com.journeyapps:zxing-android-embedded:3.0.3@aar'
|
||||
compile 'com.google.zxing:core:3.2.1'
|
||||
compile 'commons-codec:commons-codec:1.5'
|
||||
|
@ -47,5 +48,4 @@ dependencies {
|
|||
androidTestCompile 'com.android.support.test.uiautomator:uiautomator-v18:2.1.2'
|
||||
|
||||
androidTestCompile 'org.hamcrest:hamcrest-library:1.3'
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,130 @@
|
|||
package org.shadowice.flocke.andotp;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.constraint.ConstraintLayout;
|
||||
import android.support.design.widget.FloatingActionButton;
|
||||
import android.support.v4.view.ViewCompat;
|
||||
import android.view.View;
|
||||
import android.view.animation.Animation;
|
||||
import android.view.animation.AnimationUtils;
|
||||
import android.view.animation.LinearInterpolator;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
public class FloatingActionMenu {
|
||||
private boolean isFabMenuOpen = false;
|
||||
|
||||
private ConstraintLayout mainLayout;
|
||||
|
||||
private Animation fabOpenAnimation;
|
||||
private Animation fabCloseAnimation;
|
||||
|
||||
private FloatingActionButton baseFloatingActionButton;
|
||||
private FloatingActionButton qrFAB;
|
||||
private FloatingActionButton manualFAB;
|
||||
|
||||
private LinearLayout qrLayout;
|
||||
private LinearLayout manualLayout;
|
||||
|
||||
private FABHandler fabHandler;
|
||||
|
||||
public FloatingActionMenu(Context context, ConstraintLayout mainLayout) {
|
||||
this.mainLayout = mainLayout;
|
||||
|
||||
fabOpenAnimation = AnimationUtils.loadAnimation(context, R.anim.fab_open);
|
||||
fabCloseAnimation = AnimationUtils.loadAnimation(context, R.anim.fab_close);
|
||||
|
||||
baseFloatingActionButton = (FloatingActionButton) mainLayout.findViewById(R.id.baseFloatingActionButton);
|
||||
|
||||
qrFAB = (FloatingActionButton) mainLayout.findViewById(R.id.qrFAB);
|
||||
manualFAB = (FloatingActionButton) mainLayout.findViewById(R.id.manualFAB);
|
||||
|
||||
qrLayout = (LinearLayout) mainLayout.findViewById(R.id.qrLayout);
|
||||
manualLayout = (LinearLayout) mainLayout.findViewById(R.id.manualLayout);
|
||||
|
||||
baseFloatingActionButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
if (isFabMenuOpen)
|
||||
collapse();
|
||||
else
|
||||
expand();
|
||||
}
|
||||
});
|
||||
|
||||
qrFAB.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
if (fabHandler != null)
|
||||
fabHandler.onQRFabClick();
|
||||
collapse();
|
||||
}
|
||||
});
|
||||
|
||||
manualFAB.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
if (fabHandler != null)
|
||||
fabHandler.onManualFabClick();
|
||||
collapse();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void setFABHandler(FABHandler fabHandler) {
|
||||
this.fabHandler = fabHandler;
|
||||
}
|
||||
|
||||
public void show() {
|
||||
mainLayout.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
public void hide() {
|
||||
mainLayout.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
public void expand() {
|
||||
ViewCompat.animate(baseFloatingActionButton)
|
||||
.rotation(45F)
|
||||
.withLayer()
|
||||
.setDuration(300)
|
||||
.setInterpolator(new LinearInterpolator())
|
||||
.start();
|
||||
|
||||
qrLayout.setVisibility(View.VISIBLE);
|
||||
manualLayout.setVisibility(View.VISIBLE);
|
||||
|
||||
qrLayout.startAnimation(fabOpenAnimation);
|
||||
manualLayout.startAnimation(fabOpenAnimation);
|
||||
|
||||
qrFAB.setClickable(true);
|
||||
manualFAB.setClickable(true);
|
||||
|
||||
isFabMenuOpen = true;
|
||||
}
|
||||
|
||||
public void collapse() {
|
||||
ViewCompat.animate(baseFloatingActionButton)
|
||||
.rotation(0F)
|
||||
.withLayer()
|
||||
.setDuration(300)
|
||||
.setInterpolator(new LinearInterpolator())
|
||||
.start();
|
||||
|
||||
qrLayout.startAnimation(fabCloseAnimation);
|
||||
manualLayout.startAnimation(fabCloseAnimation);
|
||||
|
||||
qrLayout.setVisibility(View.GONE);
|
||||
manualLayout.setVisibility(View.GONE);
|
||||
|
||||
qrFAB.setClickable(false);
|
||||
manualFAB.setClickable(false);
|
||||
|
||||
isFabMenuOpen = false;
|
||||
|
||||
}
|
||||
|
||||
public interface FABHandler {
|
||||
void onQRFabClick();
|
||||
void onManualFabClick();
|
||||
}
|
||||
}
|
|
@ -36,7 +36,7 @@ import android.os.Bundle;
|
|||
import android.os.Handler;
|
||||
import android.provider.Settings;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.design.widget.FloatingActionButton;
|
||||
import android.support.constraint.ConstraintLayout;
|
||||
import android.support.v4.app.ActivityCompat;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.support.v4.view.MenuItemCompat;
|
||||
|
@ -61,11 +61,9 @@ import com.google.zxing.integration.android.IntentIntegrator;
|
|||
|
||||
import org.shadowice.flocke.andotp.ItemTouchHelper.SimpleItemTouchHelperCallback;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
private EntriesCardAdapter adapter;
|
||||
private FloatingActionButton fab;
|
||||
private FloatingActionMenu floatingActionMenu;
|
||||
private SimpleItemTouchHelperCallback touchHelperCallback;
|
||||
|
||||
private Handler handler;
|
||||
|
@ -242,12 +240,16 @@ public class MainActivity extends AppCompatActivity {
|
|||
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
|
||||
setSupportActionBar(toolbar);
|
||||
|
||||
fab = (FloatingActionButton) findViewById(R.id.action_scan);
|
||||
fab.setOnClickListener(new View.OnClickListener() {
|
||||
floatingActionMenu = new FloatingActionMenu(this, (ConstraintLayout) findViewById(R.id.fab_main_layout));
|
||||
floatingActionMenu.setFABHandler(new FloatingActionMenu.FABHandler() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
public void onQRFabClick() {
|
||||
scanQRCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onManualFabClick() {
|
||||
}
|
||||
});
|
||||
|
||||
final ProgressBar progressBar = (ProgressBar) findViewById(R.id.progressBar);
|
||||
|
@ -382,14 +384,14 @@ public class MainActivity extends AppCompatActivity {
|
|||
MenuItemCompat.setOnActionExpandListener(searchItem, new MenuItemCompat.OnActionExpandListener() {
|
||||
@Override
|
||||
public boolean onMenuItemActionExpand(MenuItem item) {
|
||||
fab.setVisibility(View.GONE);
|
||||
floatingActionMenu.hide();
|
||||
touchHelperCallback.setDragEnabled(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMenuItemActionCollapse(MenuItem item) {
|
||||
fab.setVisibility(View.VISIBLE);
|
||||
floatingActionMenu.show();
|
||||
touchHelperCallback.setDragEnabled(true);
|
||||
return true;
|
||||
}
|
||||
|
|
18
app/src/main/res/anim/fab_close.xml
Normal file
18
app/src/main/res/anim/fab_close.xml
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:fillAfter="true">
|
||||
<scale
|
||||
android:duration="300"
|
||||
android:fromXScale="1"
|
||||
android:fromYScale="1"
|
||||
android:interpolator="@android:anim/linear_interpolator"
|
||||
android:pivotX="50%"
|
||||
android:pivotY="50%"
|
||||
android:toXScale="0.0"
|
||||
android:toYScale="0.0" />
|
||||
<alpha
|
||||
android:duration="300"
|
||||
android:fromAlpha="1.0"
|
||||
android:interpolator="@android:anim/accelerate_interpolator"
|
||||
android:toAlpha="0.0" />
|
||||
</set>
|
18
app/src/main/res/anim/fab_open.xml
Normal file
18
app/src/main/res/anim/fab_open.xml
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:fillAfter="true">
|
||||
<scale
|
||||
android:duration="300"
|
||||
android:fromXScale="0"
|
||||
android:fromYScale="0"
|
||||
android:interpolator="@android:anim/linear_interpolator"
|
||||
android:pivotX="50%"
|
||||
android:pivotY="50%"
|
||||
android:toXScale="1"
|
||||
android:toYScale="1" />
|
||||
<alpha
|
||||
android:duration="300"
|
||||
android:fromAlpha="0.0"
|
||||
android:interpolator="@android:anim/accelerate_interpolator"
|
||||
android:toAlpha="1.0" />
|
||||
</set>
|
9
app/src/main/res/drawable/ic_camera_white.xml
Normal file
9
app/src/main/res/drawable/ic_camera_white.xml
Normal file
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M9.4,10.5l4.77,-8.26C13.47,2.09 12.75,2 12,2c-2.4,0 -4.6,0.85 -6.32,2.25l3.66,6.35 0.06,-0.1zM21.54,9c-0.92,-2.92 -3.15,-5.26 -6,-6.34L11.88,9h9.66zM21.8,10h-7.49l0.29,0.5 4.76,8.25C21,16.97 22,14.61 22,12c0,-0.69 -0.07,-1.35 -0.2,-2zM8.54,12l-3.9,-6.75C3.01,7.03 2,9.39 2,12c0,0.69 0.07,1.35 0.2,2h7.49l-1.15,-2zM2.46,15c0.92,2.92 3.15,5.26 6,6.34L12.12,15L2.46,15zM13.73,15l-3.9,6.76c0.7,0.15 1.42,0.24 2.17,0.24 2.4,0 4.6,-0.85 6.32,-2.25l-3.66,-6.35 -0.93,1.6z"/>
|
||||
</vector>
|
9
app/src/main/res/drawable/ic_edit_white.xml
Normal file
9
app/src/main/res/drawable/ic_edit_white.xml
Normal file
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z"/>
|
||||
</vector>
|
7
app/src/main/res/drawable/shape_fab_label.xml
Normal file
7
app/src/main/res/drawable/shape_fab_label.xml
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
|
||||
<corners android:radius="@dimen/fab_small_label_corners" />
|
||||
<solid android:color="@color/fab_small_label_background"/>
|
||||
</shape>
|
|
@ -44,12 +44,6 @@
|
|||
|
||||
<include layout="@layout/content_main" />
|
||||
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
android:id="@+id/action_scan"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_margin="@dimen/fab_margin"
|
||||
android:src="@drawable/ic_add_white" />
|
||||
<include layout="@layout/fab_menu" />
|
||||
|
||||
</android.support.design.widget.CoordinatorLayout>
|
||||
|
|
95
app/src/main/res/layout/fab_menu.xml
Normal file
95
app/src/main/res/layout/fab_menu.xml
Normal file
|
@ -0,0 +1,95 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.constraint.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/fab_main_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
android:id="@+id/baseFloatingActionButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/fab_base_vertical_offset"
|
||||
android:layout_marginEnd="@dimen/fab_base_horizontal_offset"
|
||||
android:clickable="true"
|
||||
android:tint="@android:color/white"
|
||||
android:src="@drawable/ic_add_white"
|
||||
app:fabSize="normal"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/fab_main_layout"
|
||||
app:layout_constraintRight_toRightOf="@+id/fab_main_layout" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/qrLayout"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/fab_small_vertical_offset"
|
||||
android:layout_marginEnd="@dimen/fab_small_horizontal_offset"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toTopOf="@+id/manualLayout"
|
||||
app:layout_constraintRight_toRightOf="@+id/fab_main_layout">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/qrLabelTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="@dimen/fab_small_label_offset"
|
||||
android:background="@drawable/shape_fab_label"
|
||||
android:padding="@dimen/fab_small_label_padding"
|
||||
android:text="@string/title_scan_qr"
|
||||
android:textColor="@android:color/white"
|
||||
android:typeface="normal" />
|
||||
|
||||
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
android:id="@+id/qrFAB"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/fab_small_margin"
|
||||
android:clickable="true"
|
||||
android:tint="@android:color/white"
|
||||
android:src="@drawable/ic_camera_white"
|
||||
app:elevation="@dimen/fab_small_elevation"
|
||||
app:fabSize="mini" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/manualLayout"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/fab_small_vertical_offset_base"
|
||||
android:layout_marginEnd="@dimen/fab_small_horizontal_offset"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toTopOf="@+id/baseFloatingActionButton"
|
||||
app:layout_constraintRight_toRightOf="@+id/fab_main_layout" >
|
||||
|
||||
<TextView
|
||||
android:id="@+id/manualLabelTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="@dimen/fab_small_label_offset"
|
||||
android:background="@drawable/shape_fab_label"
|
||||
android:padding="@dimen/fab_small_label_padding"
|
||||
android:text="@string/title_enter_details"
|
||||
android:textColor="@android:color/white"
|
||||
android:typeface="normal" />
|
||||
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
android:id="@+id/manualFAB"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/fab_small_margin"
|
||||
android:clickable="true"
|
||||
android:tint="@android:color/white"
|
||||
android:src="@drawable/ic_edit_white"
|
||||
app:elevation="@dimen/fab_small_elevation"
|
||||
app:fabSize="mini" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</android.support.constraint.ConstraintLayout>
|
|
@ -1,11 +1,13 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="colorPrimary">#388E3C</color>
|
||||
<color name="colorPrimaryDark">#00600F</color>
|
||||
<color name="primary_light">#CFD8DC</color>
|
||||
<color name="colorAccent">#FFCC00</color>
|
||||
<color name="primary_text">#212121</color>
|
||||
<color name="secondary_text">#727272</color>
|
||||
<color name="icons">#FFFFFF</color>
|
||||
<color name="divider">#B6B6B6</color>
|
||||
<color name="colorPrimary">#388E3C</color>
|
||||
<color name="colorPrimaryDark">#00600F</color>
|
||||
<color name="primary_light">#CFD8DC</color>
|
||||
<color name="colorAccent">#FFCC00</color>
|
||||
<color name="primary_text">#212121</color>
|
||||
<color name="secondary_text">#727272</color>
|
||||
<color name="icons">#FFFFFF</color>
|
||||
<color name="divider">#B6B6B6</color>
|
||||
|
||||
<color name="fab_small_label_background">#212121</color>
|
||||
</resources>
|
||||
|
|
|
@ -5,7 +5,18 @@
|
|||
<dimen name="activity_margin_large">32dp</dimen>
|
||||
<dimen name="activity_horizontal_margin">16dp</dimen>
|
||||
<dimen name="activity_vertical_margin">16dp</dimen>
|
||||
<dimen name="fab_margin">16dp</dimen>
|
||||
|
||||
<dimen name="card_corner_radius">0dp</dimen>
|
||||
|
||||
<!-- FAB Menu -->
|
||||
<dimen name="fab_small_elevation">2dp</dimen>
|
||||
<dimen name="fab_small_margin">8dp</dimen>
|
||||
<dimen name="fab_small_horizontal_offset">16dp</dimen>
|
||||
<dimen name="fab_small_vertical_offset">8dp</dimen>
|
||||
<dimen name="fab_small_vertical_offset_base">16dp</dimen>
|
||||
<dimen name="fab_small_label_corners">4dp</dimen>
|
||||
<dimen name="fab_small_label_padding">4dp</dimen>
|
||||
<dimen name="fab_small_label_offset">8dp</dimen>
|
||||
<dimen name="fab_base_horizontal_offset">16dp</dimen>
|
||||
<dimen name="fab_base_vertical_offset">16dp</dimen>
|
||||
</resources>
|
||||
|
|
|
@ -32,6 +32,8 @@
|
|||
<string name="msg_storage_not_accessible">External storage currently not accessible</string>
|
||||
<string name="msg_storage_permissions">Storage permissions not granted</string>
|
||||
|
||||
<string name="title_enter_details">Enter details</string>
|
||||
<string name="title_scan_qr">Scan QR-Code</string>
|
||||
<string name="title_search">Search</string>
|
||||
|
||||
<!-- About dialog -->
|
||||
|
|
Loading…
Reference in a new issue