本人大二学生,自学安卓半年左右,第一次发博客,忘各位不喜勿喷,有什么问题欢迎指正~
前两天看了这两篇博客
《Android自定义View系列之<贪吃蛇大作战>方向操作键效果实现》http://www.jianshu.com/p/c8e4add4780a
《AndroidMatrix详解》http://blog.csdn.net/flash129/article/details/8234599
有不少感触,想继续把贪吃蛇大作战挖一挖。
建议大家先按照第一篇引文把handleView控件做出来,因为本文是在第一篇基础上继续往下做的。
先上效果图:
在 handleView 实现后
重写 imageview,基本按照第二篇引文写的,几乎没有变动
public class TransformMatrixView extends ImageView {
private Bitmap bitmap;
private Matrix matrix;
public TransformMatrixView(Context context)
{
super(context);
bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.head2);
matrix = new Matrix();
}
@Override
protected void onDraw(Canvas canvas)
{
// 画出原图像
// canvas.drawBitmap(bitmap, 0, 0, null);
// 画出变换后的图像
canvas.drawBitmap(bitmap, matrix, null);
super.onDraw(canvas);
}
@Override
public void setImageMatrix(Matrix matrix) {
this.matrix.set(matrix);
super.setImageMatrix(matrix);
}
public Bitmap getImageBitmap()
{
return bitmap;
}
}
首先在 Handleview 里新建2个全局变量:
public float xMove;
public float yMove; //用于记录,小圆和大圆中心的相对偏移 如下:
xMove = cx2 - cx;
yMove = cy2 - cy;
tanθ = xMove/yMove; //所以图像要旋转的角度与θ有关
要明白一点,屏幕当中用的坐标系和我们现实的坐标系不同,左为屏幕中的坐标系,右为实际坐标系,如图:
所以
yMove = -yMove',即 :tanθ =xMove/(-yMove);tanθ = xMove/(-yMove);然后把θ做变换反应到matrix.setRotate(θ’,width,height);
接下来引入旋转坐标系,黑色度数为旋转度数(现在流行这种左右180的分配,当然从0~360旋转也是可以的),红色为常规坐标系,如图:
按照我这种来算的话很容易发现:θ(旋转)+θ(实际)=90°
接下来讨论arctanθ,通过java中math.atan函数,有:
angel = (float) (Math.atan(xMove / (-yMove)) / Math.PI * 180);
可知 arctan
θ(angel)在1,3象限为正,2,4象限为负,但不代表它在3象限就是180°到270°之间。
要通过一定加减90°、180°换算到我们熟悉的坐标,再被90°减去得到旋转度数,这里我直接给结果:
angel = (float) (Math.atan(xMove / (-yMove)) / Math.PI * 180);
if (xMove > 0 && yMove < 0) { //第一象限
//度数正确不改变
} else if (xMove > 0 && yMove > 0) { //第四象限
angel += 180;
} else if (xMove < 0 && yMove < 0) { //第二象限
//度数正确不改变
} else if (xMove < 0 && yMove > 0) { //第三象限
angel -= 180;
}
但是!问题来了,如果 yMove=0呢?此时手指触碰的位置应该是横向!要用一个 matrix 保存 yMove为0的情况,这里方法有很多,我采用讲常规坐标顺时针旋转90°,如图:
可然后直接保存最初方向,在oncreate 方法中先将图片逆时针旋转90°,呈现正方向状态,每一次 ACTION_MOVE 都去通过读取 angel 改变图片方向,改变后的 angel 代码:
private void rotateRole(float xMove, float yMove) {
//图片处理(蛇头旋转)
if (yMove != 0) {
angel = (float) (Math.atan(xMove / (-yMove)) / Math.PI * 180);
if (xMove > 0 && yMove < 0) { //第一象限
angel -= 90; //第二次
}
else if (xMove > 0 && yMove > 0) { //第四象限
angel += 90; //第二次
}
else if (xMove < 0 && yMove < 0) { //第二象限
angel -= 90; //第二次
}
else if (xMove < 0 && yMove > 0) { //第三象限
angel = angel - 270; //第二次
}
} else {
mRole.setImageMatrix(matrixPre);
}
matrixLast.setRotate(angel, mRole.getImageBitmap().getWidth() / 2f,
mRole.getImageBitmap().getHeight() / 2f);
mRole.setImageMatrix(matrixLast);
}
HandleView类:
public class HandleView extends View {
private Paint mPaintForCircle;
private HandleReaction mHandleReaction;
public float xMove;
public float yMove;
public HandleView(Context context) {
this(context, null);
}
public HandleView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public HandleView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
private static int getDefaultSize2(int size, int measureSpec) {
int result = size;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
switch (specMode) {
case MeasureSpec.UNSPECIFIED:
result = size;
break;
case MeasureSpec.AT_MOST:
result = Math.min(size, specSize);
break;
case MeasureSpec.EXACTLY:
result = specSize;
break;
}
return result;
}
public void setHandleReaction(HandleReaction handleReaction) {
mHandleReaction = handleReaction;
}
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(getDefaultSize2(getSuggestedMinimumWidth(), widthMeasureSpec),
getDefaultSize2(getSuggestedMinimumHeight(), heightMeasureSpec));
int childWidthSize = getMeasuredWidth();
widthMeasureSpec = MeasureSpec.makeMeasureSpec(childWidthSize, MeasureSpec.EXACTLY);
heightMeasureSpec = MeasureSpec.makeMeasureSpec(childWidthSize, MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
}
@Override protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//背景透明
canvas.drawColor(Color.TRANSPARENT);
//外圆半径
int radiusOuter = getWidth() / 2; //120
//内圆半径
int radiusInner = getWidth() / 5; //48
//圆心坐标 getWidth()代表handleView这个控件的宽度 但这个不是真实的原点坐标
float cx = getWidth() / 2;
float cy = getHeight() / 2;
if (null == mPaintForCircle) {
mPaintForCircle = new Paint();
}
mPaintForCircle.setAntiAlias(true);
mPaintForCircle.setStyle(Paint.Style.FILL);
mPaintForCircle.setColor(Color.argb(0x7f, 0x11, 0x11, 0x11)); //外围圆环颜色
canvas.drawCircle(cx, cy, radiusOuter, mPaintForCircle);
//未点击的时候
if (null == mHandleReaction || null == mHandleReaction.getTouchPosition()) {
// mPaintForCircle.setColor(Color.argb(0xff, 0x11, 0x11, 0x11));
mPaintForCircle.setColor(Color.argb(190,255,255,255)); //0为透明 255为不透明
canvas.drawCircle(cx, cy, radiusInner, mPaintForCircle);
canvas.save();
return;
}
float[] touchPosition = mHandleReaction.getTouchPosition();
double ratio = (radiusOuter - radiusInner) / Math.sqrt(
Math.pow(touchPosition[0] - cx - getLeft(), 2) + Math.pow(touchPosition[1] - cy - getTop(),
2));
float cx2 = (float) (ratio * (touchPosition[0] - cx - getLeft()) + cx);
float cy2 = (float) (ratio * (touchPosition[1] - cy - getTop()) + cy);
//点击时
// mPaintForCircle.setColor(Color.argb(0xff, 0x11, 0x11, 0x11));
mPaintForCircle.setColor(Color.argb(150,255,255,255));
canvas.drawCircle(cx2, cy2, radiusInner, mPaintForCircle);
xMove = cx2 - cx; //x偏移量 与实际xy坐标无关
yMove = cy2 - cy;
canvas.save();
}
/**
* 获得用户触摸的坐标
*/
public interface HandleReaction {
float[] getTouchPosition(); //touchPostition[0][1]
}
}
TransformMatrixView类:
public class TransformMatrixView extends ImageView {
private Bitmap bitmap;
private Matrix matrix;
public TransformMatrixView(Context context)
{
super(context);
bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.head2);
matrix = new Matrix();
}
@Override
protected void onDraw(Canvas canvas)
{
canvas.drawBitmap(bitmap, matrix, null);
super.onDraw(canvas);
}
@Override
public void setImageMatrix(Matrix matrix) {
this.matrix.set(matrix);
super.setImageMatrix(matrix);}
public Bitmap getImageBitmap()
{
return bitmap;
}
}
BackgroundView类:
public class BackgroundView extends View {
public float width = 0, height = 0;
public int unit = 30;
public int rCircle = 40;
public int[][] cXY;
public int[] colors = {Color.GREEN, Color.RED, Color.CYAN,
Color.BLUE, Color.YELLOW, Color.GREEN};
private Point[] points = new Point[colors.length];
public BackgroundView(Context context) {
super(context);
}
public BackgroundView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public BackgroundView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
Paint paintC = new Paint();
paint.setColor(getResources().getColor(R.color.colorBg));
paint.setStrokeWidth(2);
paint.setStyle(Paint.Style.FILL);
paintC.setStyle(Paint.Style.FILL);
for (int i = 0; i < width / unit; i++)
for (int j = 0; j < height / unit; j++) {
canvas.drawLine(0, (j + 1) * unit,
width, (j + 1) * unit, paint);
canvas.drawLine((i + 1) * unit, 0, (i + 1) * unit,
height, paint);
}
cXY = getCircleXY();
for (int i = 0; i < points.length; i++) {
paintC.setColor(colors[i]);
canvas.drawCircle(cXY[i][0], cXY[i][1], rCircle, paintC); //圆
}
}
private int[][] getCircleXY() {
HashSet integerHashSet = new HashSet();
Random random = new Random();
int[][] circleXY = new int[colors.length][2];
int randomX, randomY;
for (int i = 0; i
MainActivity类:
public class MainActivity extends AppCompatActivity
implements HandleView.HandleReaction, View.OnTouchListener {
private float[] mTouchPosition = null;
private HandleView mHandleView;
private BackgroundView backgroundView;
private TransformMatrixView mRole;
private Matrix matrixPre, matrixLast;
float angel = 0f;
int width, height;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
WindowManager wm = this.getWindowManager();
width = wm.getDefaultDisplay().getWidth();
height = wm.getDefaultDisplay().getHeight();
FrameLayout frameLayout = (FrameLayout) findViewById(R.id.frameLayout);
frameLayout.setOnTouchListener(this); //对整个界面这是touch监听 保证点所有位置都可以反应
mHandleView = (HandleView) findViewById(R.id.handleView);
mHandleView.setHandleReaction(this);
backgroundView = (BackgroundView) findViewById(R.id.backgroundView);
backgroundView.width = width;
backgroundView.height = height;
mRole = new TransformMatrixView(this);
mRole.setX(width / 2 - mRole.getImageBitmap().getWidth() / 2f);
mRole.setY(height / 2 - mRole.getImageBitmap().getHeight() / 2f);
mRole.setScaleType(ImageView.ScaleType.MATRIX);
matrixPre = new Matrix();
matrixLast = new Matrix();
matrixPre = mRole.getMatrix();
matrixLast.setRotate(-90, mRole.getImageBitmap().getWidth() / 2f,
mRole.getImageBitmap().getHeight() / 2f);
mRole.setImageMatrix(matrixLast);
frameLayout.addView(mRole);
// Log.d("test", String.valueOf(Math.atan(1.0)/Math.PI * 180));
}
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
switch (motionEvent.getAction()) {
case MotionEvent.ACTION_DOWN: {
mTouchPosition = new float[2];
mTouchPosition[0] = motionEvent.getX();
mTouchPosition[1] = motionEvent.getY();
rotateRole(mHandleView.xMove, mHandleView.yMove);
mHandleView.invalidate();
return true;
}
case MotionEvent.ACTION_MOVE: {
mTouchPosition[0] = motionEvent.getX();
mTouchPosition[1] = motionEvent.getY();
rotateRole(mHandleView.xMove, mHandleView.yMove);
Log.d("roleX", String.valueOf(mRole.getX()));
Log.d("roleY", String.valueOf(mRole.getY()));
mHandleView.invalidate();
return true;
}
case MotionEvent.ACTION_UP: {
mTouchPosition = null;
mHandleView.invalidate();
return true;
}
}
return true;
}
@Override
public float[] getTouchPosition() {
return mTouchPosition;
}
private void rotateRole(float xMove, float yMove) {
//图片处理(蛇头旋转)
if (yMove != 0) {
angel = (float) (Math.atan(xMove / (-yMove)) / Math.PI * 180);
if (xMove > 0 && yMove < 0) { //第一象限
angel -= 90;
} else if (xMove > 0 && yMove > 0) { //第四象限
// angel += 180;
angel += 90;
} else if (xMove < 0 && yMove < 0) { //第二象限
angel -= 90;
} else if (xMove < 0 && yMove > 0) { //第三象限
// angel = angel - 180;
angel = angel - 270;
}
} else {
mRole.setImageMatrix(matrixPre);
}
matrixLast.setRotate(angel, mRole.getImageBitmap().getWidth() / 2f,
mRole.getImageBitmap().getHeight() / 2f);
mRole.setImageMatrix(matrixLast);
}
}
XML: