以前做项目碰到过一个需求,就是有5个button,这5个button要围绕一个点不停的转动,而且点击不同的button会进行相应的逻辑,比如activity的跳转等.

就类似于gallery,但是又有所不同

有人会首先想到用偏移动画,但是android的偏移动画只是动画,也就是说你从A点移动B点,看上去是移动过去了,但是点击的事件触发却还是在A点,实际上没有真正的

偏移过去,只是欺骗眼睛罢了,但是在android2.2以后api提供了这样的一个方法setPosition(),这个方法的好处是你可以监听动画,假如一段动画完成了你可以动态的

得到现在button的位置,然后set进去,这样也可以完成操作,但是简单的运动还行,如果是向我上门说的5个button不停的转动,然后每个button的动画不断的监听然后set

会很费事,而且2.2以下的pad或者手机就没有办法安装了

其实如果是在ios上这样是非常容易的,ios的偏移动画很像我们做flash一样,定制起始点,再定制一个终点,然后创建补间动画即可,几行代码就可以搞定,但是android上就不行

所以基于以上,我就只能是这个思路,我就实现真正的偏移好了,对,就是用开发游戏的思路实现真正的偏移

下面我直接上代码了,以下是舞台的代码

我的button就相当于演员,演员要表演只能去舞台

package com.yp.rotatebutton;import android.app.Activity;import android.content.Context;import android.graphics.BitmapFactory;import android.graphics.Canvas;import android.graphics.Color;import android.util.DisplayMetrics;import android.util.Log;import android.view.SurfaceHolder;import android.view.SurfaceView;import android.view.WindowManager;public class RotateStage extends SurfaceView implements SurfaceHolder.Callback,Runnable {public static final String TAG= "RotateStage";private Context context ;private SurfaceHolder holder ;private Thread mThread ;private Canvas mCanvas;private boolean isMovie = false;private RotateImageView mOneImageView ,mTwoImageView, mThreeImageView,mFourthImageView,mFiveImageView;public static double POINTX = DisplayMetrics.DENSITY_LOW ;public static double POINTY = DisplayMetrics.DENSITY_HIGH ;public static final  double RADIUS = 100;public RotateStage(Context context) {super(context);this.context = context;this.holder = this.getHolder();this.holder.addCallback(this);DisplayMetrics dm = new DisplayMetrics();((Activity) this.context).getWindowManager().getDefaultDisplay().getMetrics(dm);POINTX = dm.widthPixels / 2 -  BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher).getWidth() / 2;POINTY = dm.heightPixels / 2 - BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher).getHeight() / 2 ;Init();}private void Init(){mOneImageView = new RotateImageView(this.context,R.drawable.ic_launcher, POINTX+ Math.cos(0 * RotateImageView.ANGLENUM) * RADIUS,POINTY + Math.sin(0 * RotateImageView.ANGLENUM) * RADIUS, 0);mTwoImageView = new RotateImageView(this.context,R.drawable.ic_launcher, POINTX+ Math.cos(72 * RotateImageView.ANGLENUM) * RADIUS,POINTY + Math.sin(72 * RotateImageView.ANGLENUM) * RADIUS, 72);mThreeImageView = new RotateImageView(this.context,R.drawable.ic_launcher, POINTX+ Math.cos(144 * RotateImageView.ANGLENUM) * RADIUS,POINTY + Math.sin(144 * RotateImageView.ANGLENUM) * RADIUS, 144);mFourthImageView = new RotateImageView(this.context,R.drawable.ic_launcher, POINTX+ Math.cos(216 * RotateImageView.ANGLENUM) * RADIUS,POINTY + Math.sin(216 * RotateImageView.ANGLENUM) * RADIUS, 216);mFiveImageView = new RotateImageView(this.context,R.drawable.ic_launcher, POINTX+ Math.cos(288 * RotateImageView.ANGLENUM) * RADIUS,POINTY + Math.sin(288 * RotateImageView.ANGLENUM) * RADIUS, 288);}@Overridepublic void surfaceCreated(SurfaceHolder holder) {// TODO Auto-generated method stubmThread = new Thread(this);mThread.start();}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width,int height) {isMovie = true ;}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {// TODO Auto-generated method stubisMovie = false;}@Overridepublic void run() {while (isMovie) {long start = System.currentTimeMillis();draw();logic();long end = System.currentTimeMillis();if (end - start < 5) {try {Thread.sleep (5 - (end - start)) ;//Thread.sleep(5);} catch (InterruptedException e) {Log.v(TAG, "run thread sleep error : " + e.toString());}}}}public void draw(){try{mCanvas = holder.lockCanvas() ;mCanvas.drawColor(Color.RED);mCanvas.drawBitmap(mOneImageView.getmBgBitmap(), (float)mOneImageView.getxPix(), (float)mOneImageView.getyPix(), null);mCanvas.drawBitmap(mTwoImageView.getmBgBitmap(), (float)mTwoImageView.getxPix(), (float)mTwoImageView.getyPix(), null);mCanvas.drawBitmap(mThreeImageView.getmBgBitmap(), (float)mThreeImageView.getxPix(), (float)mThreeImageView.getyPix(), null);mCanvas.drawBitmap(mFourthImageView.getmBgBitmap(), (float)mFourthImageView.getxPix(), (float)mFourthImageView.getyPix(), null);mCanvas.drawBitmap(mFiveImageView.getmBgBitmap(), (float)mFiveImageView.getxPix(), (float)mFiveImageView.getyPix(), null);}catch (Exception e) {Log.v(TAG, "draw error: " + e.toString());}finally{if (mCanvas != null) holder.unlockCanvasAndPost(mCanvas) ;}}private void logic() {mOneImageView.moveImageButton();mTwoImageView.moveImageButton();mThreeImageView.moveImageButton();mFourthImageView.moveImageButton();mFiveImageView.moveImageButton();}}

舞台中的演员:RotateImageView 这个也是我自己定义的一个类,就相当于button,你要在舞台上添加几个演员你就new几个好了,我没有好的图片,所以就拿默认的icon了,讲究看吧

package com.yp.rotatebutton;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.util.Log;/** *  * @author peng_yu * */public class RotateImageView {public static final String TAG = "RotateImageView";public static final double ANGLENUM = Math.PI/180;private Bitmap mBgBitmap;private double angle ;private double xPix;private double yPix;public RotateImageView() {super();}public RotateImageView(Context content,int bgId,double XPix,double Ypix,double angle) {BitmapFactory.Options opts = new BitmapFactory.Options();opts.inJustDecodeBounds = true;mBgBitmap = BitmapFactory.decodeResource(content.getResources(),bgId);this.xPix = XPix;this.yPix = Ypix;this.angle = angle;}public double getAngle() {return angle;}public void setAngle(double angle) {this.angle = angle;}public int getHeight() {return mBgBitmap.getHeight();}public int getWidth() {return mBgBitmap.getWidth();}public double getxPix() {return xPix;}public void setxPix(double xPix) {this.xPix = xPix;}public double getyPix() {return yPix;}public void setyPix(double yPix) {this.yPix = yPix;}public Bitmap getmBgBitmap() {return mBgBitmap;}public void setmBgBitmap(Bitmap mBgBitmap) {this.mBgBitmap = mBgBitmap;}public void moveImageButton(){if(angle > 360){angle = 0;}xPix = RotateStage.POINTX + Math.cos(angle*ANGLENUM)*RotateStage.RADIUS;yPix = RotateStage.POINTY + Math.sin(angle*ANGLENUM)*RotateStage.RADIUS;angle += 1;}}

这个是我的演员(button)代码

其实细心的朋友就已经发现了我是不断重绘每一个view的坐标,实现这种转圈的效果,所以这个demo最关键的就是怎么来算出每个button下一帧的位置

如果你是想让一个button转圈,这个非常好实现,但是如果想让5个button沿着同一轨迹来运动画圈不那么容易,至少我是费了很多时间的

因为表演的演员的职责,所以这样的逻辑就在它自身了

xPix = RotateStage.POINTX + Math.cos(angle*ANGLENUM)*RotateStage.RADIUS;

yPix = RotateStage.POINTY + Math.sin(angle*ANGLENUM)*RotateStage.RADIUS;

angle += 1;

这里面的RotateStage.POINTX 是我计算的屏幕中心点的位置,RotateStage.RADIUS是所绕圈的半径大小

ANGLENUM也可以看到,实际上就是Math.PI/180

每次运动绘制angle会+1,就会相应的计算出新的坐标,然后舞台调用它们各自的moveImageButton方法即可

还有值得注意的是舞台中的代码:

也就是我自定义的演员的构造方法

mOneImageView = new RotateImageView(this.context,
R.drawable.ic_launcher, POINTX
+ Math.cos(0 * RotateImageView.ANGLENUM) * RADIUS,
POINTY + Math.sin(0 * RotateImageView.ANGLENUM) * RADIUS, 0);

mTwoImageView = new RotateImageView(this.context,
R.drawable.ic_launcher, POINTX
+ Math.cos(72 * RotateImageView.ANGLENUM) * RADIUS,
POINTY + Math.sin(72 * RotateImageView.ANGLENUM) * RADIUS, 72);

不一样的也就是0 , 72 了,这个我没有进行封装,如果你们需要自己改改就可以了,为什么是0和72呢,因为我是5个button,每一等分就是72,所以

也就是起始的角度,比如你是0度,你就在最右边,你是72度,你就在72度角的方向上

我这么说你们是不是已经很明白了?

再来说说怎么样触发点击事件吧,其实也要借鉴游戏里的思路了,就是计算你当前toutch的坐标是否在button内,在哪一个button内

这样做也有很多的算法,比如Region碰撞检测还有计算矩形的碰撞

我用的是后一种

@Overridepublic boolean onTouchEvent(MotionEvent event) {if(event.getX() > mOneImageView.getxPix() && event.getX() < mOneImageView.getxPix() + mOneImageView.getWidth()  && event.getY() > mOneImageView.getyPix() && event.getY() < mOneImageView.getyPix() + mOneImageView.getHeight()){Toast.makeText(this.context,"mOneImageView", 1).show();return false;}if(event.getX() > mTwoImageView.getxPix() && event.getX() < mTwoImageView.getxPix() + mTwoImageView.getWidth()&& event.getY() > mTwoImageView.getyPix() && event.getY() < mTwoImageView.getyPix() + mTwoImageView.getHeight()){Toast.makeText(this.context,"mTwoImageView", 1).show();return false;}if(event.getX() > mThreeImageView.getxPix() && event.getX() < mThreeImageView.getxPix() + mThreeImageView.getWidth()&& event.getY() > mThreeImageView.getyPix() && event.getY() < mThreeImageView.getyPix() + mThreeImageView.getHeight()){Toast.makeText(this.context,"mThreeImageView", 1).show();return false;}if(event.getX() > mFourthImageView.getxPix() && event.getX() < mFourthImageView.getxPix() + mFourthImageView.getWidth()&& event.getY() > mFourthImageView.getyPix() && event.getY() < mFourthImageView.getyPix() + mFourthImageView.getHeight()){Toast.makeText(this.context,"mFourthImageView", 1).show();return false;}if(event.getX() > mFiveImageView.getxPix() && event.getX() < mFiveImageView.getxPix() + mFiveImageView.getWidth()&& event.getY() > mFiveImageView.getyPix() && event.getY() < mFiveImageView.getyPix() + mFiveImageView.getHeight()){Toast.makeText(this.context,"mFiveImageView", 1).show();return false;}return super.onTouchEvent(event);}

其实这样做并不好,就是每次在点击的时候都有点卡,但是要解决这个问题也很好办,但是剩下的我就不说了,自己去尝试吧

附上我项目中的一张截图:

另外如果谁还有更好的一些办法请告诉我,一定感激不尽!

更多相关文章

  1. Android情侣短信软件(1)--Frame动画在悬浮窗口上的实现
  2. Android仿“守望先锋”加载动画
  3. Android(安卓)Studio录制手机屏幕并制作GIF演示动画
  4. Android(安卓)淡入淡出动画
  5. Android(安卓)自定义动画 单个View平面位移以及一组View轮回旋转
  6. 【Android的从零单排开发日记】之入门篇(十六)——Android的动画效
  7. Android(安卓)UI--ViewPager扩展Tab标签指示
  8. [置顶] android动画详解一 概述
  9. 深入源码系列:聊聊android属性动画执行线程问题(invalidate(false

随机推荐

  1. sql server不存在 sql server拒绝访问第1
  2. SQL Server口令 sql server安全性第1/2页
  3. 用SQL语句实现随机查询数据并不显示错误
  4. SQL命令大全-中英文对照第1/3页
  5. 解决MSSQL2005远程连接sql2000非默认端口
  6. MSSQL差异备份取系统权限的相关软件下载
  7. SQL Server 不删除信息重新恢复自动编号
  8. 重装MS SQL Server 2000前必须彻底删除原
  9. sql语句中如何将datetime格式的日期转换
  10. 比较详细的完美解决安装sql2000时出现以