android 虚拟摇杆绘制

原创 2015年11月19日 11:39:24

首先附上效果图


1、自定义RockerView

package com.example.rocker;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.PointF;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.ViewTreeObserver.OnPreDrawListener;

public class RockerView extends View {

	//固定摇杆背景圆形的X,Y坐标以及半径
	private float mRockerBg_X;
	private float mRockerBg_Y;
	private float mRockerBg_R;
	//摇杆的X,Y坐标以及摇杆的半径
	private float mRockerBtn_X;
	private float mRockerBtn_Y;
	private float mRockerBtn_R;
	private Bitmap mBmpRockerBg;
	private Bitmap mBmpRockerBtn;
	
	private PointF mCenterPoint;
	
	public RockerView(Context context, AttributeSet attrs) {
		super(context, attrs);
		// TODO Auto-generated constructor stub
		// 获取bitmap
		mBmpRockerBg = BitmapFactory.decodeResource(context.getResources(), R.drawable.rocker_bg);
		mBmpRockerBtn = BitmapFactory.decodeResource(context.getResources(), R.drawable.rocker_btn);
		
		getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
			
			// 调用该方法时可以获取view实际的宽getWidth()和高getHeight()
			@Override
			public boolean onPreDraw() {
				// TODO Auto-generated method stub
				getViewTreeObserver().removeOnPreDrawListener(this); 
				
				Log.e("RockerView", getWidth() + "/" +  getHeight());
				mCenterPoint = new PointF(getWidth() / 2, getHeight() / 2);
				mRockerBg_X = mCenterPoint.x;
				mRockerBg_Y = mCenterPoint.y;
				
				mRockerBtn_X = mCenterPoint.x;
				mRockerBtn_Y = mCenterPoint.y;
				
				float tmp_f = mBmpRockerBg.getWidth() / (float)(mBmpRockerBg.getWidth() + mBmpRockerBtn.getWidth());
				mRockerBg_R = tmp_f * getWidth() / 2;
				mRockerBtn_R = (1.0f - tmp_f)* getWidth() / 2;
				
				return true;
			}
		});
	
		
		new Thread(new Runnable() {
			
			@Override
			public void run() {
				// TODO Auto-generated method stub
				while(true){
					
					//系统调用onDraw方法刷新画面
					RockerView.this.postInvalidate();
					
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
		}).start();
	}
	
	@Override
	protected void onDraw(Canvas canvas) {
		// TODO Auto-generated method stub
		super.onDraw(canvas);
		canvas.drawBitmap(mBmpRockerBg, null, 
				new Rect((int)(mRockerBg_X - mRockerBg_R), 
						(int)(mRockerBg_Y - mRockerBg_R), 
						(int)(mRockerBg_X + mRockerBg_R), 
						(int)(mRockerBg_Y + mRockerBg_R)), 
				null);
		canvas.drawBitmap(mBmpRockerBtn, null, 
				new Rect((int)(mRockerBtn_X - mRockerBtn_R), 
						(int)(mRockerBtn_Y - mRockerBtn_R), 
						(int)(mRockerBtn_X + mRockerBtn_R), 
						(int)(mRockerBtn_Y + mRockerBtn_R)), 
				null);
	}
	
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		// TODO Auto-generated method stub
		if (event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_MOVE) {
			// 当触屏区域不在活动范围内
			if (Math.sqrt(Math.pow((mRockerBg_X - (int) event.getX()), 2) + Math.pow((mRockerBg_Y - (int) event.getY()), 2)) >= mRockerBg_R) {
				//得到摇杆与触屏点所形成的角度
				double tempRad = getRad(mRockerBg_X, mRockerBg_Y, event.getX(), event.getY());
				//保证内部小圆运动的长度限制
				getXY(mRockerBg_X, mRockerBg_Y, mRockerBg_R, tempRad);
			} else {//如果小球中心点小于活动区域则随着用户触屏点移动即可
				mRockerBtn_X = (int) event.getX();
				mRockerBtn_Y = (int) event.getY();
			}
			if(mRockerChangeListener != null) {
				mRockerChangeListener.report(mRockerBtn_X - mCenterPoint.x, mRockerBtn_Y - mCenterPoint.y);
			}
		} else if (event.getAction() == MotionEvent.ACTION_UP) {
			//当释放按键时摇杆要恢复摇杆的位置为初始位置
			mRockerBtn_X = mCenterPoint.x;
			mRockerBtn_Y = mCenterPoint.y;
			if(mRockerChangeListener != null) {
				mRockerChangeListener.report(0, 0);
			}
		}
		return true;
	}
	
	/***
	 * 得到两点之间的弧度
	 */
	public double getRad(float px1, float py1, float px2, float py2) {
		//得到两点X的距离
		float x = px2 - px1;
		//得到两点Y的距离
		float y = py1 - py2;
		//算出斜边长
		float xie = (float) Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
		//得到这个角度的余弦值(通过三角函数中的定理 :邻边/斜边=角度余弦值)
		float cosAngle = x / xie;
		//通过反余弦定理获取到其角度的弧度
		float rad = (float) Math.acos(cosAngle);
		//注意:当触屏的位置Y坐标<摇杆的Y坐标我们要取反值-0~-180
		if (py2 < py1) {
			rad = -rad;
		}
		return rad;
	}
	
	/**
	 * 
	 * @param R  圆周运动的旋转点
	 * @param centerX 旋转点X
	 * @param centerY 旋转点Y
	 * @param rad 旋转的弧度
	 */
	public void getXY(float centerX, float centerY, float R, double rad) {
		//获取圆周运动的X坐标 
		mRockerBtn_X = (float) (R * Math.cos(rad)) + centerX;
		//获取圆周运动的Y坐标
		mRockerBtn_Y = (float) (R * Math.sin(rad)) + centerY;
	}
	
	RockerChangeListener mRockerChangeListener = null;
	public void setRockerChangeListener(RockerChangeListener rockerChangeListener) {
		mRockerChangeListener = rockerChangeListener;
	}
	public interface RockerChangeListener {
		public void report(float x, float y);
	}
}
2、布局文件中添加RockerView

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ff4f4f4f"
    tools:context=".MainActivity" >

    <com.example.rocker.RockerView 
        android:id="@+id/rockerView1"
        android:layout_width="120dp"
        android:layout_height="120dp"
        android:layout_alignParentBottom="true"
        android:layout_marginLeft="20dp"
        android:layout_marginBottom="20dp"/>
    
	<com.example.rocker.RockerView 
        android:id="@+id/rockerView2"
        android:layout_width="120dp"
        android:layout_height="120dp"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:layout_marginRight="20dp"
        android:layout_marginBottom="20dp"/>

</RelativeLayout>


3、MainActiviy中使用RockerView

package com.example.rocker;

import android.app.Activity;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup.MarginLayoutParams;
import android.view.Window;
import android.view.WindowManager;
import android.widget.RelativeLayout;

public class MainActivity extends Activity {

	private static final String TAG = "MainActivity";

	void doLog(String log) {
		Log.e(TAG, log);
	}

	private RockerView rockerView1;
	private RockerView rockerView2;
	int screenWidth;
	int screenHeight;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		getWindow().setFlags(
				WindowManager.LayoutParams.FLAG_FULLSCREEN
						| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,
				WindowManager.LayoutParams.FLAG_FULLSCREEN
						| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);// 设置全屏
																			// ,
																			// 屏幕长亮
		setContentView(R.layout.activity_main);

		DisplayMetrics dm = getResources().getDisplayMetrics();
		screenWidth = dm.widthPixels;
		screenHeight = dm.heightPixels;

		rockerView1 = (RockerView) findViewById(R.id.rockerView1);
		rockerView2 = (RockerView) findViewById(R.id.rockerView2);

		rockerView1.setRockerChangeListener(new RockerView.RockerChangeListener() {

					@Override
					public void report(float x, float y) {
						// TODO Auto-generated method stub
						// doLog(x + "/" + y);
						setLayout(rockerView2, (int)x, (int)y);
					}
				});

		rockerView2.setRockerChangeListener(new RockerView.RockerChangeListener() {

					@Override
					public void report(float x, float y) {
						// TODO Auto-generated method stub
						// doLog(x + "/" + y);
						setLayout(rockerView1, (int)x, (int)y);
					}
				});
	}

	public void setLayout(View v, int dx, int dy) {
		int left = v.getLeft() + dx;
		int top = v.getTop() + dy;
		int right = v.getRight() + dx;
		int bottom = v.getBottom() + dy;
		if (left < 0) {
			left = 0;
			right = left + v.getWidth();
		}
		if (right > screenWidth) {
			right = screenWidth;
			left = right - v.getWidth();
		}
		if (top < 0) {
			top = 0;
			bottom = top + v.getHeight();
		}
		if (bottom > screenHeight) {
			bottom = screenHeight;
			top = bottom - v.getHeight();
		}
		v.layout(left, top, right, bottom);
	}
}

如下是代码下载地址

http://download.csdn.net/detail/qwjun/9282127



版权声明:本文为博主原创文章,未经博主允许不得转载。 举报

相关文章推荐

QT 模仿Android游戏中虚拟摇杆(3)让圆随着角度移动

接着上一篇讲起,我们需要在鼠标离开圆的范围的时候,让圆跟着鼠标与圆心的角度移动,那么我们来看看我们的已知量是什么: 1、圆心坐标 2、圆的半径 3、当前鼠标的坐标 运用一下我们的中学知识,根据...

Android自定义摇杆实现蓝牙控制小车

1、概述 1.1 背景 本文继《Android通过蓝牙HC06与Arduino通信实例》一文进行UI设计,考虑到四方向按键操作智能小车的体验性,不如做一个摇杆来控制来得好。 1.2 需求 1)控制摇...

我是如何成为一名python大咖的?

人生苦短,都说必须python,那么我分享下我是如何从小白成为Python资深开发者的吧。2014年我大学刚毕业..

android模拟摇杆绘制

[java] view plaincopyprint? package com.rp;      import android.graphics.Canvas;   impor...

QT 模仿Android游戏中虚拟摇杆(2)限定摇杆拖动范围

此篇博客介绍了如何限定虚拟摇杆在一个圆中移动

教你一步步实现一个虚拟摇杆

各位朋友,大家好,我是秦元培,欢迎大家关注我的博客,我的博客地址是http://qinyuanpei.com。最近因为项目需要决定尝试自己来实现一个虚拟摇杆,所以在今天的文章中我们的目标是使用uGUI...
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)