android模拟实现航拍遥控
【android模拟实现航拍遥控】本文实例为大家分享了android模拟实现航拍遥控的具体代码,供大家参考,具体内容如下
由于最近做一个航拍项目,手机端模拟遥控,控制无人机,之前在网上这方面的知识比较少,所有就贴出来demo供大家参考,废话少说,先贴图
文章图片
左右两个点,在圈内活动,一个是控制油门,一个是控制方向,放手后会返回中心点,这些在游戏场景中经常看到,比如射击类的游戏,这里自定义view,继承ImageView,难点就在手指控制这部分,以下是源码。
package com.remotecontrol; import android.annotation.TargetApi; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Point; import android.graphics.Rect; import android.os.Build; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.view.MotionEvent; import android.view.WindowManager; import android.widget.ImageView; /** * Created by qingyuan on 2016/5/20. * 自定义view 模拟遥控器 */public class RemoteControl extends ImageView{public final String TAG="RemoteControl"; public RemoteControl(Context context) {super(context); InitData( context); }public RemoteControl(Context context, AttributeSet attrs) {super(context, attrs); InitData( context); }public RemoteControl(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr); InitData( context); }@TargetApi(Build.VERSION_CODES.LOLLIPOP)public RemoteControl(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {super(context, attrs, defStyleAttr, defStyleRes); InitData( context); }DisplayMetrics dm = new DisplayMetrics(); WindowManager manager; //屏幕的宽跟高int mDisplayWidth; int mDisplayWidth_2; //屏幕宽的1/2int mDisplayWidth_4; //屏幕宽的1/4int mDisplayWidth_43; //屏幕宽的3/4int mDisplayHeight; int mDisplayHeight_2; //屏幕高的1/2int mDisplayHeight_4; //屏幕高的1/4int mDisplayHeight_43; //屏幕高的3/4Point leftCenter; //左边中点的坐标Point rightCenter; //右边中点的坐标/********************右边的底图**************************/Bitmap btm_bg; Rect rectSrc_bg; Rect rectDst_bg; /********************左边的底图**************************/Bitmap btm_bar; Rect rectSrc_bar; Rect rectDst_bar; /********************左边的圆点**************************/Bitmap btm_circle_left; MyPoint leftPoint; double leftDistance; //距离中心点的距离double leftAngle; //atan2的角度值int leftCircle_2; //圆的一半/********************右边的圆点**************************/Bitmap btm_circle_right; MyPoint rightPoint; double rightDistance; //距离中心点的距离double rightAngle; //atan2的角度值int rightCircle_2; //圆的一半int stopRadius; //圆的半径,左右的半径是一样的Matrix matrix; //矩阵,同过改变矩阵来改变bitmap的位置final double degToRad = Math.PI/180.0; final double radToDeg = 180.0/Math.PI; public void InitData(Context context){manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); manager.getDefaultDisplay().getMetrics(dm); mDisplayWidth = dm.widthPixels; mDisplayHeight = dm.heightPixels; mDisplayWidth_2=mDisplayWidth/2; //屏幕宽的1/2mDisplayWidth_4=mDisplayWidth/4; //屏幕宽的1/4mDisplayWidth_43=mDisplayWidth*3/4; //屏幕宽的3/4mDisplayHeight_2=mDisplayHeight/2; //屏幕高的1/2mDisplayHeight_4=mDisplayHeight/4; //屏幕高的1/4mDisplayHeight_43=mDisplayHeight*3/4; //屏幕高的3/4btm_bg= BitmapFactory.decodeResource(context.getResources(),R.drawable.control_bg); btm_circle_left= BitmapFactory.decodeResource(context.getResources(),R.drawable.records); btm_circle_right= BitmapFactory.decodeResource(context.getResources(),R.drawable.help); btm_bar= BitmapFactory.decodeResource(context.getResources(),R.drawable.shift_bar_bg); matrix = new Matrix(); float scaleSize= (float) (mDisplayHeight*1.0/btm_bg.getWidth()*0.65f); //缩放为屏幕的0.65matrix.postScale(scaleSize,scaleSize); btm_bg = Bitmap.createBitmap(btm_bg,0,0,btm_bg.getWidth(),btm_bg.getHeight(),matrix,true); btm_bar = Bitmap.createBitmap(btm_bar,0,0,btm_bar.getWidth(),btm_bar.getHeight(),matrix,true); btm_circle_left = Bitmap.createBitmap(btm_circle_left,0,0,btm_circle_left.getWidth(),btm_circle_left.getHeight(),matrix,true); btm_circle_right = Bitmap.createBitmap(btm_circle_right,0,0,btm_circle_right.getWidth(),btm_circle_right.getHeight(),matrix,true); leftCircle_2=btm_circle_left.getWidth()/2; rightCircle_2=btm_circle_right.getWidth()/2; //左边中心点的位置设为leftCenter=new Point(); leftCenter.set(mDisplayWidth_4,mDisplayHeight_2); //右边中心点的位置设为rightCenter=new Point(); rightCenter.set(mDisplayWidth_43,mDisplayHeight_2); /***********************左边的地图位置***************************/rectSrc_bar=new Rect(0,0,btm_bar.getWidth(),btm_bar.getHeight()); rectDst_bar=new Rect(leftCenter.x-btm_bg.getWidth()/2,leftCenter.y-btm_bg.getHeight()/2,leftCenter.x+btm_bg.getWidth()/2,leftCenter.y+btm_bg.getHeight()/2); /***********************左边的圆点位置***************************/leftPoint=new MyPoint(leftCenter.x, leftCenter.y); /***********************右边的圆底图位置***************************/rectSrc_bg=new Rect(0,0,btm_bg.getWidth(),btm_bg.getHeight()); rectDst_bg=new Rect(rightCenter.x-btm_bar.getWidth()/2,rightCenter.y-btm_bar.getHeight()/2,rightCenter.x+btm_bar.getWidth()/2,rightCenter.y+btm_bar.getHeight()/2); /***********************右边边的圆点位置***************************/rightPoint=new MyPoint(rightCenter.x,rightCenter.y); //半径为底图的一半,这里决定了可移动圆的大小stopRadius=btm_bg.getWidth()/2; }@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas); canvas.drawBitmap(btm_bg,rectSrc_bg,rectDst_bg,null); canvas.drawBitmap(btm_bar,rectSrc_bar,rectDst_bar,null); //更新的左中心点的位置matrix.reset(); matrix.postTranslate(leftPoint.x-leftCircle_2,leftPoint.y-leftCircle_2); canvas.drawBitmap(btm_circle_left,matrix,null); //更新的右中心点的位置matrix.reset(); matrix.postTranslate(rightPoint.x-rightCircle_2,rightPoint.y-rightCircle_2); canvas.drawBitmap(btm_circle_right,matrix,null); }@TargetApi(Build.VERSION_CODES.ECLAIR)@Overridepublic boolean onTouchEvent(MotionEvent event) {float x; float y; double distance; //圆点离中心点的距离double angle; //圆点tan2的角度float x2; float y2; double angle2; double distance2; switch (MotionEvent.ACTION_MASK & event.getAction()){case MotionEvent.ACTION_DOWN://判断第一个手指按下的位置所在的区域if(Math.abs(event.getX()-rightPoint.x)>> MotionEvent.ACTION_POINTER_ID_SHIFT; //根据手指离开的id判断是开了的是哪个移动的点if(rightPoint.isCanMove() && rightPoint.getPointerIndex()==pointerId){rightPoint.setCanMove(false); //手指离开让圆点返回中心点rightPoint.x=rightCenter.x; rightPoint.y=rightCenter.y; rightPoint.setPointerIndex(-1); }if(leftPoint.isCanMove() &&leftPoint.getPointerIndex()==pointerId){leftPoint.setCanMove(false); leftPoint.x=leftCenter.x; leftPoint.y=rightCenter.y; leftPoint.setPointerIndex(-1); }break; case MotionEvent.ACTION_UP://全部手指离开之后rightPoint.setCanMove(false); rightPoint.x=rightCenter.x; rightPoint.y=rightCenter.y; rightPoint.setPointerIndex(0); leftPoint.setCanMove(false); leftPoint.x=leftCenter.x; leftPoint.y=leftCenter.y; leftPoint.setPointerIndex(0); break; case MotionEvent.ACTION_POINTER_DOWN://获取第二根手指的idpointerId = (event.getAction()&MotionEvent.ACTION_POINTER_ID_MASK)>>> MotionEvent.ACTION_POINTER_ID_SHIFT; //第二根手指按下if(!rightPoint.isCanMove() && Math.abs(event.getX(pointerId)-rightPoint.x) = stopRadius ) {distance = stopRadius; double radAngle = angle*degToRad; rightPoint.x = (int) (distance*Math.cos(radAngle))+rightCenter.x; rightPoint.y = (int) (-distance*Math.sin(radAngle))+rightCenter.y; }else{rightPoint.x= (int) event.getX(0); rightPoint.y = (int)event.getY(0); }rightDistance=distance; rightAngle=angle; }else if(leftPoint.isCanMove()){x=event.getX(0)-leftCenter.x; y=event.getY(0)-leftCenter.y; angle = (Math.atan2( x, y )*radToDeg)-90; distance = Math.sqrt((x*x)+(y*y)); if( distance >= stopRadius ) {distance = stopRadius; double radAngle = angle*degToRad; leftPoint.x = (int) (distance*Math.cos(radAngle))+leftCenter.x; leftPoint.y = (int) (-distance*Math.sin(radAngle))+leftCenter.y; }else{leftPoint.x = (int) event.getX(0); leftPoint.y = (int) event.getY(0); }}}else{//双指移动if (rightPoint.isCanMove() && rightPoint.getPointerIndex()!=-1&& rightPoint.getPointerIndex() = stopRadius ) {distance = stopRadius; double radAngle = angle*degToRad; rightPoint.x = (int) (distance*Math.cos(radAngle))+rightCenter.x; rightPoint.y = (int) (-distance*Math.sin(radAngle))+rightCenter.y; }else{rightPoint.x = (int) event.getX(rightPoint.getPointerIndex()); rightPoint.y = (int) event.getY(rightPoint.getPointerIndex()); }rightDistance=distance; rightAngle=angle; }if(leftPoint.isCanMove() && leftPoint.getPointerIndex()!=-1 && leftPoint.getPointerIndex() = stopRadius ) {distance2 = stopRadius; double radAngle = angle2*degToRad; leftPoint.x = (int) (distance2*Math.cos(radAngle))+leftCenter.x; leftPoint.y = (int) (-distance2*Math.sin(radAngle))+leftCenter.y; }else{leftPoint.x = (int) event.getX(leftPoint.getPointerIndex()); leftPoint.y = (int) event.getY(leftPoint.getPointerIndex()); }leftDistance=distance2; leftAngle=angle2; }}break; }invalidate(); return true; }public double getRightDistance() {return rightDistance; }public double getRightAngle() {return rightAngle; }public double getLeftAngle() {return leftAngle; }public double getLeftDistance() {return leftDistance; }/*** 自定义坐标点,添加了两个属性*/public class MyPoint extends Point{//手指的indexprivate int pointerIndex=-1; //是否能移动private boolean isCanMove; public boolean isCanMove() {return isCanMove; }public void setCanMove(boolean canMove) {isCanMove = canMove; }public MyPoint(int x, int y) {super(x, y); }public int getPointerIndex() {return pointerIndex; }public void setPointerIndex(int pointerIndex) {this.pointerIndex = pointerIndex; }}}
在我的真正项目中对内存性能要求比较高,所有我并没有直接用继承ImageView,而是使用了SurfaceView,双缓冲,单独线程刷新画面,还有局部刷新,基本上跟上面的差不多,只是将onDraw()里面的刷新代码放到SurfaceView中,网上也有很多SurfaceView使用的例子,稍微借鉴一下就能转过来。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。
推荐阅读
- android9叫什么名字,白猜这么多名字!谷歌Android 9.0正式发布(命名Android Pie)
- android11正式版发布时间|android11正式版发布时间,Android11正式发布 谷歌安卓11正式版上线时间
- Android编程|我的Android 进阶修炼(1)( AOSP源码根目录结构)
- Android|Android aosp10,谷歌正将Android 10源代码上传到AOSP安卓开源项目
- android11发布会,秒级推送!Android 11正式发布(一加、小米等手机将陆续更新)
- TypeScript|TypeScript 3.0 正式发布;谷歌将 AndroidX 移至 AOSP
- 安卓系统开发|搭建Android AOSP源码编译工作环境
- android|android n 发布时间,Android N 正式版将在9月发布
- Android|Android AOSP资源的下载
- Android|ubuntu16.04 编译Android AOSP源码 android10