自定义弹出式菜单
来源:互联网 发布:政府 阿里云 安全 编辑:程序博客网 时间:2024/06/03 16:57
自定义ViewGroup实现弹出式菜单
在看了鸿洋大神的自定义ArcMenu之后,自己动手实现了功能相同的ArcMenu,记录一下:
首先来个效果图:
- 自定义属性(创建attr.xml)
//创建自定义属性值(中心Button的位置和Item中心Button的半径)<?xml version="1.0" encoding="utf-8"?><resources> <attr name="position"> <enum name="left_top" value="0"/> <enum name="left_bottom" value="1"/> <enum name="right_top" value="2"/> <enum name="right_bottom" value="3"/> </attr> <attr name="radius" format="dimension"/> <declare-styleable name="ArcMenu"> <attr name="position"/> <attr name="radius"/> </declare-styleable></resources>
- 创建ArcMenu继承ViewGroup
import android.content.Context;import android.content.res.TypedArray;import android.util.AttributeSet;import android.util.Log;import android.util.TypedValue;import android.view.View;import android.view.ViewGroup;import android.view.animation.AlphaAnimation;import android.view.animation.Animation;import android.view.animation.AnimationSet;import android.view.animation.OvershootInterpolator;import android.view.animation.RotateAnimation;import android.view.animation.ScaleAnimation;import android.view.animation.TranslateAnimation;/** * Author : luweicheng on 2017/5/3 0003 18:56 * E-mail :1769005961@qq.com * GitHub : https://github.com/luweicheng24 * funcation: 自定义ViewGroup */public class ArcMenu extends ViewGroup implements View.OnClickListener { private Position mPosition = Position.LEFT_BOTTOM; private Statu mStatu = Statu.CLOSE; private int radius = 100; private View mCbutton; @Override public void onClick(View v) { toggleButton(); } private void toggleButton() { final int count = getChildCount(); for (int i = 0; i < count - 1; i++) { final View childView = getChildAt(i + 1); childView.setVisibility(View.VISIBLE); int xflag = 1; int yflag = 1; if (mPosition == Position.LEFT_TOP || mPosition == Position.LEFT_BOTTOM) xflag = -1; if (mPosition == Position.LEFT_TOP || mPosition == Position.RIGHT_TOP) yflag = -1; // child left int cl = (int) (radius * Math.sin(Math.PI / 2 / (count - 2) * i)); // child top int ct = (int) (radius * Math.cos(Math.PI / 2 / (count - 2) * i)); AnimationSet animSet = new AnimationSet(true); TranslateAnimation translateAnimation = null; switch (mStatu) { case CLOSE: //to open translateAnimation = new TranslateAnimation(xflag * cl, 0f, yflag * ct, 0f); childView.setClickable(true); childView.setFocusable(true); break; case OPEN: //to close translateAnimation= new TranslateAnimation(0f, xflag * cl, 0f, yflag * ct); childView.setClickable(false); childView.setFocusable(false); break; } translateAnimation.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { } @Override public void onAnimationEnd(Animation animation) { Log.e("", "onAnimationEnd: "); if (mStatu == Statu.CLOSE) { childView.setVisibility(GONE); } } @Override public void onAnimationRepeat(Animation animation) { } }); translateAnimation.setFillAfter(true); translateAnimation.setDuration(300); translateAnimation.setStartOffset((i * 100) / (count - 1)); translateAnimation.setInterpolator(new OvershootInterpolator(2F)); RotateAnimation rotateAnimation = new RotateAnimation(0, 720, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f); rotateAnimation.setFillAfter(true); rotateAnimation.setDuration(300); animSet.addAnimation(rotateAnimation); animSet.addAnimation(translateAnimation); childView.startAnimation(animSet); final int index = i+1; childView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if(onMenuItemClickListener!=null){ onMenuItemClickListener.itemClick(index); menuItemAnim(index); } } }); } changeMenuStaus(); } /** * Menu的Item动画监听 * @param index */ private void menuItemAnim(int index) { for (int i = 0; i < getChildCount()-1; i++) { View view = getChildAt(i+1); if(index == i+1){ scaleItem(view); }else{ smallScale(view); } view.setClickable(false); view.setFocusable(false); mStatu = Statu.CLOSE; } } /** * 点击菜单项放大缩小 * @param childView */ private void scaleItem(View childView) { AnimationSet set = new AnimationSet(true); ScaleAnimation scale1= new ScaleAnimation(1.0f,1.5f,1.0f,1.5f,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f); scale1.setDuration(200); ScaleAnimation scale2= new ScaleAnimation(1.5f,1.0f,1.5f,1.0f,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f); scale2.setStartOffset(200); scale2.setDuration(200); scale2.setFillAfter(true); Animation alphaAnimation = new AlphaAnimation(1, 0); alphaAnimation.setFillAfter(true); alphaAnimation.setDuration(200); set.addAnimation(scale1); set.addAnimation(scale2); set.addAnimation(alphaAnimation); set.setFillAfter(true); childView.startAnimation(set); } private void smallScale(View v){ Animation alphaAnimation = new AlphaAnimation(1, 0); alphaAnimation.setFillAfter(true); alphaAnimation.setDuration(200); v.startAnimation(alphaAnimation); } /** * 菜单点击监听 */ public interface OnMenuItemClickListener{ void itemClick(int index); } public void setOnMenuItemClickListener(OnMenuItemClickListener onMenuItemClickListener) { this.onMenuItemClickListener = onMenuItemClickListener; } private OnMenuItemClickListener onMenuItemClickListener; /** * 切换按钮状态 */ private void changeMenuStaus() { switch (mStatu) { case OPEN: rotateView(mCbutton, 0, 45f); mStatu = Statu.CLOSE; break; case CLOSE: rotateView(mCbutton, 45f, 0f); mStatu = Statu.OPEN; break; } } public void rotateView(View v, float from, Float to) { /** * 创建旋转动画, * from 开始的旋转角 to 终止的旋转角 * piovXType piovYType 旋转的类型 Animation.RELATIVE_TO_DELF 以自身为标准 * * pivotXValue (0 - 1)0 代表以该View 的左上角为中心, 1代表以该View 的右底角为中心旋转 */ RotateAnimation anim = new RotateAnimation(from, to, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); anim.setDuration(200); anim.setFillAfter(true); mCbutton.setAnimation(anim); anim.start(); } /** * 打开和关闭的枚举类 */ public enum Statu { CLOSE, OPEN } /** * 位置的枚举类 */ public enum Position { LEFT_TOP, LEFT_BOTTOM, RIGHT_TOP, RIGHT_BOTTOM } public ArcMenu(Context context) { this(context, null); } public ArcMenu(Context context, AttributeSet attrs) { this(context, attrs, 0); } public ArcMenu(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); //dp转化成px radius = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, radius, getResources().getDisplayMetrics()); TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.ArcMenu, defStyleAttr, 0); int count = a.getIndexCount(); /** * 遍历自定义属性赋值 */ for (int i = 0; i < count; i++) { int attr = a.getIndex(i); switch (attr) { case R.styleable.ArcMenu_position: int index = a.getInt(attr, 0); switch (index) { case 0: mPosition = Position.LEFT_TOP; break; case 1: mPosition = Position.LEFT_BOTTOM; break; case 2: mPosition = Position.RIGHT_TOP; break; case 3: mPosition = Position.RIGHT_BOTTOM; break; } break; case R.styleable.ArcMenu_radius: radius = a.getDimensionPixelSize(attr, 100); break; } } a.recycle(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); /** * 测量子View */ int count = getChildCount(); for (int i = 0; i < count; i++) { View v = getChildAt(i); measureChild(v, MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); } } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { if (changed) { layoutCenterButton(); int count = getChildCount() - 2; for (int i = 0; i < count + 1; i++) { View view = getChildAt(i + 1); int w = view.getMeasuredWidth(); int h = view.getMeasuredHeight(); int left = 0; int top = 0; int right = 0; int bottom = 0; switch (mPosition) { case LEFT_TOP: left = (int) (radius * Math.sin(Math.PI / 2 / count * i)); top = (int) (radius * Math.cos(Math.PI / 2 / count * i)); right = left + w; bottom = top + h; break; case LEFT_BOTTOM: left = (int) (radius * Math.sin(Math.PI / 2 / count * i)); bottom = getMeasuredHeight() - (int) (radius * Math.cos(Math.PI / 2 / count * i)); right = left + w; top = bottom - h; break; case RIGHT_BOTTOM: right = getMeasuredWidth() - (int) (radius * Math.sin(Math.PI / 2 / count * i)); bottom = getMeasuredHeight() - (int) (radius * Math.cos(Math.PI / 2 / count * i)); top = bottom - h; left = right - w; break; case RIGHT_TOP: right = getMeasuredWidth() - (int) (radius * Math.sin(Math.PI / 2 / count * i)); top = (int) (radius * Math.cos(Math.PI / 2 / count * i)); bottom = top + h; left = right - w; break; } view.layout(left, top, right, bottom); view.setVisibility(GONE); mStatu = Statu.CLOSE; } } } /** * 根据布局中设置的position属性来确定中间按钮的位置 */ private void layoutCenterButton() { int left = 0; int top = 0; mCbutton = getChildAt(0); mCbutton.setOnClickListener(this); int but_width = mCbutton.getMeasuredWidth(); int but_height = mCbutton.getMeasuredHeight(); switch (mPosition) { case LEFT_TOP: mCbutton.layout(left, top, left + but_width, top + but_height); break; case LEFT_BOTTOM: mCbutton.layout(left, getMeasuredHeight() - but_width, left + but_width, getMeasuredHeight()); break; case RIGHT_TOP: mCbutton.layout(getMeasuredWidth() - but_width, top, getMeasuredWidth(), top + but_height); break; case RIGHT_BOTTOM: mCbutton.layout(getMeasuredWidth() - but_width, getMeasuredHeight() - but_height, getMeasuredWidth(), getMeasuredHeight()); break; } }}
Github源码链接这里写链接内容
0 0
- 自定义弹出式菜单
- iphone自定义弹出式菜单(popoverView)
- 自定义PopupWindow实现底部弹出式菜单
- 自定义PopupWindow实现底部弹出式菜单
- 添加菜单/自定义菜单/弹出式菜单(转集)
- 弹出式菜单
- 弹出式菜单
- 弹出式菜单
- 弹出式菜单
- 弹出式菜单
- 弹出式菜单
- 制作弹出式菜单
- js实现弹出式菜单
- 弹出式菜单的实现
- vc6 弹出式菜单
- VC弹出式菜单
- Java 右键弹出式菜单
- 制作弹出式菜单按钮
- java 对象按字母排序
- 联合索引的基本知识
- java解析utf-8文件
- Android7.0适配之FileProvide(拍照,裁剪,应用安装)
- 金字塔游戏 递归算法
- 自定义弹出式菜单
- 移动端的rem布局
- Android Support Annotation
- PAT 乙级 1033. 旧键盘打字(20)
- ijkplayer播放器的read_thread数据接受线程在处理音频的时候如果首个数据包没有发现audio stream 以后就不会有音频数据
- 该Android studio 默认jdk版本
- Gear 360新款发布!预购有礼哦
- django 自定义分页与bootstrap分页结合
- 模拟memcpy