android模拟实现航拍遥控

2022-08-17 12:12:14

本文实例为大家分享了android模拟实现航拍遥控的具体代码,供大家参考,具体内容如下由于最近做一个航拍项目,手机端模拟遥控,控制无人机,之前在网上这方面的知识比较少,所有就贴出来demo供大家参考,...

本文实例为大家分享了android模拟实现航拍遥控的具体代码,供大家参考,具体内容如下

由于最近做一个航拍项目,手机端模拟遥控,控制无人机,之前在网上这方面的知识比较少,所有就贴出来demo供大家参考,废话少说,先贴图

android模拟实现航拍遥控

左右两个点,在圈内活动,一个是控制油门,一个是控制方向,放手后会返回中心点,这些在游戏场景中经常看到,比如射击类的游戏,这里自定义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/2
  int mDisplayWidth_4;//屏幕宽的1/4
  int mDisplayWidth_43;//屏幕宽的3/4

  int mDisplayHeight;
  int mDisplayHeight_2;//屏幕高的1/2
  int mDisplayHeight_4;//屏幕高的1/4
  int mDisplayHeight_43;//屏幕高的3/4

  Point 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/2
    mDisplayWidth_4=mDisplayWidth/4;//屏幕宽的1/4
    mDisplayWidth_43=mDisplayWidth*3/4;//屏幕宽的3/4

    mDisplayHeight_2=mDisplayHeight/2;//屏幕高的1/2
    mDisplayHeight_4=mDisplayHeight/4;//屏幕高的1/4
    mDisplayHeight_43=mDisplayHeight*3/4;//屏幕高的3/4


    btm_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.65
    matrix.postScale(scaleSize,scaleSize);

    btm_bg = Bitmap.createBitmap(btm_bg,0,0,btm_bg.getWidth()js,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;

  }


  @Override
  protected 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)
  @Override
  public 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)<btm_circle_right.getWidth()
            && Math.abs(event.getY()-rightPoint.y)<btm_circle_right.getHeight())
        {
          rightPoint.setPointerIndex(0);
          rightPoint.setCanMove(true);
        }
        else if(Math.abs(event.getX()-leftPoint.x)<btm_circle_left.getWidth()
            && Math.abs(event.getY()-leftPoint.y)<btm_circle_left.getHeight())
        {
          leftPoint.setPointerIndex(0);
          leftPoint.setCanMove(true);
        }

        break;
      case MotionEvent.ACTION_POINTER_UP:

        //获取离开手指的id
        int pointerId = (event.getAction()&MotionEvent.ACTION_POINTER_ID_MASK)>>> MotionEvent.ACTION_POINTER_ID_SHIFT;

        //根据手指离开的id判断是开了的是哪个移动的点
        if(rightPoint.isCanMove() && rightPoint.getPointerIndex()==pointerId){
       rjHrkmFb   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:

        //获取第二根手指的id
        pointerId = (event.getAction()&MotionEvent.ACTION_POINTER_ID_MASK)>>> MotionEvent.ACTION_POINTER_ID_SHIFT;

        //第二根手指按下
        if(!rightPoint.isCanMove() && Math.abs(event.getX(pointerId)-rightPoint.x)<btm_circle_right.getWidth()
            && Math.abs(event.getY(pointerId)-rightPoint.y)<btm_circle_right.getHeight())
        {
          rightPoint.setPointerIndex(pointerId);
          rightPoint.setCanMove(true);
        }else if(!leftPoint.isCanMove() && Math.abs(event.getX(pointerId)-leftPoint.x)<btm_circle_left.getWidth()
            && Math.abs(event.getY(pointerId)-leftPoint.y)<btm_circle_left.getHeight())
        {
          leftPoint.setPointerIndex(pointerId);
          leftPoint.setCanMove(true);
        }

        break;
      case MotionEvent.ACTION_MOVE:

        //如果是单指移动
        if(event.getPointerCount()==1) {

          if (rightPoint.isCanMove()) {
            x=event.getX(0)-rightCenter.x;
            y=event.getY(0)-rightCenter.y;

            //计算角度,atan2的用法自己百度咯
            angle = (Math.atan2( x, y )*radToDeg)-90;
            distance = Math.sqrt((x*x)+(y*y));

            //判断是不是超出了规定的半径长度
            if( distance >= 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()<event.getPointerCount() ) {

              x=event.getX(rightPoint.getPointerIndex())-rightCenter.x;
              y=event.getY(rightPoint.getPointerIndex())-rightCenter.y;
              angle = (Math.atan2( x, y )*radToDeg)-90;
              distance = Math.sqrt((x*x)+(y*y));

              if( distance >= 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()<event.getPointerCount())
          {

            x2=event.getX(leftPoint.getPointerIndex())-leftCenter.x;
            y2=event.getY(leftPoint.getPointerIndex())-leftCenter.y;
            angle2 = (Math.atan2( x2, y2 )*radToDeg)-90;
            distance2 = Math.sqrt((x2*x2)+(y2*y2));

            if( distance2 >= stopRawww.cppcns.comdius ) {
              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{

    //手指的index
    private 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使用的例子,稍微借鉴一下就能转过来。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。