|
@@ -3,27 +3,38 @@ package com.reactnativenavigation.views;
|
3
|
3
|
import android.animation.Animator;
|
4
|
4
|
import android.animation.AnimatorListenerAdapter;
|
5
|
5
|
import android.graphics.drawable.Drawable;
|
|
6
|
+import android.support.annotation.FloatRange;
|
|
7
|
+import android.support.annotation.NonNull;
|
6
|
8
|
import android.support.design.widget.CoordinatorLayout;
|
7
|
9
|
import android.support.design.widget.FloatingActionButton;
|
8
|
10
|
import android.view.Gravity;
|
9
|
11
|
import android.view.View;
|
10
|
12
|
import android.view.ViewGroup;
|
11
|
13
|
|
|
14
|
+import com.reactnativenavigation.params.FabActionParams;
|
12
|
15
|
import com.reactnativenavigation.params.FabParams;
|
13
|
16
|
import com.reactnativenavigation.utils.ViewUtils;
|
14
|
17
|
|
|
18
|
+import java.util.ArrayList;
|
|
19
|
+
|
15
|
20
|
public class FloatingActionButtonCoordinator {
|
16
|
21
|
|
|
22
|
+ private static final int INITIAL_EXPENDED_FAB_ROTATION = -90;
|
17
|
23
|
private CoordinatorLayout parent;
|
18
|
24
|
private FabParams params;
|
19
|
|
- FloatingActionButton collapsedFab;
|
20
|
|
- FloatingActionButton expendedFab;
|
21
|
|
- final int crossFadeAnimationDuration;
|
|
25
|
+ private FloatingActionButton collapsedFab;
|
|
26
|
+ private FloatingActionButton expendedFab;
|
|
27
|
+ private final int crossFadeAnimationDuration;
|
|
28
|
+ private final int actionSize;
|
|
29
|
+ final int margin = (int) ViewUtils.convertDpToPixel(16);
|
|
30
|
+ private final ArrayList<FloatingActionButton> actions;
|
22
|
31
|
|
23
|
32
|
public FloatingActionButtonCoordinator(CoordinatorLayout parent, FabParams params) {
|
24
|
33
|
this.parent = parent;
|
25
|
34
|
this.params = params;
|
|
35
|
+ actions = new ArrayList<>();
|
26
|
36
|
crossFadeAnimationDuration = parent.getResources().getInteger(android.R.integer.config_shortAnimTime);
|
|
37
|
+ actionSize = (int) ViewUtils.convertDpToPixel(40);
|
27
|
38
|
createCollapsedFab();
|
28
|
39
|
createExpendedFab();
|
29
|
40
|
setStyle();
|
|
@@ -31,19 +42,22 @@ public class FloatingActionButtonCoordinator {
|
31
|
42
|
|
32
|
43
|
private void createCollapsedFab() {
|
33
|
44
|
collapsedFab = createFab(params.collapsedIcon);
|
|
45
|
+ parent.addView(collapsedFab, createFabLayoutParams());
|
34
|
46
|
collapsedFab.setOnClickListener(new View.OnClickListener() {
|
35
|
47
|
@Override
|
36
|
48
|
public void onClick(View v) {
|
37
|
49
|
hideCollapsed();
|
38
|
50
|
showExpended();
|
|
51
|
+ showActions();
|
39
|
52
|
}
|
40
|
53
|
});
|
41
|
54
|
}
|
42
|
55
|
|
43
|
56
|
private void createExpendedFab() {
|
44
|
57
|
expendedFab = createFab(params.expendedIcon);
|
|
58
|
+ parent.addView(expendedFab, createFabLayoutParams());
|
45
|
59
|
expendedFab.setVisibility(View.GONE);
|
46
|
|
- expendedFab.setRotation(-90);
|
|
60
|
+ expendedFab.setRotation(INITIAL_EXPENDED_FAB_ROTATION);
|
47
|
61
|
expendedFab.setOnClickListener(new View.OnClickListener() {
|
48
|
62
|
@Override
|
49
|
63
|
public void onClick(View v) {
|
|
@@ -53,6 +67,13 @@ public class FloatingActionButtonCoordinator {
|
53
|
67
|
});
|
54
|
68
|
}
|
55
|
69
|
|
|
70
|
+ private FloatingActionButton createFab(Drawable icon) {
|
|
71
|
+ FloatingActionButton fab = new FloatingActionButton(parent.getContext());
|
|
72
|
+ fab.setId(ViewUtils.generateViewId());
|
|
73
|
+ fab.setImageDrawable(icon);
|
|
74
|
+ return fab;
|
|
75
|
+ }
|
|
76
|
+
|
56
|
77
|
private void hideCollapsed() {
|
57
|
78
|
animateFab(collapsedFab, 0, 90);
|
58
|
79
|
}
|
|
@@ -90,20 +111,12 @@ public class FloatingActionButtonCoordinator {
|
90
|
111
|
.start();
|
91
|
112
|
}
|
92
|
113
|
|
93
|
|
-
|
94
|
|
- private FloatingActionButton createFab(Drawable icon) {
|
95
|
|
- FloatingActionButton fab = new FloatingActionButton(parent.getContext());
|
96
|
|
- fab.setImageDrawable(icon);
|
97
|
|
- parent.addView(fab, createFabLayoutParams());
|
98
|
|
- return fab;
|
99
|
|
- }
|
100
|
|
-
|
101
|
114
|
private CoordinatorLayout.LayoutParams createFabLayoutParams() {
|
102
|
115
|
final CoordinatorLayout.LayoutParams lp = new CoordinatorLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
103
|
116
|
lp.gravity = Gravity.RIGHT | Gravity.BOTTOM;
|
104
|
|
- final int margin = (int) ViewUtils.convertDpToPixel(16);
|
105
|
117
|
lp.bottomMargin = margin;
|
106
|
118
|
lp.rightMargin = margin;
|
|
119
|
+ lp.topMargin = margin;
|
107
|
120
|
return lp;
|
108
|
121
|
}
|
109
|
122
|
|
|
@@ -114,4 +127,71 @@ public class FloatingActionButtonCoordinator {
|
114
|
127
|
public void show() {
|
115
|
128
|
|
116
|
129
|
}
|
|
130
|
+
|
|
131
|
+ private void showActions() {
|
|
132
|
+ if (actions.size() > 0) {
|
|
133
|
+ return;
|
|
134
|
+ }
|
|
135
|
+
|
|
136
|
+ for (int i = 0; i < params.actions.size(); i++) {
|
|
137
|
+ FloatingActionButton action = createAction(i);
|
|
138
|
+ actions.add(action);
|
|
139
|
+ parent.addView(action);
|
|
140
|
+ }
|
|
141
|
+ }
|
|
142
|
+
|
|
143
|
+ private FloatingActionButton createAction(int index) {
|
|
144
|
+ FabActionParams actionParams = params.actions.get(index);
|
|
145
|
+ FloatingActionButton action = createFab(actionParams.icon);
|
|
146
|
+ action.setLayoutParams(createActionLayoutParams(index));
|
|
147
|
+ // action.setAlpha(0);
|
|
148
|
+ return action;
|
|
149
|
+ }
|
|
150
|
+
|
|
151
|
+ @NonNull
|
|
152
|
+ private CoordinatorLayout.LayoutParams createActionLayoutParams(int actionIndex) {
|
|
153
|
+ CoordinatorLayout.LayoutParams lp = new CoordinatorLayout.LayoutParams(actionSize, actionSize);
|
|
154
|
+ lp.setAnchorId(expendedFab.getId());
|
|
155
|
+ lp.anchorGravity = Gravity.CENTER_HORIZONTAL;
|
|
156
|
+ lp.setBehavior(new ActionBehaviour(expendedFab, (actionIndex + 1) * (actionSize + margin / 2)));
|
|
157
|
+ return lp;
|
|
158
|
+ }
|
|
159
|
+
|
|
160
|
+ public static class ActionBehaviour extends CoordinatorLayout.Behavior<FloatingActionButton> {
|
|
161
|
+ private final int MAX_VALUE = 90;
|
|
162
|
+ private int dependencyId;
|
|
163
|
+ private float yStep;
|
|
164
|
+
|
|
165
|
+ public ActionBehaviour(View anchor, float yStep) {
|
|
166
|
+ this.yStep = yStep;
|
|
167
|
+ this.dependencyId = anchor.getId();
|
|
168
|
+ }
|
|
169
|
+
|
|
170
|
+ @Override
|
|
171
|
+ public boolean layoutDependsOn(CoordinatorLayout parent, FloatingActionButton child, View dependency) {
|
|
172
|
+ return dependency.getId() == dependencyId;
|
|
173
|
+ }
|
|
174
|
+
|
|
175
|
+ @Override
|
|
176
|
+ public boolean onDependentViewChanged(CoordinatorLayout parent, FloatingActionButton child, View dependency) {
|
|
177
|
+ final float dependentValue = dependency.getRotation();
|
|
178
|
+ float fraction = calculateTransitionFraction(dependentValue);
|
|
179
|
+ child.setY(calculateY(parent, fraction));
|
|
180
|
+ child.setAlpha(calculateAlpha(fraction));
|
|
181
|
+ return true;
|
|
182
|
+ }
|
|
183
|
+
|
|
184
|
+ private float calculateAlpha(float fraction) {
|
|
185
|
+ return 1 * fraction;
|
|
186
|
+ }
|
|
187
|
+
|
|
188
|
+ private float calculateY(CoordinatorLayout parent, float fraction) {
|
|
189
|
+ return parent.findViewById(dependencyId).getY() - yStep * fraction;
|
|
190
|
+ }
|
|
191
|
+
|
|
192
|
+ @FloatRange(from=0.0, to=1.0)
|
|
193
|
+ private float calculateTransitionFraction(float dependentValue) {
|
|
194
|
+ return 1 - Math.abs(dependentValue / MAX_VALUE);
|
|
195
|
+ }
|
|
196
|
+ }
|
117
|
197
|
}
|