LZ该公司最近接手一个项目,需要写一个圆形旋转菜单,和菜单之间的移动换位支持,我本来以为这样的demo如若互联网是非常。想想你妈妈也帮不了我,空旋转,但它不能改变位置,所以LZ我们只能靠自己摸索。

最后LZ参考代码的在线部分。了一个自己定义的view最终实现了这个看似非常吊。却没有实际意义的功能。

在此贡献出来给广大码农们共享。

话不多说,先上代码:

自己定义view类:

public class RoundSpinView extends View {private Paint mPaint = new Paint();private PaintFlagsDrawFilter pfd;private int startMenu;   //菜单的第一张图片的资源id// stone列表private BigStone[] mStones;// 数目private static final int STONE_COUNT = 3;// 圆心坐标private int mPointX = 0, mPointY = 0;// 半径private int mRadius = 0;// 每两个点间隔的角度private int mDegreeDelta;private int menuRadius; // 菜单的半径private int mCur = -1; // 正在被移动的menu;private boolean[] quadrantTouched;   //对每一个象限触摸情况的记录// Touch detectionprivate GestureDetector mGestureDetector;private onRoundSpinViewListener mListener;  //自己定义事件监听器private final static int TO_ROTATE_BUTTON = 0;  //旋转button;private Handler handler = new Handler(){public void handleMessage(Message msg) {switch (msg.what) {case TO_ROTATE_BUTTON:float velocity = Float.parseFloat(msg.obj.toString());rotateButtons(velocity/75);velocity /= 1.0666F;new Thread(new FlingRunnable(velocity)).start();break;default:break;}};};public interface onRoundSpinViewListener{public void onSingleTapUp(int position);  //监听每一个菜单的单击事件}public RoundSpinView(Context context,AttributeSet attrs) {super(context,attrs);if(attrs!=null){TypedArray a = getContext().obtainStyledAttributes(attrs,R.styleable.RoundSpinView);startMenu = a.getResourceId(R.styleable.RoundSpinView_menuStart, 0);}pfd = new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG|Paint.FILTER_BITMAP_FLAG); mPaint.setColor(Color.WHITE);mPaint.setStrokeWidth(2);mPaint.setAntiAlias(true); //消除锯齿  mPaint.setStyle(Paint.Style.STROKE); //绘制空心圆 PathEffect effects = new DashPathEffect(new float[]{5,5,5,5},1);  mPaint.setPathEffect(effects);quadrantTouched = new boolean[] { false, false, false, false, false };mGestureDetector = new GestureDetector(getContext(),new MyGestureListener());setupStones();}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {// TODO Auto-generated method stubsuper.onMeasure(widthMeasureSpec, heightMeasureSpec);mPointX = this.getMeasuredWidth()/2;mPointY = this.getMeasuredHeight()/2;//初始化半径和菜单半径mRadius = mPointX-mPointX/5;menuRadius = (int)(mPointX/5.5);computeCoordinates();}/*** 初始化每一个点*/private void setupStones() {mStones = new BigStone[STONE_COUNT];BigStone stone;int angle = 270;mDegreeDelta = 360 / STONE_COUNT;for (int index = 0; index < STONE_COUNT; index++) {stone = new BigStone();if (angle >= 360) {angle -= 360;}else if(angle < 0){angle += 360;}stone.angle = angle;stone.bitmap = BitmapFactory.decodeResource(getResources(),startMenu + index);angle += mDegreeDelta;mStones[index] = stone;}}/*** 又一次计算每一个点的角度*/private void resetStonesAngle(float x, float y) {int angle = computeCurrentAngle(x, y);Log.d("RoundSpinView", "angle:" + angle);for (int index = 0; index < STONE_COUNT; index++) {mStones[index].angle = angle;angle += mDegreeDelta;}}/*** 计算每一个点的坐标*/private void computeCoordinates() {BigStone stone;for (int index = 0; index < STONE_COUNT; index++) {stone = mStones[index];stone.x = mPointX+ (float) (mRadius * Math.cos(Math.toRadians(stone.angle)));stone.y = mPointY+ (float) (mRadius * Math.sin(Math.toRadians(stone.angle)));}}/*** 计算某点的角度* * @param x* @param y* @return*/private int computeCurrentAngle(float x, float y) {float distance = (float) Math.sqrt(((x - mPointX) * (x - mPointX) + (y - mPointY)* (y - mPointY)));int degree = (int) (Math.acos((x - mPointX) / distance) * 180 / Math.PI);if (y < mPointY) {degree = -degree;}Log.d("RoundSpinView", "x:" + x + ",y:" + y + ",degree:" + degree);return degree;}private double startAngle;@Overridepublic boolean dispatchTouchEvent(MotionEvent event) {// resetStonesAngle(event.getX(), event.getY());// computeCoordinates();// invalidate();int x, y;if (event.getAction() == MotionEvent.ACTION_DOWN) {x = (int) event.getX();y = (int) event.getY();mCur = getInCircle(x, y);if (mCur == -1) {startAngle = computeCurrentAngle(x, y);}} else if (event.getAction() == MotionEvent.ACTION_MOVE) {x = (int) event.getX();y = (int) event.getY();if (mCur != -1) {mStones[mCur].x = x;mStones[mCur].y = y;invalidate();} else {double currentAngle = computeCurrentAngle(x, y);rotateButtons(startAngle - currentAngle);startAngle = currentAngle;}} else if (event.getAction() == MotionEvent.ACTION_UP) {x = (int) event.getX();y = (int) event.getY();if (mCur != -1) {computeCoordinates();int cur = getInCircle(x, y);if (cur != mCur && cur != -1) {int angle = mStones[mCur].angle;mStones[mCur].angle = mStones[cur].angle;mStones[cur].angle = angle;}computeCoordinates();invalidate();mCur = -1;}}// set the touched quadrant to truequadrantTouched[getQuadrant(event.getX() - mPointX,mPointY - event.getY())] = true;mGestureDetector.onTouchEvent(event);return true;}private class MyGestureListener extends SimpleOnGestureListener {@Overridepublic boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,float velocityY) {// get the quadrant of the start and the end of the flingint q1 = getQuadrant(e1.getX() - mPointX, mPointY - e1.getY());int q2 = getQuadrant(e2.getX() - mPointX, mPointY - e2.getY());// the inversed rotationsif ((q1 == 2 && q2 == 2 && Math.abs(velocityX) < Math.abs(velocityY))|| (q1 == 3 && q2 == 3)|| (q1 == 1 && q2 == 3)|| (q1 == 4 && q2 == 4 && Math.abs(velocityX) > Math.abs(velocityY))|| ((q1 == 2 && q2 == 3) || (q1 == 3 && q2 == 2))|| ((q1 == 3 && q2 == 4) || (q1 == 4 && q2 == 3))|| (q1 == 2 && q2 == 4 && quadrantTouched[3])|| (q1 == 4 && q2 == 2 && quadrantTouched[3])) {// CircleLayout.this.post(new FlingRunnable(-1// * (velocityX + velocityY)));new Thread(new FlingRunnable(velocityX+velocityY)).start();} else {// the normal rotation// CircleLayout.this// .post(new FlingRunnable(velocityX + velocityY));new Thread(new FlingRunnable(-(velocityX+velocityY))).start();}return true;}@Overridepublic boolean onSingleTapUp(MotionEvent e) {int cur = getInCircle((int)e.getX(),(int)e.getY());if(cur!=-1){if(mListener!=null){mListener.onSingleTapUp(cur);}
//              Toast.makeText(getContext(), "position:"+cur, 0).show();return true;}return false;}}private class FlingRunnable implements Runnable{private float velocity;public FlingRunnable(float velocity){this.velocity = velocity;}@Overridepublic void run() {// TODO Auto-generated method stubif(Math.abs(velocity)>=200){Message message = Message.obtain();message.what = TO_ROTATE_BUTTON;message.obj = velocity;handler.sendMessage(message);}}}/*** @return The selected quadrant.*/private static int getQuadrant(double x, double y) {if (x >= 0) {return y >= 0 ? 1 : 4;} else {}return y >= 0 ?

2 : 3; } /* * 旋转菜单button */ private void rotateButtons(double degree) { for (int i = 0; i < STONE_COUNT; i++) { mStones[i].angle -= degree; if (mStones[i].angle < 0) { mStones[i].angle += 360; }else if(mStones[i].angle >=360){ mStones[i].angle -= 360; } } computeCoordinates(); invalidate(); } @Override public void onDraw(Canvas canvas) { //画一个白色的圆环 canvas.drawCircle(mPointX, mPointY, mRadius, mPaint); //将每一个菜单画出来 for (int index = 0; index < STONE_COUNT; index++) { if (!mStones[index].isVisible) continue; drawInCenter(canvas, mStones[index].bitmap, mStones[index].x, mStones[index].y); } } /** * 把中心点放到中心处 * * @param canvas * @param bitmap * @param left * @param top */ private void drawInCenter(Canvas canvas, Bitmap bitmap, float left, float top) { Rect dst = new Rect(); dst.left = (int) (left - menuRadius); dst.right = (int) (left + menuRadius); dst.top = (int) (top - menuRadius); dst.bottom = (int) (top + menuRadius); canvas.setDrawFilter(pfd); canvas.drawBitmap(bitmap, null, dst, mPaint); } private int getInCircle(int x, int y) { for (int i = 0; i < STONE_COUNT; i++) { BigStone stone = mStones[i]; int mx = (int) stone.x; int my = (int) stone.y; if (((x - mx) * (x - mx) + (y - my) * (y - my)) < menuRadius * menuRadius) { return i; } } return -1; } public void setOnRoundSpinViewListener(onRoundSpinViewListener listener){ this.mListener = listener; } class BigStone { // 图片 Bitmap bitmap; // 角度 int angle; // x坐标 float x; // y坐标 float y; // 是否可见 boolean isVisible = true; } }

layout文件代码:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><com.example.roundspinviewdemo.view.RoundSpinViewandroid:id="@+id/rsv_test"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_gravity="center"android:background="@drawable/menubkground"app:menuStart="@drawable/menu1" /></LinearLayout>

注意:必须加上这一条 :

xmlns:app="http://schemas.android.com/apk/res-auto"

此外必须加入attr文件设置相应的自己定义属性:

<?xml version="1.0" encoding="utf-8"?>
<resources><!-- 设置旋转菜单相应的第一张图片 --><declare-styleable name="RoundSpinView"><attr name="menuStart" format="reference" /></declare-styleable>
</resources>

接下来就是activity中的应用了:

public class MainActivity extends Activity implements onRoundSpinViewListener {private RoundSpinView rsv_test;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initView();}private void initView(){rsv_test = (RoundSpinView)this.findViewById(R.id.rsv_test);rsv_test.setOnRoundSpinViewListener(this);}@Overridepublic void onSingleTapUp(int position) {// TODO Auto-generated method stubswitch (position) {case 0:Toast.makeText(MainActivity.this, "place:0", 0).show();break;case 1:Toast.makeText(MainActivity.this, "place:1", 0).show();break;case 2:Toast.makeText(MainActivity.this, "place:2", 0).show();break;default:break;}}}

注意:

rsv_test.setOnRoundSpinViewListener(this);

对自己定义view的自己定义监听器进行赋值

至此。你的项目就能够拥有看上去非常高大上的旋转换位菜单功能

这里附上此demo相应的资源链接:点击打开链接

版权声明:本文博客原创文章,博客,未经同意,不得转载。

android圆形旋转菜单,而对于移动转换功能支持相关推荐

  1. Android 圆形旋转菜单

    我的视频课程:<FFmpeg打造Android万能音频播放器> 最近帮朋友做了一个动画菜单,感觉有一定的实用价值,就在此给大家分享一下,先看看效果:源码下载地址在末尾 实现思路: 从图中可 ...

  2. android圆形菜单,android 圆形旋转菜单例子

    [实例简介] [实例截图] [核心代码] package com.szugyi.circlemenu.view; /* * Copyright 2013 Csaba Szugyiczki * * Li ...

  3. android 双层旋转菜单,Android 高仿【优酷】圆盘旋转菜单的实现

    目前,用户对安卓应用程序的UI设计要求越来越高,因此,掌握一些新颖的设计很有必要. 比如菜单,传统的菜单已经不能满足用户的需求. 其中优酷中圆盘旋转菜单的实现就比较优秀,这里我提供下我的思路及实现,仅 ...

  4. ios 圆形旋转菜单_iOS 圆环菜单

    前言 之前的一个项目,没有使用TabBar,而是选择用圆环作为用户点击的菜单,加上深蓝的冷色调,APP看着还蛮高大上,先看下效果图: demo.gif 效果图分析 1.类似地球的是一张Image,其余 ...

  5. ios 圆形旋转菜单_iOS高级动画:圆形树展开收起动画

    转自:标哥的技术博客,作者:黄仪标(微博) 前段时间帮某某做了一个动画效果,今天分享给大家.关于动画的基础知识,这里不会细说,如果您还没有核心动画的基础知识,请先阅读相关文章,了解核心动画如何使用,然 ...

  6. html转动的圆圈,CSS圆形旋转效果 纯CSS制作圆形旋转菜单效果(七步完成)

    我们理念中的菜单都是矩形的,不是横向排列就是纵向排列,这里我们打破了常规的思维,把菜单做成圆形的. 在这里我们不得不克服几个问题: 如何定义html如何悬停定位菜单元素 在此之前先看一下最终效果是怎样 ...

  7. android圆形贝塞尔 菜单,Android 贝塞尔曲线——圆渐变心

    大家好!我是一名执着的Android开发攻城狮,第一次写简书,没有写好的希望大家多多包涵,万事开头难,从去年开始我就想写点自己的东西,但是一直没有写下去的勇气和毅力,希望这是我一个好的习惯开始.在这我 ...

  8. ios 圆形旋转菜单_iOS 屏幕强制旋转 (模态、Push、导航栏、状态栏)

    界面旋转准备 在AppDelegate.h中添加属性 //是否旋转 @property (nonatomic, assign) BOOL isRotation; 在AppDelegate.m中添加方法 ...

  9. ios 圆形旋转菜单_iOS实现滑动弧形菜单的思路与方法

    前言 最近公司的项目中需要用到弧形菜单,起初自定义UICollectionView的layout,但实现出的效果并不符合项目中要求按钮始终垂直于界面.界面始终保持几个按钮等一系列需求(是我水平不够), ...

最新文章

  1. Verilog学习----条件语句、循环语句、块语句与生成语句
  2. excel调用python编程-如何在excel中调用python脚本
  3. 汇编语言 pushf 和 popf指令
  4. CodeForces 340C
  5. GCC安装UBUNTU
  6. 关于Ubuntu 安装tftp服务器的问题解决
  7. 思维+multiset ZOJ Monthly, July 2015 - H Twelves Monkeys
  8. java 读取jar包中的文件
  9. python怎么导包_如何从python中的包导入所有函数?
  10. 在三个层次对Asp.Net的数据操作进行事务
  11. 帮写python代码_10个工具,帮你写出更好的Python代码
  12. x64技术之SSDT_Hook
  13. 部分js文件在360浏览器极速模式下不加载,不执行的原因
  14. CAN总线接口静电保护及ESD二极管选型
  15. Mybatis学习【2】
  16. 困惑与破题:人人喊打的屏幕时间究竟对孩子做了什么?
  17. 【数据分析师---数据可视化】第二章:plotly绘图基础篇
  18. “中国版特斯拉”绝地反击,自动驾驶开辟“第三条路”?
  19. 回文联对联大全_《回文对联集锦》序
  20. 【C语言】指针变量的定义、使用及初始化

热门文章

  1. Delphi 调用webservice接口
  2. 关于对J2EE几点误解和错误认识的澄清
  3. Winform与Webform中的对话框
  4. 你猜猜typeof (typeof 1) 会返回什么值(类型)?!
  5. 在CentOS7上部署Apache Mesos
  6. linux小脚本批量添加/删除用户
  7. 获取保存在沙盒中plist文件的用户的字典信息
  8. JetBrains发布DataGrip 1.0——数据库与SQL领域中的瑞士军刀
  9. 《团队项目开发之三对一维环形数组的求解》
  10. discuz,ecshop的伪静态规则(apache+nginx)