在之前A single virtual joystick development使用的圆盘和摇杆都是使用颜色来实现的,但是在实际的开发过程中,这并不美观,所有在这使用图片替换之前使用颜色的圆盘和摇杆,两者之间的区别在于,使用颜色绘制使用的是中心点作为坐标,而使用图片则使用的是左上角作为坐标,所以这里需要进行转换,同时注意的就是图片的宽度问题,里面计算的都是使用的像素,而你一开始将图片转化为bitmap的时候并不是你期望的尺寸,这里也需要转换,最后一点就是摇杆图片移动的问题,这里有两个方案,一个是改变坐标(要实现这种方法则可以使用组件显示图片,然后移动组件),第二种方法就是我现在使用的canvas绘制每次都是先清空颜色然后重新绘制的方法。
实现圆盘和摇杆功能的类---AppSingleRocker.java:
package com.seuic.singlerocker; import com.seuic.util.MathUtils; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.Point; import android.graphics.PorterDuff.Mode; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.SurfaceHolder.Callback; public class AppSingleRocker extends SurfaceView implements Callback{ private SurfaceHolder mHolder; private Paint mPaint; public Point mRockerPosition; // 摇杆位置 private Point mCtrlPoint = new Point(80, 80);// 摇杆起始位置 //private int mRudderRadius = 20;// 摇杆半径 private int mWheelRadius = 60;// 摇杆活动范围半径 int isHide = 0; private SingleRudderListener listener = null; //事件回调接口 Bitmap bitmap,bitmap2; public static final int ACTION_RUDDER = 1, ACTION_ATTACK_DEVICEMOVE = 2, ACTION_STOP = 3, ACTION_ATTACK_CAMERAMOVE = 4; public AppSingleRocker(Context context) { super(context); this.setKeepScreenOn(true); mHolder = getHolder(); mHolder.addCallback(this); mPaint = new Paint(); mPaint.setColor(Color.GREEN); mPaint.setAntiAlias(true);//抗锯齿 mRockerPosition = new Point(mCtrlPoint); setFocusable(true); setFocusableInTouchMode(true); setZOrderOnTop(true); mHolder.setFormat(PixelFormat.TRANSPARENT);//设置背景透明bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.j4); bitmap = Bitmap.createScaledBitmap(bitmap, 120, 120, false); bitmap2 = BitmapFactory.decodeResource(getResources(), R.drawable.j5); bitmap2 = Bitmap.createScaledBitmap(bitmap2, 40, 40, false);}
public AppSingleRocker(Context context, AttributeSet attribute)
{super(context, attribute);
this.setKeepScreenOn(true);
mHolder = getHolder();
mHolder.addCallback(this);
mPaint = new Paint();
mPaint.setColor(Color.GREEN);
mPaint.setAntiAlias(true);//抗锯齿
mRockerPosition = new Point(mCtrlPoint);
setFocusable(true);
setFocusableInTouchMode(true);
setZOrderOnTop(true);
mHolder.setFormat(PixelFormat.TRANSPARENT);//设置背景透明
bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.j4);
bitmap = Bitmap.createScaledBitmap(bitmap, 120, 120, false);
bitmap2 = BitmapFactory.decodeResource(getResources(), R.drawable.j5);
bitmap2 = Bitmap.createScaledBitmap(bitmap2, 40, 40, false);
}
//回调接口
public interface SingleRudderListener {
void onSteeringWheelChanged(int action,int angle);
}
//设置回调接口
public void setSingleRudderListener(SingleRudderListener rockerListener) {
listener = rockerListener;
}
int len;
@Override
public boolean onTouchEvent(MotionEvent event) {
try {
if (isHide == 0) {
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
len = MathUtils.getLength(mCtrlPoint.x, mCtrlPoint.y, event.getX(), event.getY()); //如果屏幕接触点不在摇杆挥动范围内,则不处理
if(len >mWheelRadius) {
return true;
}
break;
case MotionEvent.ACTION_MOVE:
len = MathUtils.getLength(mCtrlPoint.x, mCtrlPoint.y, event.getX(), event.getY());
if(len <= mWheelRadius) {
//如果手指在摇杆活动范围内,则摇杆处于手指触摸位置
mRockerPosition.set((int)event.getX(), (int)event.getY());
}else{
//设置摇杆位置,使其处于手指触摸方向的 摇杆活动范围边缘
mRockerPosition = MathUtils.getBorderPoint(mCtrlPoint, new Point((int)event.getX(), (int)event.getY()), mWheelRadius);
}
if(listener != null) {
float radian = MathUtils.getRadian(mCtrlPoint, new Point((int)event.getX(), (int)event.getY()));
listener.onSteeringWheelChanged(ACTION_RUDDER, getAngleCouvert(radian));
}
break;
case MotionEvent.ACTION_UP:
mRockerPosition = new Point(mCtrlPoint);
listener.onSteeringWheelChanged(ACTION_STOP, 0);
break;
}
Canvas_OK();
Thread.sleep(60);
}else {
Thread.sleep(200);
}
} catch (Exception e) {
}
return true;
}
//获取摇杆偏移角度 0-360°
private int getAngleCouvert(float radian) {
int tmp = (int)Math.round(radian/Math.PI*180);
if(tmp < 0) {
return -tmp;
}else{
return 180 + (180 - tmp);
}
}
public void surfaceCreated(SurfaceHolder holder) {
Canvas_OK();
}
public void surfaceChanged(SurfaceHolder holder, int format, int width,int height) {
}
public void surfaceDestroyed(SurfaceHolder holder) {
}
// 设置是否隐藏
public void Hided(int opt){
isHide = opt;
Canvas_OK();
}
//绘制图像public void Canvas_OK(){
Canvas canvas = null;
try {
canvas = mHolder.lockCanvas();
canvas.drawColor(Color.TRANSPARENT,Mode.CLEAR);//清除屏幕
canvas.drawBitmap(bitmap, mCtrlPoint.x - 60, mCtrlPoint.y-60, mPaint);
//这里的60px是最外围的图片的半径 canvas.drawBitmap(bitmap2, mRockerPosition.x - 20, mRockerPosition.y-20, mPaint);
//这里的20px是最里面的图片的半径
} catch (Exception e) {
e.printStackTrace();
} finally {
if(canvas != null) {
mHolder.unlockCanvasAndPost(canvas);
} }}}
主类,调用圆盘的类----SingleRocker.java
package com.seuic.singlerocker; import com.seuic.singlerocker.AppSingleRocker.SingleRudderListener; import android.os.Bundle; import android.util.Log; import android.widget.RelativeLayout; import android.app.Activity; public class SingleRocker extends Activity { RelativeLayout Parent; AppSingleRocker appSingleRocker; public static final String Main = "SingleRocker"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Parent = new RelativeLayout(this); RelativeLayout.LayoutParams RockerCanvasParams = new RelativeLayout.LayoutParams(160,160); RockerCanvasParams.addRule(RelativeLayout.CENTER_VERTICAL); RockerCanvasParams.leftMargin = 120; appSingleRocker = new AppSingleRocker(this); Parent.addView(appSingleRocker,RockerCanvasParams); setContentView(Parent); appSingleRocker.setSingleRudderListener(new SingleRudderListener() { @Override public void onSteeringWheelChanged(int action, int angle) { Log.e(Main, angle+""); } }); } }
实现的图片如下:源码连接地址如下:
http://download.csdn.net/download/jwzhangjie/5291058注:
源代码里面需要修改
在AppSingleRocker.java中将 bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.j4); bitmap2 = BitmapFactory.decodeResource(getResources(), R.drawable.j5); 替换为 bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.j4); bitmap = Bitmap.createScaledBitmap(bitmap, 120, 120, false); bitmap2 = BitmapFactory.decodeResource(getResources(), R.drawable.j5); bitmap2 = Bitmap.createScaledBitmap(bitmap2, 40, 40, false);
不然适应性不好,因为我是在华硕大平板上调试的,上面的代码是可以的,但是如果到了其他的机器就不好了,所以使用下面的代码通用性。