We see a lot of slideshow menus. Have you ever thought of another way to pop up menus? For example, make the Toolbar a menu?
I don’t know how to describe this effect, so let’s just show it:
Fry not fry!
It’s actually super simple to implement.
Train of thought
It looks like the Toolbar has become a menu, but as you can guess, the rotation menu is actually a separate control from the Toolbar, as is the menu button in the upper left corner, with the same image in the same place.
So I customized a rotation control SpringRotateMenu, inherit FrameLayout, in this to achieve rotation animation and gesture operations.
Rotating animation
Gifs may not be obvious, but they shake when the menu is expanded and folded, giving it a “DUANG” feel. Does it feel like a spring? Yes, I’m using the new SpringAnimation.
I have a more detailed introduction to SpringAnimation in my previous article:
Implement a ScrollView with a drop-down spring animation
SpringAnimation supports panning, scaling, and rotation effects, and this time we will use its rotation effect.
Let’s first define two angles of expansion and collapse:
private final static int ROTATE_EXPAND = 0;
private final static int ROTATE_COLLAPSE = -90;Copy the code
Then get the rotating spring animation like this:
expandAnimation = new SpringAnimation(this, SpringAnimation.ROTATION, ROTATE_EXPAND);
collapseAnimation = new SpringAnimation(this, SpringAnimation.ROTATION, ROTATE_COLLAPSE);Copy the code
Note the third parameter. In a pan animation, the third parameter is the offset, while in a rotation animation it represents the degree. Here I define unfolding animation (rotate to 0°) and unwinding animation (rotate to -90°).
It then provides two methods to set the expand and collapse buttons:
/** * sets the expansion button */
public void setExpandButton(View expandButton) {
expandButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) { expand(); }}); }/** * sets the collapse button */
public void setCollapseButton(View collapseButton) {
collapseButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) { collapse(); }}); }Copy the code
The expand button is the Toolbar button, and the collapse button is the menu button.
The way to expand and collapse is also simple:
/** * expand menu */
public void expand(a) {
setVisibility(VISIBLE);
expandAnimation.start();
if(listener ! =null) {
listener.expandBegin();
collapseAnimation.addEndListener(new DynamicAnimation.OnAnimationEndListener() {
@Override
public void onAnimationEnd(DynamicAnimation animation,
boolean canceled,
float value,
float velocity) { setVisibility(INVISIBLE); listener.expandEnd(); }}); }}/** ** collapse menu */
public void collapse(a) {
collapseAnimation.start();
if(listener ! =null) {
listener.collapseBegin();
collapseAnimation.addEndListener(new DynamicAnimation.OnAnimationEndListener() {
@Override
public void onAnimationEnd(DynamicAnimation animation,
boolean canceled,
float value,
float velocity) { listener.collapseEnd(); }}); }}Copy the code
In fact, the corresponding animation is executed, the menu is displayed when it starts to expand, and hidden when it is completely closed. The listener here is an animation listener that I added to listen for the start and end of two animations for external use.
gestures
The gesture is to override onTouchEvent as follows:
private float mDownX;
@Override
public boolean onTouchEvent(MotionEvent event) {
if (expandAnimation.isRunning() || collapseAnimation.isRunning()) {
return super.onTouchEvent(event);
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mDownX = event.getRawX();
break;
case MotionEvent.ACTION_MOVE:
// Slide distance
float deltaX = event.getRawX() - mDownX;
// Set the Angle
float rotation = (deltaX / (screenWidth * 0.8 f)) * ROTATE_COLLAPSE;
if (rotation <= ROTATE_EXPAND && rotation >= ROTATE_COLLAPSE) {
setRotation(rotation);
} else if (rotation > ROTATE_EXPAND) {
setRotation(ROTATE_EXPAND);
} else if (rotation < ROTATE_COLLAPSE) {
setRotation(ROTATE_COLLAPSE);
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
if (getRotation() < ROTATE_COLLAPSE / 3) {
collapse();
} else {
expand();
}
break;
}
return true;
}Copy the code
The key is to convert the horizontal sliding distance of the finger into the rotation Angle. My calculation is that the rotation Angle of the menu control is equal to the ratio of the horizontal sliding distance to the screen width, multiplied by -90°. As for why I multiplied the width by 0.8, I did it so that I could slide my finger across 80% of the screen width to fold up the menu completely.
There is also the handling of finger lifting. I think most of the time when a user swipes a menu to the right, they want it to go away, so it should be easier to go away. So what I do is, when the finger is up and the menu is more than 30 degrees vertical, I tell it to do the folded animation, otherwise I do the expanded animation.
use
layout
Use SpringRotateMenu as the root layout of the rotation menu and set the rotation center point of the control. The default Toolbar height is 56dp, and if the menu button is centered, you can use:
android:transformPivotX="28dp"
android:transformPivotY="28dp"Copy the code
Then overlay it over the Toolbar with FrameLayout.
It is recommended that the background color of the menu layout be the same as the Toolbar color and use the same menu icon with a parameter inside:
android:rotation="90"Copy the code
Rotate the icon 90 degrees.
code
Find our SpringRotateMenu in the code and simply set it up like this:
springRotateMenu.setExpandButton(findViewById(R.id.iv_menu));
springRotateMenu.setCollapseButton(springRotateMenu.findViewById(R.id.iv_menu));
springRotateMenu.setAnimationListener(new SpringRotateMenu.OnAnimationListener() {
@Override
public void expandBegin(a) {
toolbar.setVisibility(View.INVISIBLE);
}
@Override
public void expandEnd(a) {}@Override
public void collapseBegin(a) {}@Override
public void collapseEnd(a) { toolbar.setVisibility(View.VISIBLE); }});Copy the code
There we go. No problem.
The source address