Skip to content
This repository was archived by the owner on Jan 30, 2021. It is now read-only.

Support centerAt to center menu layout around a different view #103

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
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 @@ -35,6 +35,10 @@ public class FloatingActionMenu {

/** Reference to the view (usually a button) to trigger the menu to show */
private View mainActionView;
/** Optional reference to the view around which to center the menu (if differs from mainActionView) */
private View centeringView;
/** Optional reference to a point around which to center the menu. If specified this will take precedence over centeringView. */
private Point centeringPoint;
/** The angle (in degrees, modulus 360) which the circular menu starts from */
private int startAngle;
/** The angle (in degrees, modulus 360) which the circular menu ends at */
Expand All @@ -61,14 +65,20 @@ public class FloatingActionMenu {
/**
* Constructor that takes the parameters collected using {@link FloatingActionMenu.Builder}
* @param mainActionView
* @param centeringView
* @param centeringPoint
* @param startAngle
* @param endAngle
* @param radius
* @param subActionItems
* @param animationHandler
* @param animated
* @param stateChangeListener
* @param systemOverlay
*/
public FloatingActionMenu(final View mainActionView,
final View centeringView,
final Point centeringPoint,
int startAngle,
int endAngle,
int radius,
Expand All @@ -78,6 +88,8 @@ public FloatingActionMenu(final View mainActionView,
MenuStateChangeListener stateChangeListener,
final boolean systemOverlay) {
this.mainActionView = mainActionView;
this.centeringView = centeringView;
this.centeringPoint = centeringPoint;
this.startAngle = startAngle;
this.endAngle = endAngle;
this.radius = radius;
Expand Down Expand Up @@ -308,10 +320,10 @@ public void updateItemPositions() {
* such as when a user clicks the action button.
* @return a Point containing x and y coordinates of the top left corner of action view
*/
private Point getActionViewCoordinates() {
private Point getViewCoordinates(View view) {
int[] coords = new int[2];
// This method returns a x and y values that can be larger than the dimensions of the device screen.
mainActionView.getLocationOnScreen(coords);
view.getLocationOnScreen(coords);

// So, we need to deduce the offsets.
if(systemOverlay) {
Expand All @@ -331,20 +343,38 @@ private Point getActionViewCoordinates() {
* @return the action view center point
*/
public Point getActionViewCenter() {
Point point = getActionViewCoordinates();
Point point = getViewCoordinates(mainActionView);
point.x += mainActionView.getMeasuredWidth() / 2;
point.y += mainActionView.getMeasuredHeight() / 2;
return point;
}

/**
* Returns the center point of the centering view or point
* @return the action view center point
*/
public Point getMenuCenter() {
if (centeringPoint != null) {
return centeringPoint;
} else if (centeringView != null) {
Point point = getViewCoordinates(centeringView);
point.x += centeringView.getMeasuredWidth() / 2;
point.y += centeringView.getMeasuredHeight() / 2;
return point;
} else {
return getActionViewCenter();
}
}

/**
* Calculates the desired positions of all items.
* @return getActionViewCenter()
*/
private Point calculateItemPositions() {
// Create an arc that starts from startAngle and ends at endAngle
// in an area that is as large as 4*radius^2
final Point center = getActionViewCenter();
final Point origin = getActionViewCenter();
final Point center = getMenuCenter();
RectF area = new RectF(center.x - radius, center.y - radius, center.x + radius, center.y + radius);

Path orbit = new Path();
Expand All @@ -369,7 +399,7 @@ private Point calculateItemPositions() {
subActionItems.get(i).x = (int) coords[0] - subActionItems.get(i).width / 2;
subActionItems.get(i).y = (int) coords[1] - subActionItems.get(i).height / 2;
}
return center;
return origin;
}

/**
Expand Down Expand Up @@ -596,6 +626,8 @@ public static class Builder {
private int endAngle;
private int radius;
private View actionView;
private View centeringView;
private Point centeringPoint;
private List<Item> subActionItems;
private MenuAnimationHandler animationHandler;
private boolean animated;
Expand Down Expand Up @@ -705,8 +737,20 @@ public Builder attachTo(View actionView) {
return this;
}

public Builder centerAt(View centeringView) {
this.centeringView = centeringView;
return this;
}

public Builder centerAt(Point centeringPoint) {
this.centeringPoint = centeringPoint;
return this;
}

public FloatingActionMenu build() {
return new FloatingActionMenu(actionView,
centeringView,
centeringPoint,
startAngle,
endAngle,
radius,
Expand All @@ -730,4 +774,4 @@ public static WindowManager.LayoutParams getDefaultSystemWindowParams() {
return params;
}

}
}
8 changes: 8 additions & 0 deletions samples/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,14 @@
android:name="android.support.PARENT_ACTIVITY"
android:value="com.oguzdev.circularfloatingactionmenu.samples.DemoActivity" />
</activity>
<activity
android:name=".MenuAltCenteredActivity"
android:label="@string/title_activity_menu_with_fab"
android:parentActivityName=".DemoActivity" >
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.oguzdev.circularfloatingactionmenu.samples.DemoActivity" />
</activity>

<service
android:name=".SystemOverlayMenuService"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container,
"Menu attached to custom button",
"Menu with custom animation",
"Menu in ScrollView",
"Menu as system overlay"
"Menu as system overlay",
"Alt Centered"
};
ArrayAdapter<String> simpleAdapter = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, items);
demosListView = (ListView) rootView.findViewById(R.id.demosListView);
Expand All @@ -92,6 +93,9 @@ public void onItemClick(AdapterView<?> parent, View view, int position, long id)
case 4:
startActivity(new Intent(getActivity(), SystemOverlayMenuActivity.class));
break;
case 5:
startActivity(new Intent(getActivity(), MenuAltCenteredActivity.class));
break;
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
package com.oguzdev.circularfloatingactionmenu.samples;

import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;

import com.oguzdev.circularfloatingactionmenu.library.FloatingActionButton;
import com.oguzdev.circularfloatingactionmenu.library.FloatingActionMenu;
import com.oguzdev.circularfloatingactionmenu.library.SubActionButton;

public class MenuAltCenteredActivity extends ActionBarActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_menu_with_fab);

// Set up the white button on the lower right corner
// more or less with default parameter
final ImageView fabIconNew = new ImageView(this);
fabIconNew.setImageDrawable(getResources().getDrawable(R.drawable.ic_action_new_light));
final FloatingActionButton rightLowerButton = new FloatingActionButton.Builder(this)
.setContentView(fabIconNew)
.build();

// Set up the large red button on the center right side
// With custom button and content sizes and margins
int redActionButtonSize = getResources().getDimensionPixelSize(R.dimen.red_action_button_size);
int redActionButtonMargin = getResources().getDimensionPixelOffset(R.dimen.action_button_margin);
int redActionButtonContentSize = getResources().getDimensionPixelSize(R.dimen.red_action_button_content_size);
int redActionButtonContentMargin = getResources().getDimensionPixelSize(R.dimen.red_action_button_content_margin);
int redActionMenuRadius = getResources().getDimensionPixelSize(R.dimen.red_action_menu_radius);
int blueSubActionButtonSize = getResources().getDimensionPixelSize(R.dimen.blue_sub_action_button_size);
int blueSubActionButtonContentMargin = getResources().getDimensionPixelSize(R.dimen.blue_sub_action_button_content_margin);

ImageView fabIconStar = new ImageView(this);
fabIconStar.setImageDrawable(getResources().getDrawable(R.drawable.ic_action_important));

FloatingActionButton.LayoutParams starParams = new FloatingActionButton.LayoutParams(redActionButtonSize, redActionButtonSize);
starParams.setMargins(redActionButtonMargin,
redActionButtonMargin,
redActionButtonMargin,
redActionButtonMargin);
fabIconStar.setLayoutParams(starParams);

FloatingActionButton.LayoutParams fabIconStarParams = new FloatingActionButton.LayoutParams(redActionButtonContentSize, redActionButtonContentSize);
fabIconStarParams.setMargins(redActionButtonContentMargin,
redActionButtonContentMargin,
redActionButtonContentMargin,
redActionButtonContentMargin);

final FloatingActionButton leftCenterButton = new FloatingActionButton.Builder(this)
.setContentView(fabIconStar, fabIconStarParams)
.setBackgroundDrawable(R.drawable.button_action_red_selector)
.setPosition(FloatingActionButton.POSITION_LEFT_CENTER)
.setLayoutParams(starParams)
.build();


SubActionButton.Builder rLSubBuilder = new SubActionButton.Builder(this);
ImageView rlIcon1 = new ImageView(this);
ImageView rlIcon2 = new ImageView(this);
ImageView rlIcon3 = new ImageView(this);
ImageView rlIcon4 = new ImageView(this);

rlIcon1.setImageDrawable(getResources().getDrawable(R.drawable.ic_action_chat_light));
rlIcon2.setImageDrawable(getResources().getDrawable(R.drawable.ic_action_camera_light));
rlIcon3.setImageDrawable(getResources().getDrawable(R.drawable.ic_action_video_light));
rlIcon4.setImageDrawable(getResources().getDrawable(R.drawable.ic_action_place_light));

// Build the menu with default options: light theme, 90 degrees, 72dp radius.
// Set 4 default SubActionButtons
final FloatingActionMenu rightLowerMenu = new FloatingActionMenu.Builder(this)
.addSubActionView(rLSubBuilder.setContentView(rlIcon1).build())
.addSubActionView(rLSubBuilder.setContentView(rlIcon2).build())
.addSubActionView(rLSubBuilder.setContentView(rlIcon3).build())
.addSubActionView(rLSubBuilder.setContentView(rlIcon4).build())
.attachTo(leftCenterButton)
.centerAt(rightLowerButton)
.build();

// Listen menu open and close events to animate the button content view
rightLowerMenu.setStateChangeListener(new FloatingActionMenu.MenuStateChangeListener() {
@Override
public void onMenuOpened(FloatingActionMenu menu) {
// Rotate the icon of rightLowerButton 45 degrees clockwise
fabIconNew.setRotation(0);
PropertyValuesHolder pvhR = PropertyValuesHolder.ofFloat(View.ROTATION, 45);
ObjectAnimator animation = ObjectAnimator.ofPropertyValuesHolder(fabIconNew, pvhR);
animation.start();
}

@Override
public void onMenuClosed(FloatingActionMenu menu) {
// Rotate the icon of rightLowerButton 45 degrees counter-clockwise
fabIconNew.setRotation(45);
PropertyValuesHolder pvhR = PropertyValuesHolder.ofFloat(View.ROTATION, 0);
ObjectAnimator animation = ObjectAnimator.ofPropertyValuesHolder(fabIconNew, pvhR);
animation.start();
}
});


// Set up customized SubActionButtons for the right center menu
SubActionButton.Builder lCSubBuilder = new SubActionButton.Builder(this);
lCSubBuilder.setBackgroundDrawable(getResources().getDrawable(R.drawable.button_action_blue_selector));

FrameLayout.LayoutParams blueContentParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
blueContentParams.setMargins(blueSubActionButtonContentMargin,
blueSubActionButtonContentMargin,
blueSubActionButtonContentMargin,
blueSubActionButtonContentMargin);
lCSubBuilder.setLayoutParams(blueContentParams);
// Set custom layout params
FrameLayout.LayoutParams blueParams = new FrameLayout.LayoutParams(blueSubActionButtonSize, blueSubActionButtonSize);
lCSubBuilder.setLayoutParams(blueParams);

ImageView lcIcon1 = new ImageView(this);
ImageView lcIcon2 = new ImageView(this);
ImageView lcIcon3 = new ImageView(this);
ImageView lcIcon4 = new ImageView(this);
ImageView lcIcon5 = new ImageView(this);

lcIcon1.setImageDrawable(getResources().getDrawable(R.drawable.ic_action_camera));
lcIcon2.setImageDrawable(getResources().getDrawable(R.drawable.ic_action_picture));
lcIcon3.setImageDrawable(getResources().getDrawable(R.drawable.ic_action_video));
lcIcon4.setImageDrawable(getResources().getDrawable(R.drawable.ic_action_location_found));
lcIcon5.setImageDrawable(getResources().getDrawable(R.drawable.ic_action_headphones));

// Build another menu with custom options
final 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())
.setRadius(redActionMenuRadius)
.setStartAngle(70)
.setEndAngle(-70)
.attachTo(rightLowerButton)
.centerAt(leftCenterButton)
.build();


}


@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_with_fab, menu);
return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}