来自:http://blog.csdn.net/ywl5320/article/details/52449392
最近帮朋友做了一个动画菜单,感觉有一定的实用价值,就在此给大家分享一下,先看看效果:源码下载地址在末尾
实现思路:
从图中可以看出,这三个(或更多,需要自己再实现)菜单是围绕着中心点旋转的,旋转分为2层,背景旋转和菜单旋转,背景旋转可以直接用旋转动画来实现;菜单的旋转是在以中心点为圆心的圆环上,所以这里用了根据旋转角度求此点在直角坐标系中的坐标点的函数(x = r * cos(rotation* 3.14 / 180) 和y = r * sin(rotation* 3.14 / 180) ),然后根据获取到的点的位置来设置菜单的位置就能实现这种效果。由此可见 数学是很重要的 哈哈~~
有了思路我们就能用代码来实现了:
1、首先自定义View继承相对布局并重写构造函数
- /**
- * Created by ywl on 2016/8/7.
- */
- public class CircleMenuLayout extends RelativeLayout {
- public CircleMenuLayout(Context context) {
- this(context, null);
- }
- public CircleMenuLayout(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
- /**
- * 初始化布局 把旋转背景和中心点添加进去
- * @param context
- * @param attrs
- * @param defStyleAttr
- */
- public CircleMenuLayout(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- this.context = context;
- layoutInflater = LayoutInflater.from(context);
- menuitems = new ArrayList<View>();
- centerview = new View(context);//中心点
- centerview.setId(ID_CENTER_VIEW);
- LayoutParams lp = new LayoutParams(0, 0);
- lp.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
- addView(centerview, lp); //添加中心的 用于旋转定位
- progressBar = new ProgressBar(context);//旋转的背景
- LayoutParams lp2 = new LayoutParams(dip2px(context, 90), dip2px(context, 90));
- lp2.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
- addView(progressBar, lp2);
- progressBar.setIndeterminateDrawable(context.getResources().getDrawable(R.mipmap.icon_circle_menu));
- }
- }
2、根据传入的图片数组和菜单名字数组,生成菜单原始位置效果。
- /**
- * 菜单的数量 和 半径 名字 和图片 这里只为3个菜单做了适配
- * @param size
- * @param center_distance
- */
- public void initMenuItem(int size, int center_distance, String[] titles, int[] imgs)
- {
- radus = 360f / size;
- int width = dip2px(context, 50); //菜单宽度
- int height = dip2px(context, 50);//菜单高度
- for(int i = 0; i < size; i++) //循环添加布局
- {
- int top = 0;
- int left = 0;
- top = -(int)(Math.sin(radus * i * 3.1415f / 180) * center_distance); //r * cos(ao * 3.14 /180 )
- left = -(int)(Math.cos(radus * i * 3.1415f / 180) * center_distance); //计算位置点
- LayoutParams lp = new LayoutParams(dip2px(context, 50), dip2px(context, 50));
- View view = layoutInflater.inflate(R.layout.item_circle_menu, this, false);
- view.setTag(i);
- TextView tvname = (TextView) view.findViewById(R.id.tv_name);
- ImageView ivimg = (ImageView) view.findViewById(R.id.img);
- tvname.setText(titles[i]);
- ivimg.setImageResource(imgs[i]);
- view.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {//根据点击的区域 旋转菜单
- if(!isrun) {
- tag = (int) v.getTag();
- currentPosition = tag;
- if(tag == 0)
- {
- finishdus = -360;
- }
- else if(tag == 1)
- {
- finishdus = -120;
- }
- else if(tag == 2)
- {
- finishdus = -240;
- }
- LayoutParams lp = (LayoutParams) v.getLayoutParams();
- int l = lp.leftMargin;
- int t = lp.topMargin;
- if (t > -dip2px(context, 5) && l > -dip2px(context, 5)) {
- oldradus = 120f;
- isright = false;
- } else if (t > -dip2px(context, 5) && l < -dip2px(context, 5)) {
- oldradus = 120f;
- isright = true;
- } else if (t < -dip2px(context, 5)) {
- oldradus = 0f;
- }
- sub = 0;
- circleMenu(8, dip2px(context, 45), oldradus, isright);
- }
- }
- });
- lp.addRule(RelativeLayout.BELOW, centerview.getId());
- lp.addRule(RelativeLayout.RIGHT_OF, centerview.getId());
- lp.setMargins(-width / 2 + top, -height / 2 + left, 0, 0);
- addView(view, lp);
- menuitems.add(view);
- }
- handler.postDelayed(runnable, 0);
- }
根据菜单的数量循环计算每个菜单的位置,然后在相应的位置添加相应的菜单就可以实现菜单的初始化了。这里为每个菜单添加了点击事件,但是只适配了3个菜单的情况,至于其他数量的菜单,可以自己来改或者写一个通用的方法来计算点击位置。
3、背景旋转动画:
- /**
- * 根据度数来旋转菜单 菜单中心都在一个圆上面 采用圆周运动来旋转
- * @param offserradius
- * @param center_distance
- * @param d
- * @param right
- */
- public void circleMenu(float offserradius, int center_distance, float d, boolean right)
- {
- if(oldradus != 0)
- {
- progressBar.clearAnimation();
- if(isright)
- {
- mRotateUpAnim = new RotateAnimation(bgdus, bgdus + 120,
- Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
- 0.5f);
- bgdus += 120;
- }
- else
- {
- mRotateUpAnim = new RotateAnimation(bgdus, bgdus - 120,
- Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
- 0.5f);
- bgdus -= 120;
- }
- lir = new LinearInterpolator();
- mRotateUpAnim.setDuration(350);
- mRotateUpAnim.setFillAfter(true);
- mRotateUpAnim.setInterpolator(lir);
- // mRotateUpAnim.setRepeatCount(Animation.INFINITE);
- progressBar.startAnimation(mRotateUpAnim);
- }
- circleMenuItem(offserradius, center_distance, d, right);
- }
4、旋转菜单:
- /**
- * 菜单旋转
- * @param offserradius
- * @param center_distance
- * @param d
- * @param right
- */
- public void circleMenuItem(float offserradius, int center_distance, float d, boolean right)
- {
- sub += offserradius;
- if(sub > d)
- {
- if(onMenuItemSelectedListener != null)
- {
- onMenuItemSelectedListener.onMenuItemOnclick(tag);
- }
- isrun = false;
- return;
- }
- if(right) {
- offsetradus -= offserradius;
- }
- else
- {
- offsetradus += offserradius;
- }
- int size = menuitems.size();
- int width = dip2px(context, 50);
- int height = dip2px(context, 50);
- for(int i = 0; i < size; i++)
- {
- if(Math.abs(sub - d) <= 8)
- {
- offsetradus = finishdus;
- }
- LayoutParams lp = (LayoutParams) menuitems.get(i).getLayoutParams();
- float ds = radus * i + offsetradus;
- int top = -(int)(Math.sin(ds * 3.1415f / 180) * center_distance); //r * cos(ao * 3.14 /180 )
- int left = -(int)(Math.cos(ds * 3.1415f / 180) * center_distance);
- lp.setMargins(-width / 2 + top, -height / 2 + left, 0, 0);
- menuitems.get(i).requestLayout();
- }
- if(sub <= d) {
- isrun = true;
- offsetradus = offsetradus % 360;
- handler.postDelayed(runnable, 5);
- }
- else
- {
- if(onMenuItemSelectedListener != null)
- {
- onMenuItemSelectedListener.onMenuItemOnclick(tag);
- }
- isrun = false;
- }
- }
5、手动设置菜单项(有局限,没有通用性):
- /**
- * 设置旋转到哪个菜单项
- * @param tag
- */
- public void setCurrentTag(int tag)
- {
- if(currentPosition == tag)
- {
- return;
- }
- if(tag == 0)
- {
- finishdus = -360;
- }
- else if(tag == 1)
- {
- finishdus = -120;
- }
- else if(tag == 2)
- {
- finishdus = -240;
- }
- if(currentPosition == 0) //当前是0
- {
- if(tag == 1)
- {
- oldradus = 120f;
- isright = true;
- }
- else if(tag == 2)
- {
- oldradus = 120f;
- isright = false;
- }
- }
- else if(currentPosition == 1)
- {
- if(tag == 2)
- {
- oldradus = 120f;
- isright = true;
- }
- else if(tag == 0)
- {
- oldradus = 120f;
- isright = false;
- }
- }
- else if(currentPosition == 2)
- {
- if(tag == 0)
- {
- oldradus = 120f;
- isright = true;
- }
- else if(tag == 1)
- {
- oldradus = 120f;
- isright = false;
- }
- }
- currentPosition = tag;
- this.tag = tag;
- sub = 0;
- circleMenu(8, dip2px(context, 45), oldradus, isright);
- }
这样就可以实现旋转效果了。
6、调用方法:
(1)布局文件:
- <com.ywl5320.circlemenu.CircleMenuLayout
- android:id="@+id/cml_menu"
- android:layout_width="150dp"
- android:layout_height="150dp"
- android:layout_centerHorizontal="true"
- android:layout_alignParentBottom="true"
- android:layout_marginBottom="92dp"/>
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="100dp"
- android:layout_height="100dp"
- android:padding="5dp"
- android:gravity="center">
- <ImageView
- android:id="@+id/img"
- android:layout_width="25dp"
- android:layout_height="25dp"
- android:scaleType="fitXY"/>
- <TextView
- android:id="@+id/tv_name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="菜单项"
- android:textSize="9sp"
- android:gravity="center"
- android:textColor="#ffffff"/>
- </LinearLayout>
(3)Activity中调用
- <span style="white-space:pre"> </span>cmlmenu = (CircleMenuLayout) findViewById(R.id.cml_menu);
- btn = (Button) findViewById(R.id.btn);
- cmlmenu.initDatas(titles, imgs);
- cmlmenu.setOnMenuItemSelectedListener(new CircleMenuLayout.OnMenuItemSelectedListener() {
- @Override
- public void onMenuItemOnclick(int code) {
- if(code == 0)//
- {
- Toast.makeText(MainActivity.this, "支付宝", Toast.LENGTH_SHORT).show();
- }
- else if(code == 1)
- {
- Toast.makeText(MainActivity.this, "银联", Toast.LENGTH_SHORT).show();
- }
- else if(code == 2)
- {
- Toast.makeText(MainActivity.this, "微信", Toast.LENGTH_SHORT).show();
- }
- }
- });
欢迎下载和Star