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/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(),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){
                    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 >= 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{

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

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

(0)

相关推荐

  • Android 8.0实现蓝牙遥控器自动配对

    本文要实现的是在 android 8.0 的平台上,蓝牙遥控器与TV自动配对,具体就是在TV端打开配对界面,TV端开始搜索远程蓝牙设备,按下遥控器按键让蓝牙遥控器进入对码模式,此时蓝牙遥控器就能作为一个远程蓝牙设备被发现,TV端扫描到这个远程蓝牙设备(蓝牙遥控器),就会自动进行配对连接. 话不多说,直接上代码分析. public class RcConnectActivity extends Activity {         private static final String TAG =

  • Android编程调用红外线遥控功能示例

    本文实例讲述了Android编程调用红外线遥控功能.分享给大家供大家参考,具体如下: Android API Demos中有红外线遥控的小例子,在网上找了很久相关的资料,发现比较少,或许找的方法不对. Github上有一个与之相关的开源项目https://github.com/timnew/AndroidInfrared,还没来得及学习.希望有相关资料或学习项目的大神们多指导 . /** * Android红外线遥控官方Demo * * @description: * @author ldm *

  • Android自定义View实现遥控器按钮

    本文实例为大家分享了Android自定义View实现遥控器按钮的具体代码,供大家参考,具体内容如下 效果图: 原理: onSizeChanged拿到控件宽高,进行path和region的计算(此处,path和region的坐标值都是以viewWidth/2,viewHeight/2为坐标原点进行计算的) 画布平移,绘制5个path 点击事件,判断是否处于相应的region区域内,进行控件的重绘 点击事件motionEvent的原始坐标(getX和getY),是以viewParent的左上角为坐标

  • android模拟实现航拍遥控

    本文实例为大家分享了android模拟实现航拍遥控的具体代码,供大家参考,具体内容如下 由于最近做一个航拍项目,手机端模拟遥控,控制无人机,之前在网上这方面的知识比较少,所有就贴出来demo供大家参考,废话少说,先贴图 左右两个点,在圈内活动,一个是控制油门,一个是控制方向,放手后会返回中心点,这些在游戏场景中经常看到,比如射击类的游戏,这里自定义view,继承ImageView,难点就在手指控制这部分,以下是源码. package com.remotecontrol; import andro

  • Android 模拟新闻APP显示界面滑动优化实例代码

    内容: 1.滑动优化(滑动时不加载图片,停止才加载) 2.第一次进入时手动加载 代码如下: 1.界面布局 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:

  • Android模拟强制下线通知功能实例代码

    package com.itheima74.broadcastbestpractice; import android.content.Intent; import android.os.Bundle; import android.os.SystemClock; import android.support.v4.content.LocalBroadcastManager; import android.view.View; /** * 模拟强制下线通知 * 1.登录成功后10秒发送一条本地自

  • Android模拟用户点击的实现方法

    前言 Android模拟用户点击.在自动化测试中可使用的工具. 可以利用adb命令,也可以使用Android SDK中的monkeyrunner工具. win7-64 gitbash 使用adb命令 主要使用input命令 usage: input ... input text <string> input keyevent <key code number or name> input tap <x> <y> input swipe <x1>

  • Android模拟实现滑动解锁界面

    本文实例为大家分享了Android模拟滑动解锁界面,供大家参考,具体内容如下 实现逻辑 自定义一个view继承view类,实现里面的方法 在构造方法中加载出图片资源.在onMeasure中获取背景的宽和高作为自定义控件的宽和高 在onDraw方法中绘制出滑块,在控件的布局文件中设置控件的背景图片 设置滑块的触摸事件,分别算出当手指按下屏幕.移动,离开屏幕时滑块的位置 在移动的过程中,对滑块的位置进行限定,使滑块的位置不能超过指定的区域 在手指离开屏幕的事件中判定手指的位置,如果滑块没有到达最右边

  • Android模拟实现华为系统升级进度条

    目录 前言 实现步骤 1.用DashPathEffect给paint加上虚线效果 2.画出进度条 3.绘制文字 4.加入动画效果 完整代码 前言 之前用华为Android系统的时候总是会想到这种虚线进度条是怎么实现的,因为直接用canvas的drawArc方法画出来的是实线,所以最近在网上搜了很多进度条相关的文章,也了解到了其中的原理,下面分享给大家.下面这两篇文章是我之前写的Android进度条相关的文章,有兴趣的朋友们可以看看: Android实现绚丽的自定义进度条 详解Android如何自

  • Android模拟美团客户端进度提示框

    用过美团客户端的朋友都知道,美团的加载等待提示很有意思,是一种动画的形式展现给我们,下面我们就对这背后的原理进行了解,然后实现自己的等待动画效果. 首先我们准备两张图片: 这两张图片看起来一模一样啊?细心的朋友会发现唯一不同的就在脚部,OK,我们就利用这两张图片的轮换播放实现动画效果,下面看一下代码: 1.动画文件frame_meituan.xml: <?xml version="1.0" encoding="utf-8"?> <animation

  • Android模拟实现网易新闻客户端

    首先我们先看一下要模拟的界面 我们主要实现的就是ListView解析json文件中的数据,UI布局很简单不做赘述. 这里我们需要一个服务器来实现数据的动态更新, 这里我们用到的是Tomcat8.0. 首先我们把需要解析的json文件放置到Tomcat的webapp文件下的ROOT里面,方便我们解析. 首先我们创建一个JsonParse类用来解析json文件: package cn.edu.bzu.myapplication.Tools; import com.google.gson.Gson;

  • Android模拟登录评论CSDN实现代码

    有时候作为非官方开发的APP集成了官方的所有信息,但是现在需要实现另一个功能那就是登录发表评论到官方的网站,而非官方的APP并不知道官方网站是怎么实现登录与评论的,而且越大型的网站,为了防止这样的事情发生,增加了许许多多阻碍,不过我们这里可以给大家提供一个通用的方式,就是有点费时,不过按照此方法,基本所有的网站都不在话下.今天就拿CSDN做一下试验. 1.登录CSDN 查看其源代码看看其form表单: 其难点在post data数据中it的value与execution的value,其为随机产生

  • 浅析Android 模拟键盘鼠标事件

    通过Socket + Instrumentation实现模拟键盘鼠标事件主要通过以下三个部分组成:Socket编程:实现PC和Emulator通讯,并进行循环监听Service服务:将Socket的监听程序放在Service中,从而达到后台运行的目的.这里要说明的是启动服务有两种方式,bindService和startService,两者的区别是,前者会使启动的Service随着启动Service的Activity的消亡而消亡,而startService则不会这样,除非显式调用stopServi

随机推荐