欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android仿优酷圆形菜单学习笔记分享

程序员文章站 2024-03-01 12:12:52
先来看看效果: 首先来分析一下: 这个菜单可以分成三个菜单: 1.一级菜单(即最内圈那个菜单) 2.二级菜单(即中间圈那个菜单) 3.三级菜单(即最外圈那个菜...

先来看看效果:

Android仿优酷圆形菜单学习笔记分享

首先来分析一下:

这个菜单可以分成三个菜单:

1.一级菜单(即最内圈那个菜单)

2.二级菜单(即中间圈那个菜单)

3.三级菜单(即最外圈那个菜单)

首先,可以将这三个菜单使用相对布局

一级菜单只有一个按钮(即home),可以控制二级和三级菜单

二级菜单有三个按钮(即menu),中间那个按钮可以控制三级菜单

三级菜单有七个按钮

那先把布局文件先写出来,采用三个相对布局(即每个菜单采用一个相对布局)

<relativelayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  tools:context="com.example.youkumenu.mainactivity" >

  <!-- 三级菜单 -->

  <relativelayout
    android:id="@+id/level3_rl"
    android:layout_width="220dp"
    android:layout_height="110dp"
    android:layout_alignparentbottom="true"
    android:layout_centerhorizontal="true"
    android:background="@drawable/level3" >

    <imageview
      android:id="@+id/channel1"
      android:layout_marginleft="5dp"
      android:layout_alignparentbottom="true" 
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:src="@drawable/channel1"/>
    <imageview
      android:id="@+id/channel2"
      android:layout_marginbottom="10dp"
      android:layout_marginleft="25dp"
      android:layout_above="@id/channel1"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:src="@drawable/channel2"/>
    <imageview
      android:layout_marginbottom="1dp"
      android:layout_marginleft="52dp"
      android:layout_above="@id/channel2"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:src="@drawable/channel3"/>
    <imageview
      android:layout_centerhorizontal="true"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:src="@drawable/channel4"/>
    <imageview
      android:id="@+id/channel7"
      android:layout_marginright="5dp"
      android:layout_alignparentright="true"
      android:layout_alignparentbottom="true" 
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:src="@drawable/channel7"/>
    <imageview
      android:id="@+id/channel6"
      android:layout_alignparentright="true"
      android:layout_marginbottom="10dp"
      android:layout_marginright="25dp"
      android:layout_above="@id/channel7"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:src="@drawable/channel6"/>
    <imageview
      android:layout_marginbottom="1dp"
      android:layout_marginright="52dp"
      android:layout_alignparentright="true"
      android:layout_above="@id/channel6"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:src="@drawable/channel5"/>
  </relativelayout>

  <!-- 二级菜单 -->

  <relativelayout
    android:id="@+id/level2_rl"
    android:layout_width="140dp"
    android:layout_height="70dp"
    android:layout_alignparentbottom="true"
    android:layout_centerhorizontal="true"
    android:background="@drawable/level2" >
    <imageview
      android:layout_marginleft="3dp"
      android:layout_alignparentbottom="true"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:src="@drawable/icon_search"/>
    <imageview
      android:id="@+id/menu_iv"
      android:layout_centerhorizontal="true"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:src="@drawable/icon_menu"/>
    <imageview
      android:id="@+id/myyouku_iv"
      android:layout_marginright="3dp"
      android:layout_alignparentbottom="true"
      android:layout_alignparentright="true"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:src="@drawable/icon_myyouku"/>

  </relativelayout>
  <!-- 一级菜单 -->

  <relativelayout
    android:layout_width="80dp"
    android:layout_height="40dp"
    android:layout_alignparentbottom="true"
    android:layout_centerhorizontal="true"
    android:background="@drawable/level1" >

    <imageview
      android:id="@+id/home_iv"
      android:layout_centerinparent="true"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:src="@drawable/icon_home" />
  </relativelayout>

</relativelayout>

那好,布局写好,就能看到这样的效果,只不过现在只是静态的,没有加逻辑而已

Android仿优酷圆形菜单学习笔记分享

下面就该来分析下逻辑了,先来看看home(即一级菜单中间那个按钮)

点击home,会有三种情况,下面分情况考虑:

情况1.二级、三级菜单都显示,就将二、三级菜单隐藏掉

情况2.二、三级菜单都不显示的时候,就将二级菜单显示

情况3.二级菜单显示且三级菜单不显示的时候,就将二级菜单隐藏

当然我们知道,要知道菜单隐藏或者显示,只需要设个标记位即可

那要如何隐藏或显示菜单,当然是使用动画了,可以使用补间动画和

属性动画,我这里就使用补间动画

下面就该来分析下逻辑了,先来看看menu(即二级菜单中间那个按钮)

点击menu,会有三种情况,下面分情况考虑:

情况1.三级显示的时候,就将三级菜单隐藏

情况2.三级隐藏的时候,就将三级菜单显示

这个就比较简单了,就两种情况。

public class mainactivity extends activity implements onclicklistener{
  //一级菜单中的home按钮
  private imageview home_iv;
  //二级菜单中的menu按钮
  private imageview menu_iv;
  //用于判断二级菜单的显示状况,true为显示,false为隐藏
  private boolean level2listplay = true;
  //用于判断二级菜单的显示状况,true为显示,false为隐藏
  private boolean level3listplay = true;
  //二级和三级菜单
  private relativelayout level2_rl,level3_rl;
  @override
  protected void oncreate(bundle savedinstancestate) {
    super.oncreate(savedinstancestate);
    setcontentview(r.layout.activity_main);
    initview();
  }  
  //初始化组件
  private void initview() {
    home_iv = (imageview) findviewbyid(r.id.home_iv);
    home_iv.setonclicklistener(this);

    level2_rl = (relativelayout) findviewbyid(r.id.level2_rl);
    level3_rl = (relativelayout) findviewbyid(r.id.level3_rl);

    menu_iv = (imageview) findviewbyid(r.id.menu_iv);
    menu_iv.setonclicklistener(this);
  }
  @override
  public void onclick(view v) {
    switch (v.getid()) {
    case r.id.home_iv:   //点击home按钮的逻辑代码
      clickhomeiv();
      break;
    case r.id.menu_iv:
      clickmenuiv();   //点击二级菜单中的menu按钮的逻辑代码
      break;
    default:
      break;
    }
  }
  //点击二级菜单中的menu按钮的逻辑代码
  private void clickmenuiv() {
    //分情况考虑
    //1.三级显示的时候,就将三级菜单隐藏
    if (level3listplay) {
      hidemenu(level3_rl,0);
      level3listplay = false;
      return;
    }
    //2.三级隐藏的时候,就将三级菜单显示
    if (!level3listplay) {
      showmenu(level3_rl);
      level3listplay = true;
      return;
    }
  }
  //点击一级菜单中的home按钮的逻辑代码
  private void clickhomeiv() {
    //分情况考虑
    //1.二级、三级菜单都显示,就将二、三级菜单隐藏掉
    if (level2listplay && level3listplay) {
      //将二三级菜单隐藏,并改变标记
      hidemenu(level2_rl,300);
      hidemenu(level3_rl,500);
      level2listplay = false;
      level3listplay = false;
      return;
    }
    //2.二、三级菜单都不显示的时候,就将二级菜单显示
    if (!level2listplay && !level3listplay) {
      showmenu(level2_rl);
      level2listplay = true;
      return;
    }
    //3.二级菜单显示且三级菜单不显示的时候,就将二级菜单隐藏
    if (level2listplay && !level3listplay) {
      hidemenu(level2_rl,0);
      level2listplay = false;
      return;
    }

  }
  /**
   * 显示菜单
   * @param view 要显示的菜单
   */
  private void showmenu(relativelayout view) {
//   view.setvisibility(view.visible);
    //旋转动画
    rotateanimation animation = new rotateanimation(-180, 0, animation.relative_to_self, 
        0.5f, animation.relative_to_self, 1.0f);
    animation.setduration(500);   //设置动画持续的时间
    animation.setfillafter(true); //动画停留在动画结束的位置
    view.startanimation(animation);
  }
  /**
   * 隐藏菜单
   * @param view 要隐藏的菜单 ,startoffset 动画延迟执行的时间
   */
  private void hidemenu(relativelayout view,long startoffset) {
//   view.setvisibility(view.gone);
    /** 
     * 旋转动画 
     * rotateanimation(fromdegrees, todegrees, pivotxtype, pivotxvalue, pivotytype, pivotyvalue) 
     * fromdegrees 开始旋转角度 
     * todegrees 旋转的结束角度 
     * pivotxtype x轴 参照物 (x轴的伸缩模式,可以取值为absolute、relative_to_self)
     * pivotxvalue x轴 旋转的参考点(x坐标的伸缩值) 
     * pivotytype y轴 参照物 (y轴的伸缩模式,可以取值为absolute、relative_to_self)
     * pivotyvalue y轴 旋转的参考点 ((y坐标的伸缩值) )
     */ 
    rotateanimation animation = new rotateanimation(0, -180, animation.relative_to_self, 
        0.5f, animation.relative_to_self, 1.0f);
    animation.setduration(500);
    animation.setfillafter(true); //动画停留在动画结束的位置
    animation.setstartoffset(startoffset);   //设置动画的延迟执行
    view.startanimation(animation);
  }
}

写到这里,应该差不多可以看到效果了,但是细心的伙伴应该会发现两个bug:

第一:当你快速点击一级菜单home按钮或二级菜单menu按钮的时候,会发现二级菜单或三级菜单的第一次动画还没执行完,又执行第二次动画,看起来就在晃一样。(原因:就是执行的动画都设定了一定时间,你点击的时间快于动画执行的时间)

解决办法:

对动画进行监听,当动画开始执行和结束的时候,对它进行监听,大家应该会想到用一个标记位来判断,可我们知道一个标记为只能判断两种状态,可这里有两种动画(显示的动画和隐藏的动画),一个标记位肯定不行,可以用一个int值来控制

//用于记录有多少个动画在执行
  private int annimationcount = 0;
  //对动画进行监听的时候
  animation.setanimationlistener(new animationlistener() {
      @override
      public void onanimationstart(animation animation) {
//       menu_iv.setonclicklistener(null);
//       home_iv.setonclicklistener(null);
        annimationcount ++;
      }
      @override
      public void onanimationrepeat(animation animation) {

      }
      @override
      public void onanimationend(animation animation) {
//       menu_iv.setonclicklistener(mainactivity.this);
//       home_iv.setonclicklistener(mainactivity.this);
        annimationcount --;
      }
    //当点击的时候就可以进行判断,只要annimationcount值大于0,说明还有动画在执行
    if (annimationcount > 0) {
      return ;
    }

第二:当二级菜单隐藏的时候,你点击二级菜单中menu按钮(虽然现在看不见)时,你会惊奇的发现三级菜单居然显示了。(原因:补间动画,没有真正的改变组件的属性,而属性动画就不一样,大家有时间可以试试属性动画做做)

解决办法:

只要当二级菜单隐藏的时候,就让二级菜单的所有选项按钮都不可点。因为二级菜单有可以能有多个按钮,所以拿到父容器,去使它的子控件失去焦点即可。

//如果要显示菜单,那么就将相应的控件设为有焦点
    //获取父容器中有几个子控件
    int childcount = view.getchildcount();
    for (int i = 0; i < childcount; i++) {
      view.getchildat(i).setenabled(true);
    }

写到这里就差不多了,大家可以试试

这里把我写的完整代码贴出来:

public class mainactivity extends activity implements onclicklistener{
  //一级菜单中的home按钮
  private imageview home_iv;
  //二级菜单中的menu按钮
  private imageview menu_iv;
  //用于判断二级菜单的显示状况,true为显示,false为隐藏
  private boolean level2listplay = true;
  //用于判断二级菜单的显示状况,true为显示,false为隐藏
  private boolean level3listplay = true;
  //二级和三级菜单
  private relativelayout level2_rl,level3_rl;
  //用于记录有多少个动画在执行
  private int annimationcount = 0;
  @override
  protected void oncreate(bundle savedinstancestate) {
    super.oncreate(savedinstancestate);
    setcontentview(r.layout.activity_main);
    initview();
  }  
  //初始化组件
  private void initview() {
    home_iv = (imageview) findviewbyid(r.id.home_iv);
    home_iv.setonclicklistener(this);

    level2_rl = (relativelayout) findviewbyid(r.id.level2_rl);
    level3_rl = (relativelayout) findviewbyid(r.id.level3_rl);

    menu_iv = (imageview) findviewbyid(r.id.menu_iv);
    menu_iv.setonclicklistener(this);
  }
  @override
  public void onclick(view v) {
    switch (v.getid()) {
    case r.id.home_iv:   //点击home按钮的逻辑代码
      clickhomeiv();
      break;
    case r.id.menu_iv:
      clickmenuiv();   //点击二级菜单中的menu按钮的逻辑代码
      break;
    default:
      break;
    }
  }
  //点击二级菜单中的menu按钮的逻辑代码
  private void clickmenuiv() {
    //当点击的时候就可以进行判断,只要annimationcount值大于0,说明还有动画在执行
    if (annimationcount > 0) {
      return ;
    }
    //分情况考虑
    //1.三级显示的时候,就将三级菜单隐藏
    if (level3listplay) {
      hidemenu(level3_rl,0);
      level3listplay = false;
      return;
    }
    //2.三级隐藏的时候,就将三级菜单显示
    if (!level3listplay) {
      showmenu(level3_rl);
      level3listplay = true;
      return;
    }
  }
  //点击一级菜单中的home按钮的逻辑代码
  private void clickhomeiv() {
    //当点击的时候就可以进行判断,只要annimationcount值大于0,说明还有动画在执行
    if (annimationcount > 0) {
      return ;
    }
    //分情况考虑
    //1.二级、三级菜单都显示,就将二、三级菜单隐藏掉
    if (level2listplay && level3listplay) {
      //将二三级菜单隐藏,并改变标记
      hidemenu(level2_rl,300);
      hidemenu(level3_rl,500);
      level2listplay = false;
      level3listplay = false;
      return;
    }
    //2.二、三级菜单都不显示的时候,就将二级菜单显示
    if (!level2listplay && !level3listplay) {
      showmenu(level2_rl);
      level2listplay = true;
      return;
    }
    //3.二级菜单显示且三级菜单不显示的时候,就将二级菜单隐藏
    if (level2listplay && !level3listplay) {
      hidemenu(level2_rl,0);
      level2listplay = false;
      return;
    }

  }
  /**
   * 显示菜单
   * @param view 要显示的菜单
   */
  private void showmenu(relativelayout view) {
//   view.setvisibility(view.visible);
    //如果要显示菜单,那么就将相应的控件设为有焦点
    //获取父容器中有几个子控件
    int childcount = view.getchildcount();
    for (int i = 0; i < childcount; i++) {
      view.getchildat(i).setenabled(true);
    }
    //旋转动画
    rotateanimation animation = new rotateanimation(-180, 0, animation.relative_to_self, 
        0.5f, animation.relative_to_self, 1.0f);
    animation.setduration(500);   //设置动画持续的时间
    animation.setfillafter(true); //动画停留在动画结束的位置
    view.startanimation(animation);
    animation.setanimationlistener(new animationlistener() {
      @override
      public void onanimationstart(animation animation) {
        //动画开始的时候回调
//       menu_iv.setonclicklistener(null);
//       home_iv.setonclicklistener(null);
        annimationcount ++;
      }

      @override
      public void onanimationrepeat(animation animation) {
        //动画执行过程调用
      }

      @override
      public void onanimationend(animation animation) {
        //动画结束的时候调用
//       menu_iv.setonclicklistener(mainactivity.this);
//       home_iv.setonclicklistener(mainactivity.this);
        annimationcount --;
      }
    });
  }
  /**
   * 隐藏菜单
   * @param view 要隐藏的菜单 ,startoffset 动画延迟执行的时间
   */
  private void hidemenu(relativelayout view,long startoffset) {
//   view.setvisibility(view.gone);
    //如果要隐藏菜单,那么就将相应的控件设为没有焦点
    //获取父容器中有几个子控件
    int childcount = view.getchildcount();
    for (int i = 0; i < childcount; i++) {
      view.getchildat(i).setenabled(false);
    }
    /** 
     * 旋转动画 
     * rotateanimation(fromdegrees, todegrees, pivotxtype, pivotxvalue, pivotytype, pivotyvalue) 
     * fromdegrees 开始旋转角度 
     * todegrees 旋转的结束角度 
     * pivotxtype x轴 参照物 (x轴的伸缩模式,可以取值为absolute、relative_to_self)
     * pivotxvalue x轴 旋转的参考点(x坐标的伸缩值) 
     * pivotytype y轴 参照物 (y轴的伸缩模式,可以取值为absolute、relative_to_self)
     * pivotyvalue y轴 旋转的参考点 ((y坐标的伸缩值) )
     */ 
    rotateanimation animation = new rotateanimation(0, -180, animation.relative_to_self, 
        0.5f, animation.relative_to_self, 1.0f);
    animation.setduration(500);
    animation.setfillafter(true); //动画停留在动画结束的位置
    animation.setstartoffset(startoffset);   //设置动画的延迟执行
    view.startanimation(animation);
    animation.setanimationlistener(new animationlistener() {
      @override
      public void onanimationstart(animation animation) {
//       menu_iv.setonclicklistener(null);
//       home_iv.setonclicklistener(null);
        annimationcount ++;
      }
      @override
      public void onanimationrepeat(animation animation) {

      }
      @override
      public void onanimationend(animation animation) {
//       menu_iv.setonclicklistener(mainactivity.this);
//       home_iv.setonclicklistener(mainactivity.this);
        annimationcount --;
      }
    });
  }
}

布局文件:

<relativelayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  tools:context="com.example.youkumenu.mainactivity" >

  <!-- 三级菜单 -->

  <relativelayout
    android:id="@+id/level3_rl"
    android:layout_width="220dp"
    android:layout_height="110dp"
    android:layout_alignparentbottom="true"
    android:layout_centerhorizontal="true"
    android:background="@drawable/level3" >

    <imageview
      android:id="@+id/channel1"
      android:layout_marginleft="5dp"
      android:layout_alignparentbottom="true" 
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:src="@drawable/channel1"/>
    <imageview
      android:id="@+id/channel2"
      android:layout_marginbottom="10dp"
      android:layout_marginleft="25dp"
      android:layout_above="@id/channel1"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:src="@drawable/channel2"/>
    <imageview
      android:layout_marginbottom="1dp"
      android:layout_marginleft="52dp"
      android:layout_above="@id/channel2"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:src="@drawable/channel3"/>
    <imageview
      android:layout_centerhorizontal="true"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:src="@drawable/channel4"/>
    <imageview
      android:id="@+id/channel7"
      android:layout_marginright="5dp"
      android:layout_alignparentright="true"
      android:layout_alignparentbottom="true" 
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:src="@drawable/channel7"/>
    <imageview
      android:id="@+id/channel6"
      android:layout_alignparentright="true"
      android:layout_marginbottom="10dp"
      android:layout_marginright="25dp"
      android:layout_above="@id/channel7"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:src="@drawable/channel6"/>
    <imageview
      android:layout_marginbottom="1dp"
      android:layout_marginright="52dp"
      android:layout_alignparentright="true"
      android:layout_above="@id/channel6"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:src="@drawable/channel5"/>
  </relativelayout>

  <!-- 二级菜单 -->

  <relativelayout
    android:id="@+id/level2_rl"
    android:layout_width="140dp"
    android:layout_height="70dp"
    android:layout_alignparentbottom="true"
    android:layout_centerhorizontal="true"
    android:background="@drawable/level2" >
    <imageview
      android:layout_marginleft="3dp"
      android:layout_alignparentbottom="true"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:src="@drawable/icon_search"/>
    <imageview
      android:id="@+id/menu_iv"
      android:layout_centerhorizontal="true"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:src="@drawable/icon_menu"/>
    <imageview
      android:id="@+id/myyouku_iv"
      android:layout_marginright="3dp"
      android:layout_alignparentbottom="true"
      android:layout_alignparentright="true"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:src="@drawable/icon_myyouku"/>

  </relativelayout>
  <!-- 一级菜单 -->

  <relativelayout
    android:layout_width="80dp"
    android:layout_height="40dp"
    android:layout_alignparentbottom="true"
    android:layout_centerhorizontal="true"
    android:background="@drawable/level1" >

    <imageview
      android:id="@+id/home_iv"
      android:layout_centerinparent="true"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:src="@drawable/icon_home" />
  </relativelayout>

</relativelayout>

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家继续关注的更多精彩内容!