当前位置: 移动技术网 > 移动技术>移动开发>Android > Android自定义转盘菜单效果

Android自定义转盘菜单效果

2020年07月30日  | 移动技术网移动技术  | 我要评论

最近由于公司项目需要,需要开发一款转盘菜单,费了好大功夫搞出来了,下面分享下

样图

具体功能如下:

import android.graphics.color;
import android.os.bundle;
import android.support.v4.app.fragment;
import android.support.v4.app.fragmentpageradapter;
import android.support.v7.app.appcompatactivity;
import android.widget.toast;

import com.hitomi.smlibrary.onspinmenustatechangelistener;
import com.hitomi.smlibrary.turntablemenu;

import java.util.arraylist;
import java.util.list;

public class mainactivity extends appcompatactivity {

  private turntablemenu turntablemenu;

  @override
  protected void oncreate(bundle savedinstancestate) {
    super.oncreate(savedinstancestate);
    setcontentview(r.layout.activity_main);

    turntablemenu = (turntablemenu) findviewbyid(r.id.spin_menu);

    // 设置页面标题
    list<string> hintstrlist = new arraylist<>();
    hintstrlist.add("热门信息");
    hintstrlist.add("实时新闻");
    hintstrlist.add("我的论坛");
    hintstrlist.add("我的信息");
    hintstrlist.add("环游世界");
    hintstrlist.add("阅读空间");
    hintstrlist.add("欢乐空间");
    hintstrlist.add("系统设置");

    turntablemenu.sethinttextstrlist(hintstrlist);
    turntablemenu.sethinttextcolor(color.parsecolor("#ffffff"));
    turntablemenu.sethinttextsize(14);

    // 设置页面适配器
    final list<fragment> fragmentlist = new arraylist<>();
    fragmentlist.add(fragment1.newinstance());
    fragmentlist.add(fragment2.newinstance());
    fragmentlist.add(fragment3.newinstance());
    fragmentlist.add(fragment4.newinstance());
    fragmentlist.add(fragment5.newinstance());
    fragmentlist.add(fragment6.newinstance());
    fragmentlist.add(fragment7.newinstance());
    fragmentlist.add(fragment8.newinstance());
    fragmentpageradapter fragmentpageradapter = new fragmentpageradapter(getsupportfragmentmanager()) {
      @override
      public fragment getitem(int position) {
        return fragmentlist.get(position);
      }

      @override
      public int getcount() {
        return fragmentlist.size();
      }
    };
    turntablemenu.setfragmentadapter(fragmentpageradapter);

    // 设置菜单状态改变时的监听器
    turntablemenu.setonspinmenustatechangelistener(new onspinmenustatechangelistener() {
      @override
      public void onmenuopened() {
        toast.maketext(mainactivity.this, "spinmenu opened", toast.length_short).show();
      }

      @override
      public void onmenuclosed() {
        toast.maketext(mainactivity.this, "spinmenu closed", toast.length_short).show();
      }
    });
  }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<com.hitomi.smlibrary.turntablemenu xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  xmlns:tools="http://schemas.android.com/tools"
  android:id="@+id/spin_menu"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  app:hint_text_color="#ffffff"
  app:hint_text_size="14sp"
  app:scale_ratio="0.36"
  tools:context="com.hitomi.spinmenu.mainactivity">

  <framelayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#333a4a"></framelayout>

</com.hitomi.smlibrary.turntablemenu>

3.自定义view turntablemenu

import android.content.context;
import android.content.res.typedarray;
import android.graphics.color;
import android.os.build;
import android.support.annotation.idres;
import android.support.v4.view.gesturedetectorcompat;
import android.support.v4.view.pageradapter;
import android.util.attributeset;
import android.util.log;
import android.view.gesturedetector;
import android.view.gravity;
import android.view.motionevent;
import android.view.viewconfiguration;
import android.view.viewgroup;
import android.widget.framelayout;
import android.widget.linearlayout;
import android.widget.textview;

import java.util.arraylist;
import java.util.list;

import static android.view.viewgroup.layoutparams.match_parent;
import static android.view.viewgroup.layoutparams.wrap_content;

public class turntablemenu extends framelayout {

  static final string tag = "spinmenu";

  static final string tag_item_container = "tag_item_container";

  static final string tag_item_pager = "tag_item_pager";

  static final string tag_item_hint = "tag_item_hint";

  static final int menu_state_close = -2;

  static final int menu_state_closed = -1;

  static final int menu_state_open = 1;

  static final int menu_state_opened = 2;

  /**
   * 左右菜单 item 移动动画的距离
   */
  static final float tran_sknew_value = 160;

  /**
   * hint 相对 页面的上外边距
   */
  static final int hint_top_margin = 15;

  /**
   * 可旋转、转动布局
   */
  private turntablemenulayout turntablemenulayout;

  /**
   * 菜单打开关闭动画帮助类
   */
  private turntablemenuanimator turntablemenuanimator;

  /**
   * 页面适配器
   */
  private pageradapter pageradapter;

  /**
   * 手势识别器
   */
  private gesturedetectorcompat menudetector;

  /**
   * 菜单状态改变监听器
   */
  private onspinmenustatechangelistener onspinmenustatechangelistener;

  /**
   * 缓存 fragment 的集合,供 {@link #pageradapter} 回收使用
   */
  private list pagerobjects;

  /**
   * 菜单项集合
   */
  private list<smitemlayout> smitemlayoutlist;

  /**
   * 页面标题字符集合
   */
  private list<string> hintstrlist;

  /**
   * 页面标题字符尺寸
   */
  private int hinttextsize = 14;

  /**
   * 页面标题字符颜色
   */
  private int hinttextcolor = color.parsecolor("#666666");

  /**
   * 默认打开菜单时页面缩小的比率
   */
  private float scaleratio = .36f;

  /**
   * 控件是否初始化的标记变量
   */
  private boolean init = true;

  /**
   * 是否启用手势识别
   */
  private boolean enablegesture;

  /**
   * 当前菜单状态,默认为打开
   */
  private int menustate = menu_state_closed;

  /**
   * 滑动与触摸之间的阀值
   */
  private int touchslop = 8;

  private onspinselectedlistener onspinselectedlistener = new onspinselectedlistener() {
    @override
    public void onspinselected(int position) {
      log("spinmenu position:" + position);
    }
  };

  private onmenuselectedlistener onmenuselectedlistener = new onmenuselectedlistener() {
    @override
    public void onmenuselected(smitemlayout smitemlayout) {
      closemenu(smitemlayout);
    }
  };

  private gesturedetector.simpleongesturelistener menugesturelistener = new gesturedetector.simpleongesturelistener() {

    @override
    public boolean onscroll(motionevent e1, motionevent e2, float distancex, float distancey) {
      if (math.abs(distancex) < touchslop && distancey < -touchslop * 3) {
        openmenu();
      }
      return true;
    }
  };

  public turntablemenu(context context) {
    this(context, null);
  }

  public turntablemenu(context context, attributeset attrs) {
    this(context, attrs, 0);
  }

  public turntablemenu(context context, attributeset attrs, int defstyleattr) {
    super(context, attrs, defstyleattr);

    typedarray typedarray = context.obtainstyledattributes(attrs, r.styleable.turntablemenu);
    scaleratio = typedarray.getfloat(r.styleable.turntablemenu_scale_ratio, scaleratio);
    hinttextsize = typedarray.getdimensionpixelsize(r.styleable.turntablemenu_hint_text_size, hinttextsize);
    hinttextsize = px2sp(hinttextcolor);
    hinttextcolor = typedarray.getcolor(r.styleable.turntablemenu_hint_text_color, hinttextcolor);
    typedarray.recycle();

    pagerobjects = new arraylist();
    smitemlayoutlist = new arraylist<>();
    menudetector = new gesturedetectorcompat(context, menugesturelistener);

    if (build.version.sdk_int >= build.version_codes.donut) {
      viewconfiguration conf = viewconfiguration.get(getcontext());
      touchslop = conf.getscaledtouchslop();
    }
  }

  @override
  protected void onfinishinflate() {
    super.onfinishinflate();

    @idres final int smlayoutid = 0x6f060505;
    viewgroup.layoutparams layoutparams = new viewgroup.layoutparams(match_parent, match_parent);
    turntablemenulayout = new turntablemenulayout(getcontext());
    turntablemenulayout.setid(smlayoutid);
    turntablemenulayout.setlayoutparams(layoutparams);
    turntablemenulayout.setonspinselectedlistener(onspinselectedlistener);
    turntablemenulayout.setonmenuselectedlistener(onmenuselectedlistener);
    addview(turntablemenulayout);
  }

  @override
  protected void onlayout(boolean changed, int left, int top, int right, int bottom) {
    super.onlayout(changed, left, top, right, bottom);

    if (init && smitemlayoutlist.size() > 0) {
      // 根据 scaleratio 去调整菜单中 item 视图的整体大小
      int pagerwidth = (int) (getmeasuredwidth() * scaleratio);
      int pagerheight = (int) (getmeasuredheight() * scaleratio);
      smitemlayout.layoutparams containerlayoutparams = new smitemlayout.layoutparams(pagerwidth, pagerheight);
      smitemlayout smitemlayout;
      framelayout framecontainer;
      textview tvhint;
      for (int i = 0; i < smitemlayoutlist.size(); i++) {
        smitemlayout = smitemlayoutlist.get(i);
        framecontainer = (framelayout) smitemlayout.findviewwithtag(tag_item_container);
        framecontainer.setlayoutparams(containerlayoutparams);
        if (i == 0) { // 初始菜单的时候,默认显示第一个 fragment
          framelayout pagerlayout = (framelayout) smitemlayout.findviewwithtag(tag_item_pager);
          // 先移除第一个包含 fragment 的布局
          framecontainer.removeview(pagerlayout);

          // 创建一个用来占位的 framelayout
          framelayout holderlayout = new framelayout(getcontext());
          linearlayout.layoutparams pagerlinlayparams = new linearlayout.layoutparams(match_parent, match_parent);
          holderlayout.setlayoutparams(pagerlinlayparams);

          // 将占位的 framelayout 添加到布局中的 framecontainer 中
          framecontainer.addview(holderlayout, 0);

          // 添加 第一个包含 fragment 的布局添加到 spinmenu 中
          framelayout.layoutparams pagerframeparams = new framelayout.layoutparams(match_parent, match_parent);
          pagerlayout.setlayoutparams(pagerframeparams);
          addview(pagerlayout);
        }

        // 显示标题
        if (hintstrlist != null && !hintstrlist.isempty() && i < hintstrlist.size()) {
          tvhint = (textview) smitemlayout.findviewwithtag(tag_item_hint);
          tvhint.settext(hintstrlist.get(i));
          tvhint.settextsize(hinttextsize);
          tvhint.settextcolor(hinttextcolor);
        }

        // 位于菜单中当前显示 fragment 两边的 smitemlayout 左右移动 tran_sknew_value 个距离
        if (turntablemenulayout.getselectedposition() + 1 == i
            || (turntablemenulayout.iscyclic()
              && turntablemenulayout.getmenuitemcount() - i == turntablemenulayout.getselectedposition() + 1)) { // 右侧 itemmenu
          smitemlayout.settranslationx(tran_sknew_value);
        } else if (turntablemenulayout.getselectedposition() - 1 == i
            || (turntablemenulayout.iscyclic()
              && turntablemenulayout.getmenuitemcount() - i == 1)) { // 左侧 itemmenu
          smitemlayout.settranslationx(-tran_sknew_value);
        } else {
          smitemlayout.settranslationx(0);
        }
      }
      turntablemenuanimator = new turntablemenuanimator(this, turntablemenulayout, onspinmenustatechangelistener);
      init = false;
      openmenu();
    }
  }

  @override
  public boolean dispatchtouchevent(motionevent ev) {
    if (enablegesture) menudetector.ontouchevent(ev);
    return super.dispatchtouchevent(ev);
  }

  @override
  public boolean ontouchevent(motionevent event) {
    if (enablegesture) {
      menudetector.ontouchevent(event);
      return true;
    } else {
      return super.ontouchevent(event);
    }
  }

  /**
   * 根据手机的分辨率从 px(像素) 的单位转成为 sp
   * @param pxvalue
   * @return
   */
  private int px2sp(float pxvalue) {
    final float fontscale = getcontext().getresources().getdisplaymetrics().scaleddensity;
    return (int) (pxvalue / fontscale + 0.5f);
  }

  private void log(string log) {
    log.d(tag, log);
  }

  public void setfragmentadapter(pageradapter adapter) {
    if (pageradapter != null) {
      pageradapter.startupdate(turntablemenulayout);
      for (int i = 0; i < adapter.getcount(); i++) {
        viewgroup pager = (viewgroup) turntablemenulayout.getchildat(i).findviewwithtag(tag_item_pager);
        pageradapter.destroyitem(pager, i, pagerobjects.get(i));
      }
      pageradapter.finishupdate(turntablemenulayout);
    }

    int pagercount = adapter.getcount();
    if (pagercount > turntablemenulayout.getmaxmenuitemcount())
      throw new runtimeexception(string.format("fragment number can't be more than %d", turntablemenulayout.getmaxmenuitemcount()));

    pageradapter = adapter;

    smitemlayout.layoutparams itemlinlayparams = new smitemlayout.layoutparams(wrap_content, wrap_content);
    linearlayout.layoutparams containerlinlayparams = new linearlayout.layoutparams(match_parent, match_parent);
    framelayout.layoutparams pagerframeparams = new framelayout.layoutparams(match_parent, match_parent);
    linearlayout.layoutparams hintlinlayparams = new linearlayout.layoutparams(wrap_content, wrap_content);
    hintlinlayparams.topmargin = hint_top_margin;
    pageradapter.startupdate(turntablemenulayout);
    for (int i = 0; i < pagercount; i++) {
      // 创建菜单父容器布局
      smitemlayout smitemlayout = new smitemlayout(getcontext());
      smitemlayout.setid(i + 1);
      smitemlayout.setgravity(gravity.center);
      smitemlayout.setlayoutparams(itemlinlayparams);

      // 创建包裹framelayout
      framelayout framecontainer = new framelayout(getcontext());
      framecontainer.setid(pagercount + i + 1);
      framecontainer.settag(tag_item_container);
      framecontainer.setlayoutparams(containerlinlayparams);

      // 创建 fragment 容器
      framelayout framepager = new framelayout(getcontext());
      framepager.setid(pagercount * 2 + i + 1);
      framepager.settag(tag_item_pager);
      framepager.setlayoutparams(pagerframeparams);
      object object = pageradapter.instantiateitem(framepager, i);

      // 创建菜单标题 textview
      textview tvhint = new textview(getcontext());
      tvhint.setid(pagercount * 3 + i + 1);
      tvhint.settag(tag_item_hint);
      tvhint.setlayoutparams(hintlinlayparams);

      framecontainer.addview(framepager);
      smitemlayout.addview(framecontainer);
      smitemlayout.addview(tvhint);
      turntablemenulayout.addview(smitemlayout);

      pagerobjects.add(object);
      smitemlayoutlist.add(smitemlayout);
    }
    pageradapter.finishupdate(turntablemenulayout);
  }

  public void openmenu() {
    if (menustate == menu_state_closed) {
      turntablemenuanimator.openmenuanimator();
    }
  }

  public void closemenu(smitemlayout chooseitemlayout) {
    if (menustate == menu_state_opened) {
      turntablemenuanimator.closemenuanimator(chooseitemlayout);
    }
  }

  public int getmenustate() {
    return menustate;
  }

  public void updatemenustate(int state) {
    menustate = state;
  }

  public void setenablegesture(boolean enable) {
    enablegesture = enable;
  }

  public void setmenuitemscalevalue(float scalevalue) {
    scaleratio = scalevalue;
  }

  public void sethinttextsize(int textsize) {
    hinttextsize = textsize;
  }

  public void sethinttextcolor(int textcolor) {
    hinttextcolor = textcolor;
  }

  public void sethinttextstrlist(list<string> hinttextlist) {
    hintstrlist = hinttextlist;
  }

  public void setonspinmenustatechangelistener(onspinmenustatechangelistener listener) {
    onspinmenustatechangelistener = listener;
  }

  public float getscaleratio() {
    return scaleratio;
  }
}

github:slidmenu

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网