一、弹出菜单
制作一个可以弹出的菜单,具体直接看效果吧~
具体实现:
1,在XML文件里面添加图片按钮
2,为按钮设置样式,在values文件中
3,添加动画
(1),定义数组保存所有的动画按钮的资源ID
private int[] resld = {R.id.id_b,R.id.id_c,R.id.id_d};
(2),获取菜单按钮的状态,并为菜单按钮添加点击事件,isOpen记录按钮菜单的是否是打开状态
private void initView(){
//给菜单添加点击事件
ImageButton menu = findViewById(R.id.id_a);
menu.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//遍历数组,取出每一个按钮
for(int i = 0;i < resld.length;i++){
//判断是打开 还是关闭
if(isOpen == true){
//之前是打开 ,现在需要关闭
close(i);
}else{
//之间是关闭,现在需要打开
open(i);
}
}
isOpen = !isOpen;
}
});
}
(3),定义方法封装菜单的open和close动画
public void close(int i){
animate(i,true);
}
public void open(int i){
animate(i,false);
}
(4),实现动画,使用AnimationSet管理多个动画
public void animate(int i,boolean state){
//计算菜单平分之后的夹角
double angle = (Math.PI/(resld.length+1));
//获取id对应的控件
ImageButton imageButton = findViewById(resld[i]);
//计算当前控制对应控件的角度
double mAngle = (i+1) * angle;
//计算x距离
float x = (float)(Math.cos(mAngle) * 400);
//计算y距离
float y = (float)(Math.sin(mAngle) * 400);
float startx;
float tox;
float starty;
float toy;
Interpolator interpolator;
if(state == true){
startx = 0;
starty = 0;
tox = x;
toy = -y;
interpolator = new BounceInterpolator();
}else{
startx = x;
starty = -y;
tox = 0;
toy = 0;
interpolator = new AnticipateInterpolator();
}
//移动的动画
TranslateAnimation translateAnimation = new TranslateAnimation(startx,tox,starty,toy);
translateAnimation.setDuration(500);
translateAnimation.setInterpolator(interpolator);
//旋转的动画
RotateAnimation rotateAnimation = new RotateAnimation(0,360*3, Animation.RELATIVE_TO_SELF,
0.5f,Animation.RELATIVE_TO_SELF,0.5f);
rotateAnimation.setDuration(500);
//创建一个Animation集合 包裹多个动画
AnimationSet set = new AnimationSet(false);
set.setFillAfter(true); //保持状态
set.addAnimation(rotateAnimation);
set.addAnimation(translateAnimation);
//开始动画
imageButton.startAnimation(set);
}
二、多级菜单
先展示效果:
具体实现:
1,在XML文件里面添加每层菜单的布局
效果图:
2,读取XML文件里面的控件,并为菜单添加点击事件
private boolean isOpen3 = true; //记录三级菜单是否打开
private boolean isOpen2 = true; //记录二级菜单是否打开
private RelativeLayout level3;
private RelativeLayout level2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//加载容器布局
level2 = findViewById(R.id.rl_level2);
level3 = findViewById(R.id.rl_level3);
ImageButton menu = findViewById(R.id.ib_menu);
ImageButton home = findViewById(R.id.ib_home);
//添加点击事件
menu.setOnClickListener(this);
home.setOnClickListener(this);
3,点击二级菜单的菜单按钮,隐藏或显示三级菜单
@Override
public void onClick(View v) {
//判断哪一个菜单被点击了
switch (v.getId()){
case R.id.ib_menu:
if(isOpen3){
//应该关闭菜单
close(level3,200);
}else{
//应该打开菜单
open(level3);
}
isOpen3 = !isOpen3;
break;
case R.id.ib_home:
if(isOpen3){
//如果显示三级菜单,就关闭三级菜单
close(level3,0);
isOpen3 = false;
}
if(isOpen2){
//关闭二级菜单
close(level2,200);
}else{
//打开二级菜单
open(level2);
}
isOpen2 = !isOpen2;
break;
default:
break;
}
}
4,创建anim文件,然后添加动画
创建步骤:
创建完成后再回到Android项目,在src文件夹下就会出现anim动画文件,然后再在anim文件加下配置动画的XML文件
5,封装旋转动画
public void open(RelativeLayout relativeLayout){
//打开三级菜单
Animation in = AnimationUtils.loadAnimation(this,R.anim.rotate_in_anim);
relativeLayout.startAnimation(in);
//子控件可点击
changeState(relativeLayout,true);
}
public void close(RelativeLayout relativeLayout,long dalay){
//关闭三级菜单
Animation out = AnimationUtils.loadAnimation(this,R.anim.rotate_out_anim);
out.setStartOffset(dalay); //添加延迟效果
relativeLayout.startAnimation(out);
//子控件不可点击
changeState(relativeLayout,false);
}
其中解决了补间动画的弊端:视觉效果上翻转上去了,点击原来的位置,按钮还可以响应事件。转出去就设置这个容器的所有空间都可点击;转回来的容器的所有子控件都可以点击。
public void changeState(RelativeLayout relativeLayout,boolean enable){
//获取容器子控件的个数
int childCount = relativeLayout.getChildCount();
//遍历容器的子控件
for(int i =0;i < childCount;i++){
//取出对应的子控件
View view = relativeLayout.getChildAt(i);
//设置子控件的状态
view.setEnabled(enable);
}
}
MainActivity
完整代码:
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.ImageButton;
import android.widget.RelativeLayout;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private boolean isOpen3 = true; //记录三级菜单是否打开
private boolean isOpen2 = true; //记录二级菜单是否打开
private RelativeLayout level3;
private RelativeLayout level2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//加载容器布局
level2 = findViewById(R.id.rl_level2);
level3 = findViewById(R.id.rl_level3);
ImageButton menu = findViewById(R.id.ib_menu);
ImageButton home = findViewById(R.id.ib_home);
//添加点击事件
menu.setOnClickListener(this);
home.setOnClickListener(this);
}
@Override
public void onClick(View v) {
//判断哪一个菜单被点击了
switch (v.getId()){
case R.id.ib_menu:
if(isOpen3){
//应该关闭菜单
close(level3,200);
}else{
//应该打开菜单
open(level3);
}
isOpen3 = !isOpen3;
break;
case R.id.ib_home:
if(isOpen3){
//如果显示三级菜单,就关闭三级菜单
close(level3,0);
isOpen3 = false;
}
if(isOpen2){
//关闭二级菜单
close(level2,200);
}else{
//打开二级菜单
open(level2);
}
isOpen2 = !isOpen2;
break;
default:
break;
}
}
public void open(RelativeLayout relativeLayout){
//打开三级菜单
Animation in = AnimationUtils.loadAnimation(this,R.anim.rotate_in_anim);
relativeLayout.startAnimation(in);
//子控件可点击
changeState(relativeLayout,true);
}
public void close(RelativeLayout relativeLayout,long dalay){
//关闭三级菜单
Animation out = AnimationUtils.loadAnimation(this,R.anim.rotate_out_anim);
out.setStartOffset(dalay);
relativeLayout.startAnimation(out);
//子控件不可点击
changeState(relativeLayout,false);
}
public void changeState(RelativeLayout relativeLayout,boolean enable){
//获取容器子控件的个数
int childCount = relativeLayout.getChildCount();
//遍历容器的子控件
for(int i =0;i < childCount;i++){
//取出对应的子控件
View view = relativeLayout.getChildAt(i);
//设置子控件的状态
view.setEnabled(enable);
}
}
}
三、感悟
这个Demo虽然很简单但写起来的时候还是会出各种各样的麻烦,最难得地方就是动画旋转角度,思维不缜密,还有待加强。多多练习,熟能生巧!