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 detection
private 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();
} @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
super.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; @Override
public 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 true
quadrantTouched[getQuadrant(event.getX() - mPointX,
mPointY - event.getY())] = true;
mGestureDetector.onTouchEvent(event);
return true;
} private class MyGestureListener extends SimpleOnGestureListener {
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
// get the quadrant of the start and the end of the fling
int q1 = getQuadrant(e1.getX() - mPointX, mPointY - e1.getY());
int q2 = getQuadrant(e2.getX() - mPointX, mPointY - e2.getY()); // the inversed rotations
if ((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; } @Override
public 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;
} @Override
public void run() {
// TODO Auto-generated method stub
if(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.RoundSpinView
android: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;

	@Override
protected 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);
} @Override
public void onSingleTapUp(int position) {
// TODO Auto-generated method stub
switch (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的自己定义监听器进行赋值

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

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc3A2NjQ1NTk3/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">



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

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

android圆形旋转菜单,而对于移动转换功能支持的更多相关文章

  1. [Android阅读代码]圆形旋转菜单CircleMenu

    项目名称:圆形旋转菜单CircleMenu 原版项目代码下载 感谢原作者开源

  2. android简洁饼状图组件、圆形Menu菜单、画板画笔应用、答题应用等源码

    Android精选源码 android自动监听复制内容源码 Android上简洁轻量级的饼图控件 好看的 Android 圆形 Menu 菜单效果 android画笔.画板功能效果的实现 Androi ...

  3. Android 自定义圆形旋转进度条,仿微博头像加载效果

    微博 App 的用户头像有一个圆形旋转进度条的加载效果,看上去效果非常不错,如图所示: 据说 Instagram 也采用了这种效果.最近抽空研究了一下,最后实现的效果是这样: 基本上能模拟出个大概,代 ...

  4. 3D旋转菜单

    今天来个3D旋转菜单,是纯css3实现的,主要用到transform,transition,backface-visibility. 主要是transform这个变换,它是今天猪脚. transfor ...

  5. android 屏幕旋转

    转自:http://blog.csdn.net/oyzhizhong/article/details/8131799 屏是LANDSCAPE的,要让它默认显示为PORTRAIT. 1.kernel里要 ...

  6. Android 3D滑动菜单完全解析,实现推拉门式的立体特效

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/10471245 在上一篇文章中,我们学习了Camera的基本用法,并借助它们编写了一 ...

  7. Android中轴旋转特效实现,制作别样的图片浏览器

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/10766017 Android API Demos中有很多非常Nice的例子,这些例 ...

  8. Android立体旋转动画实现与封装(支持以X、Y、Z三个轴为轴心旋转)

    本文主要介绍Android立体旋转动画,或者3D旋转,下图是我自己实现的一个界面 立体旋转分为以下三种: 1. 以X轴为轴心旋转 2. 以Y轴为轴心旋转 3. 以Z轴为轴心旋转--这种等价于andro ...

  9. Android 屏幕旋转 处理 AsyncTask 和 ProgressDialog 的最佳方案

    的最佳方案 标签: Android屏幕旋转AsyncTaskProgressDialog 2014-07-19 09:25 39227人阅读 评论(46) 收藏 举报 分类: [android 进阶之 ...

随机推荐

  1. Instruments性能优化-Core Animation

    简书地址:http://www.jianshu.com/users/6cb2622d5eac/latest_articles 当App发展到一定的规模.性能优化就成为不可缺少的一点.可是非常多人,又对 ...

  2. vmnet1 and vmnet8

    在使用VMware Workstation创建虚拟机时.创建的虚拟机中能够包含网卡.你能够依据须要选择使用何种虚拟网卡.从而表明想要连接到那个虚拟交换机.在VMware Workstation中,默认 ...

  3. JavaScript、Ajax与jQuery的关系 分类: C1_HTML/JS/JQUERY 2014-07-31 10:15 3388人阅读 评论(0) 收藏

    简单总结: 1.JS是一门前端语言. 2.Ajax是一门技术,它提供了异步更新的机制,使用客户端与服务器间交换数据而非整个页面文档,实现页面的局部更新. 3.jQuery是一个框架,它对JS进行了封装 ...

  4. [内核编程] visual studio 2010配置驱动开发环境

    visual studio 2010 配置驱动开发环境 ** 工具/材料 VS2010.WDK开发包 **  配置过程 以下将讲述VS2010驱动开发环境的配置过程,至于必要软件的安装过程这里不再赘述 ...

  5. jquery获取元素坐标获取鼠标坐标

    获取页面某一元素的绝对X,Y坐标,可以用offset()方法: var X = $('#DivID').offset().top; var Y = $('#DivID').offset().left; ...

  6. linux下Oracle11g RAC搭建(一)

    linux下Oracle11g RAC搭建(一) 文档说明 作者    深蓝 项目 Visualbox下模拟RAC搭建(双节点)(Redhat5+Oracle11G) 环境 RedHat Enterp ...

  7. vs 2013 常用快捷键及常见问题的解决

    1. 代码编辑 关闭当前文档:ctrl + F4 打开光标所在位置的文档:ctrl + G(shift + g) 返回上次编辑的位置:ctrl + -(键盘数字键 0 后的那个按键) 移动光标所在的行 ...

  8. ArcSDE 设置

    ---------------------转载----------------------- a)创建加载路径——st_shapelib.dll         执行创建库脚本:create or r ...

  9. 【心情】codeforces涨分啦!

    虽然只有10分. 第二次比赛!

  10. NetSnmp配置

    http://blog.csdn.net/shanzhizi/article/details/16985989