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

Android自定义转盘菜单效果

程序员文章站 2022-07-09 15:20:28
最近由于公司项目需要,需要开发一款转盘菜单,费了好大功夫搞出来了,下面分享下样图具体功能如下:import android.graphics.color;import android.os.bundl...

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

样图

Android自定义转盘菜单效果

具体功能如下:

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

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