Android自定义转盘菜单效果
程序员文章站
2022-04-05 18:54:23
最近由于公司项目需要,需要开发一款转盘菜单,费了好大功夫搞出来了,下面分享下样图具体功能如下:import android.graphics.color;import android.os.bundl...
最近由于公司项目需要,需要开发一款转盘菜单,费了好大功夫搞出来了,下面分享下
样图
具体功能如下:
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
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。