android 虚拟摇杆绘制
首先附上效果图
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);
- }
- }
- <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>
- 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);
- }
- }
如下是代码下载地址
相关推荐
- 一条取回Android 7.0(API 24)虚拟机data/data下文件的崎岖之路
- android 动态绘制View(VideoView ,ImageView ,ViewPager。。。。。)
- Android Studio自带虚拟器访问数据库的正确使用
- Android仿华为天气绘制刻度盘
- Android Shape绘制实用圆圈
- Android中使用shape绘制空心圆
- android手机 ping 虚拟机ubuntu的ip地址
- 重翻已生灰的Android书---View绘制流程及原理
- APKAnalyser —— Android 静态虚拟分析工具
- Windows XP下用qemu虚拟ubuntu、xp、redhat、centos、redflag、fedora、debian、android
- 工作流反思——流程的需求分类
- 常用的流程引擎API开发调用接口大全-工作流引擎设计