Skip to content
This repository was archived by the owner on Jan 30, 2021. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package com.oguzdev.circularfloatingactionmenu.library;

import android.app.Activity;
import android.content.ClipData;
import android.content.Context;
import android.graphics.Path;
import android.graphics.PathMeasure;
Expand Down Expand Up @@ -88,15 +89,15 @@ public FloatingActionMenu(View mainActionView,

// Find items with undefined sizes
for(final Item item : subActionItems) {
if(item.width == 0 || item.height == 0) {
// Figure out the size by temporarily adding it to the Activity content view hierarchy
// and ask the size from the system
((ViewGroup) getActivityContentView()).addView(item.view);
// Make item view invisible, just in case
item.view.setAlpha(0);
// Wait for the right time
item.view.post(new ItemViewQueueListener(item));
}
if (item.width == 0 || item.height == 0) {
// Figure out the size by temporarily adding it to the Activity content view hierarchy
// and ask the size from the system
((ViewGroup) getActivityContentView()).addView(item.view);
// Make item view invisible, just in case
item.view.setAlpha(0);
// Wait for the right time
item.view.post(new ItemViewQueueListener(item));
}
}
}

Expand All @@ -121,29 +122,35 @@ public void open(boolean animated) {
// It is required that these Item views are not currently added to any parent
// Because they are supposed to be added to the Activity content view,
// just before the animation starts
if (subActionItems.get(i).view.getParent() != null) {
throw new RuntimeException("All of the sub action items have to be independent from a parent.");
}
// Initially, place all items right at the center of the main action view
// Because they are supposed to start animating from that point.
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(subActionItems.get(i).width, subActionItems.get(i).height, Gravity.TOP | Gravity.LEFT);
params.setMargins(center.x - subActionItems.get(i).width / 2, center.y - subActionItems.get(i).height / 2, 0, 0);
//
((ViewGroup) getActivityContentView()).addView(subActionItems.get(i).view, params);
Item item = subActionItems.get(i);
if (item.view.getParent() != null) {
throw new RuntimeException("All of the sub action items have to be independent from a parent.");
}

// Initially, place all items right at the center of the main action view
// Because they are supposed to start animating from that point.
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(item.width, item.height, Gravity.TOP | Gravity.LEFT);
params.setMargins(center.x - item.width / 2, center.y - item.height / 2, 0, 0);
//
((ViewGroup) getActivityContentView()).addView(item.view, params);
}

getActivityContentView().invalidate();
getActivityContentView().requestLayout();
// Tell the current MenuAnimationHandler to animate from the center
animationHandler.animateMenuOpening(center);
}
else {
// If animations are disabled, just place each of the items to their calculated destination positions.
for (int i = 0; i < subActionItems.size(); i++) {
// This is currently done by giving them large margins
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(subActionItems.get(i).width, subActionItems.get(i).height, Gravity.TOP | Gravity.LEFT);
params.setMargins(subActionItems.get(i).x, subActionItems.get(i).y, 0, 0);
subActionItems.get(i).view.setLayoutParams(params);
// Because they are placed into the main content view of the Activity,
// which is itself a FrameLayout
((ViewGroup) getActivityContentView()).addView(subActionItems.get(i).view, params);
Item item = subActionItems.get(i);
// This is currently done by giving them large margins
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(item.width, item.height, Gravity.TOP | Gravity.LEFT);
params.setMargins(item.x, item.y, 0, 0);
item.view.setLayoutParams(params);
// Because they are placed into the main content view of the Activity,
// which is itself a FrameLayout
((ViewGroup) getActivityContentView()).addView(item.view, params);
}
}
// do not forget to specify that the menu is open.
Expand All @@ -170,7 +177,8 @@ public void close(boolean animated) {
else {
// If animations are disabled, just detach each of the Item views from the Activity content view.
for (int i = 0; i < subActionItems.size(); i++) {
((ViewGroup) getActivityContentView()).removeView(subActionItems.get(i).view);
Item item = subActionItems.get(i);
((ViewGroup) getActivityContentView()).removeView(item.view);
}
}
// do not forget to specify that the menu is now closed.
Expand Down Expand Up @@ -215,9 +223,12 @@ public void updateItemPositions() {
// Simply update layout params for each item
for (int i = 0; i < subActionItems.size(); i++) {
// This is currently done by giving them large margins
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(subActionItems.get(i).width, subActionItems.get(i).height, Gravity.TOP | Gravity.LEFT);
params.setMargins(subActionItems.get(i).x, subActionItems.get(i).y, 0, 0);
subActionItems.get(i).view.setLayoutParams(params);
Item item = subActionItems.get(i);
if (View.INVISIBLE != item.view.getVisibility()) {
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(item.width, item.height, Gravity.TOP | Gravity.LEFT);
params.setMargins(item.x, item.y, 0, 0);
item.view.setLayoutParams(params);
}
}
}

Expand Down Expand Up @@ -265,21 +276,37 @@ private void calculateItemPositions() {

// Prevent overlapping when it is a full circle
int divisor;
if(Math.abs(endAngle - startAngle) >= 360 || subActionItems.size() <= 1) {
divisor = subActionItems.size();
int size = getVisibleSubActionsCount();
if(Math.abs(endAngle - startAngle) >= 360 || size <= 1) {
divisor = size;
}
else {
divisor = subActionItems.size() -1;
divisor = size -1;
}

int visibleCounter = 0;
// Measure this path, in order to find points that have the same distance between each other
for(int i=0; i<subActionItems.size(); i++) {
float[] coords = new float[] {0f, 0f};
measure.getPosTan((i) * measure.getLength() / divisor, coords, null);
// get the x and y values of these points and set them to each of sub action items.
subActionItems.get(i).x = (int) coords[0] - subActionItems.get(i).width / 2;
subActionItems.get(i).y = (int) coords[1] - subActionItems.get(i).height / 2;
Item item = subActionItems.get(i);
if (View.INVISIBLE != item.view.getVisibility()) {
float[] coords = new float[] {0f, 0f};
measure.getPosTan((visibleCounter++) * measure.getLength() / divisor, coords, null);
// get the x and y values of these points and set them to each of sub action items.
item.x = (int) coords[0] - item.width / 2;
item.y = (int) coords[1] - item.height / 2;
}
}
}

private int getVisibleSubActionsCount() {
int size = 0;
for(int i=0; i<subActionItems.size(); i++) {
Item item = subActionItems.get(i);
if (View.INVISIBLE != item.view.getVisibility()) {
size ++;
}
}
return size;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,30 +38,30 @@ public void animateMenuOpening(Point center) {

Animator lastAnimation = null;
for (int i = 0; i < menu.getSubActionItems().size(); i++) {

menu.getSubActionItems().get(i).view.setScaleX(0);
menu.getSubActionItems().get(i).view.setScaleY(0);
menu.getSubActionItems().get(i).view.setAlpha(0);

PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat(View.TRANSLATION_X, menu.getSubActionItems().get(i).x - center.x + menu.getSubActionItems().get(i).width / 2);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, menu.getSubActionItems().get(i).y - center.y + menu.getSubActionItems().get(i).height / 2);
PropertyValuesHolder pvhR = PropertyValuesHolder.ofFloat(View.ROTATION, 720);
PropertyValuesHolder pvhsX = PropertyValuesHolder.ofFloat(View.SCALE_X, 1);
PropertyValuesHolder pvhsY = PropertyValuesHolder.ofFloat(View.SCALE_Y, 1);
PropertyValuesHolder pvhA = PropertyValuesHolder.ofFloat(View.ALPHA, 1);

final ObjectAnimator animation = ObjectAnimator.ofPropertyValuesHolder(menu.getSubActionItems().get(i).view, pvhX, pvhY, pvhR, pvhsX, pvhsY, pvhA);
animation.setDuration(DURATION);
animation.setInterpolator(new OvershootInterpolator(0.9f));
animation.addListener(new SubActionItemAnimationListener(menu.getSubActionItems().get(i), ActionType.OPENING));

if(i == 0) {
lastAnimation = animation;
}

// Put a slight lag between each of the menu items to make it asymmetric
animation.setStartDelay((menu.getSubActionItems().size() - i) * LAG_BETWEEN_ITEMS);
animation.start();
FloatingActionMenu.Item item = menu.getSubActionItems().get(i);
item.view.setScaleX(0);
item.view.setScaleY(0);
item.view.setAlpha(0);

PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat(View.TRANSLATION_X, item.x - center.x + item.width / 2);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, item.y - center.y + item.height / 2);
PropertyValuesHolder pvhR = PropertyValuesHolder.ofFloat(View.ROTATION, 720);
PropertyValuesHolder pvhsX = PropertyValuesHolder.ofFloat(View.SCALE_X, 1);
PropertyValuesHolder pvhsY = PropertyValuesHolder.ofFloat(View.SCALE_Y, 1);
PropertyValuesHolder pvhA = PropertyValuesHolder.ofFloat(View.ALPHA, 1);

final ObjectAnimator animation = ObjectAnimator.ofPropertyValuesHolder(item.view, pvhX, pvhY, pvhR, pvhsX, pvhsY, pvhA);
animation.setDuration(DURATION);
animation.setInterpolator(new OvershootInterpolator(0.9f));
animation.addListener(new SubActionItemAnimationListener(item, ActionType.OPENING));

if (i == 0) {
lastAnimation = animation;
}

// Put a slight lag between each of the menu items to make it asymmetric
animation.setStartDelay((menu.getSubActionItems().size() - i) * LAG_BETWEEN_ITEMS);
animation.start();
}
if(lastAnimation != null) {
lastAnimation.addListener(new LastAnimationListener());
Expand All @@ -77,24 +77,25 @@ public void animateMenuClosing(Point center) {

Animator lastAnimation = null;
for (int i = 0; i < menu.getSubActionItems().size(); i++) {
PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat(View.TRANSLATION_X, - (menu.getSubActionItems().get(i).x - center.x + menu.getSubActionItems().get(i).width / 2));
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, - (menu.getSubActionItems().get(i).y - center.y + menu.getSubActionItems().get(i).height / 2));
PropertyValuesHolder pvhR = PropertyValuesHolder.ofFloat(View.ROTATION, -720);
PropertyValuesHolder pvhsX = PropertyValuesHolder.ofFloat(View.SCALE_X, 0);
PropertyValuesHolder pvhsY = PropertyValuesHolder.ofFloat(View.SCALE_Y, 0);
PropertyValuesHolder pvhA = PropertyValuesHolder.ofFloat(View.ALPHA, 0);

final ObjectAnimator animation = ObjectAnimator.ofPropertyValuesHolder(menu.getSubActionItems().get(i).view, pvhX, pvhY, pvhR, pvhsX, pvhsY, pvhA);
animation.setDuration(DURATION);
animation.setInterpolator(new AccelerateDecelerateInterpolator());
animation.addListener(new SubActionItemAnimationListener(menu.getSubActionItems().get(i), ActionType.CLOSING));

if(i == 0) {
lastAnimation = animation;
}

animation.setStartDelay((menu.getSubActionItems().size() - i) * LAG_BETWEEN_ITEMS);
animation.start();
FloatingActionMenu.Item item = menu.getSubActionItems().get(i);
PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat(View.TRANSLATION_X, -(item.x - center.x + item.width / 2));
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, -(item.y - center.y + item.height / 2));
PropertyValuesHolder pvhR = PropertyValuesHolder.ofFloat(View.ROTATION, -720);
PropertyValuesHolder pvhsX = PropertyValuesHolder.ofFloat(View.SCALE_X, 0);
PropertyValuesHolder pvhsY = PropertyValuesHolder.ofFloat(View.SCALE_Y, 0);
PropertyValuesHolder pvhA = PropertyValuesHolder.ofFloat(View.ALPHA, 0);

final ObjectAnimator animation = ObjectAnimator.ofPropertyValuesHolder(item.view, pvhX, pvhY, pvhR, pvhsX, pvhsY, pvhA);
animation.setDuration(DURATION);
animation.setInterpolator(new AccelerateDecelerateInterpolator());
animation.addListener(new SubActionItemAnimationListener(item, ActionType.CLOSING));

if (i == 0) {
lastAnimation = animation;
}

animation.setStartDelay((menu.getSubActionItems().size() - i) * LAG_BETWEEN_ITEMS);
animation.start();
}
if(lastAnimation != null) {
lastAnimation.addListener(new LastAnimationListener());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;

Expand Down Expand Up @@ -107,12 +108,20 @@ protected void onCreate(Bundle savedInstanceState) {
lcIcon5.setImageDrawable(getResources().getDrawable(R.drawable.ic_action_headphones));

// Build another menu with custom options
SubActionButton build1 = lCSubBuilder.setContentView(lcIcon1, blueContentParams).build();
SubActionButton build2 = lCSubBuilder.setContentView(lcIcon2, blueContentParams).build();
SubActionButton build3 = lCSubBuilder.setContentView(lcIcon3, blueContentParams).build();
SubActionButton build4 = lCSubBuilder.setContentView(lcIcon4, blueContentParams).build();
SubActionButton build5 = lCSubBuilder.setContentView(lcIcon5, blueContentParams).build();

build3.setVisibility(View.INVISIBLE);

FloatingActionMenu leftCenterMenu = new FloatingActionMenu.Builder(this)
.addSubActionView(lCSubBuilder.setContentView(lcIcon1, blueContentParams).build())
.addSubActionView(lCSubBuilder.setContentView(lcIcon2, blueContentParams).build())
.addSubActionView(lCSubBuilder.setContentView(lcIcon3, blueContentParams).build())
.addSubActionView(lCSubBuilder.setContentView(lcIcon4, blueContentParams).build())
.addSubActionView(lCSubBuilder.setContentView(lcIcon5, blueContentParams).build())
.addSubActionView(build1)
.addSubActionView(build2)
.addSubActionView(build3)
.addSubActionView(build4)
.addSubActionView(build5)
.setRadius(redActionMenuRadius)
.setStartAngle(70)
.setEndAngle(-70)
Expand Down