【Android 车载 App】实现座椅调节控制十字指针的效果

news2024/11/19 0:52:36

【Android 车载 App】实现座椅调节控制十字指针的效果

  • 效果展示
  • 实现方法
    • 思路
    • 代码
      • 第一步,画两条十字虚线
      • 第二步,在每个虚线的末端画出圆角三角形
      • 第三步,在十字虚线的中间位置画出两个同心圆,一个填充内容,一个描边
      • 第四步,复写onTouchEvent方法,实现同心圆的移动逻辑
  • 代码链接

效果展示

在这里插入图片描述

实现方法

思路

  1. 第一步,画两条十字虚线
  2. 第二步,在每个虚线的末端画出圆角三角形
  3. 第三步,在十字虚线的中间位置画出两个同心圆,一个填充内容,一个描边
  4. 第四步,复写onTouchEvent方法,实现同心圆的移动逻辑

代码

第一步,画两条十字虚线

初始化画笔

        PathEffect pathEffect = new DashPathEffect(new float[]{10f,10f}, 1);
        linePaint.setStyle(Paint.Style.STROKE);
        linePaint.setStrokeWidth(5f);
        linePaint.setColor(Color.GRAY);
        linePaint.setPathEffect(pathEffect);

在onDraw方法中使用画笔,画出两条十字虚线

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        canvas.drawLine(30,getHeight()/2, getWidth()-30,getHeight()/2, linePaint);
        canvas.drawLine(getWidth()/2, 30, getWidth()/2, getHeight()-30, linePaint);
    }

第二步,在每个虚线的末端画出圆角三角形

画三角形需要用到Path的相关知识(这部分内容请同学们自行百度),声明及Path的初始化如下:

	Path upTrianglePath = new Path();
	Path downTrianglePath = new Path();
	Path leftTrianglePath = new Path();
	Path rightTrianglePath = new Path();

    private Path getTrianglePath(int direction) {
        initTrianglePath();
        switch (direction) {
            case 0://return upTrianglePath;
            case 1: // 下
                return downTrianglePath;
            case 2: // 左
                return leftTrianglePath;
            case 3: // 右
                return rightTrianglePath;
            default:
                break;
        }
        return upTrianglePath;
    }

   private void initTrianglePath() {
        upTrianglePath.moveTo(getWidth()/2, 0);
        upTrianglePath.lineTo(getWidth()/2 - 30, 52);
        upTrianglePath.lineTo(getWidth()/2 + 30, 52);
        upTrianglePath.close();

        downTrianglePath.moveTo(getWidth()/2, getHeight());
        downTrianglePath.lineTo(getWidth()/2 - 30, getHeight() - 52);
        downTrianglePath.lineTo(getWidth()/2 + 30, getHeight() - 52);
        downTrianglePath.close();

        leftTrianglePath.moveTo(0, getHeight()/2);
        leftTrianglePath.lineTo(52, getHeight()/2 + 30);
        leftTrianglePath.lineTo(52, getHeight()/2 - 30);
        leftTrianglePath.close();

        rightTrianglePath.moveTo(getWidth(), getHeight()/2);
        rightTrianglePath.lineTo(getWidth() - 52, getHeight()/2 + 30);
        rightTrianglePath.lineTo(getWidth() - 52, getHeight()/2 - 30);
        rightTrianglePath.close();
    }

除了使用 Path 之外,因为我们需要画出圆角三角形,所以还需要对 Paint 对象的 PathEffect 做一下设置:

    private void initPaint() {
//...
        trianglePaint.setStyle(Paint.Style.FILL);
        trianglePaint.setColor(Color.GRAY);
        float radius = 10f;
        CornerPathEffect corEffect = new CornerPathEffect(radius);
        trianglePaint.setPathEffect(corEffect);
//...
    }

然后在 onDraw 方法中画出四个顶点位置的三角形:

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
		//....
        canvas.drawPath(getTrianglePath(0), trianglePaint);
        canvas.drawPath(getTrianglePath(1), trianglePaint);
        canvas.drawPath(getTrianglePath(2), trianglePaint);
        canvas.drawPath(getTrianglePath(3), trianglePaint);
		//....
    }

第三步,在十字虚线的中间位置画出两个同心圆,一个填充内容,一个描边

画圆只需要使用canvas.drawCircle方法即可,但是由于两个圆一个需要填充内容,一个需要描边,所以我们使用两个Paint对象来分别实现对应的效果。
声明Paint对象:

    Paint circlePaint1 = new Paint();
    Paint circlePaint2 = new Paint();
    
    private void initPaint() {
		// ...
        circlePaint1.setStyle(Paint.Style.FILL);// 填充内容
        circlePaint1.setColor(Color.GRAY);
        circlePaint2.setStyle(Paint.Style.STROKE); // 描边
        circlePaint2.setStrokeWidth(14);
        circlePaint2.setColor(Color.GRAY);
    }

然后在 onDraw 方法中画出中心的两个同心圆:

    @Override
    protected void onDraw(Canvas canvas) {
        // ...
        canvas.drawCircle(getCircleX(), getCircleY(), 20, circlePaint1);
        canvas.drawCircle(getCircleX(), getCircleY(), 48, circlePaint2);

    }

第四步,复写onTouchEvent方法,实现同心圆的移动逻辑

复写onTouchEvent方法前,需要先设置clickabletrue,否则我们的View只能接收到 ACTION_DOWN 事件,无法接收到其他事件。

    public SeatAdaptionView(Context context, @Nullable AttributeSet attrs) {
//...
        setClickable(true);
    }

然后复写 onTouchEvent 方法,实现同心圆的移动逻辑,实现的思路是:

  1. ACTION_DOWN 时记录初始触摸点
  2. ACTION_MOVE 时计算X轴与Y轴的偏移值 deltaXdeltaY,比较二者绝对值大小,根据比较结果设定滑动方向。deltaX大,则延X轴滑动,deltaY大则延Y轴滑动。
  3. 根据 deltaX(或deltaY)的值,改变圆心位置,并执行重绘。
  4. ACTION_UP时,恢复到初始状态。
    @Override
    public boolean onTouchEvent(MotionEvent event) {

        int action = event.getAction();

        switch(action) {
            case MotionEvent.ACTION_DOWN:
	            // 1.记录初始触摸点
                touchX = event.getX();
                touchY = event.getY();
                lastX = event.getX();
                lastY = event.getY();
                break;
            case MotionEvent.ACTION_MOVE:
            	// 2.计算X轴与Y轴的偏移值 `deltaX` 与 `deltaY`
                touchX = event.getX();
                touchY = event.getY();
                float deltaX = lastX - touchX;
                float deltaY = lastY - touchY;
                if (moveDirection == -1) {
                	// 比较二者绝对值大小,根据比较结果设定滑动方向。`deltaX`大,则延X轴滑动,`deltaY`大则延Y轴滑动。
                    if (Math.abs(deltaX) >= Math.abs(deltaY)) {
                        moveDirection = 0;
                    } else {
                        moveDirection = 1;
                    }
                } else if (moveDirection == 0) {
                    // 水平方向移动
                    mDeltaX = deltaX;
                    // 3.根据 `deltaX`(或`deltaY`)的值,改变圆心位置,并执行重绘。
                    invalidate();
                } else {
                    // 垂直方向移动
                    mDeltaY = deltaY;
                    // 根据 `deltaX`(或`deltaY`)的值,改变圆心位置,并执行重绘。
                    invalidate();
                }

                break;
            case MotionEvent.ACTION_UP:
            	// 4.恢复到初始状态。
                touchX = -1;
                touchY = -1;
                moveDirection = -1;
                mDeltaX = 0;
                mDeltaY = 0;
                invalidate();
                break;
            default:
                break;
        }

        Log.d("SeatAdaptionView", "onTouchEvent: Action = " + event.getAction() + " touchX = " + touchX + " touchY = " + touchY);

        return super.onTouchEvent(event);
    }

代码链接

代码链接(github)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/148070.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一款新兴的操作pcap的神器

一 前言有机会接触到这款软件,还是同事的一个图,图介绍了开源项目Zed和基于Zed做的一款全流量安全产品Brim。整个产品其实是不少开源项目的一个小集成,只所以感兴趣,除了brim在github有1.5k个star的原因外,更吸引我的是…

缓存的数据一致性

文章目录1.先更新缓存,再更新DB2.先更新DB,再更新缓存3.先删除缓存,后更新DB4.先更新DB,后删除缓存 (推荐)前言: 只要使用到缓存,无论是本地内存做缓存还是使用 redis 做缓存&#…

Neo4j网页服务器端口Cypher操作直接创建知识图谱

案例1:创建新节点、关系 CREATE (n:美国企业家{name:马斯克}) MERGE (n) <-[:主公]- (n1:总统{name:拜登}) RETURN *创建其他节点的时候,可以一次输入:例如 CREATE

代码随想录day32

第32天 前言 终于到周六了&#xff0c;明天可以休息了&#xff0c;哈哈哈 122. 买卖股票的最佳时机 II 题目 给定一个数组&#xff0c;它的第 i 个元素是一支给定股票第 i 天的价格。 设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易&#xff08;多…

DenseNet详解

入门小菜鸟&#xff0c;希望像做笔记记录自己学的东西&#xff0c;也希望能帮助到同样入门的人&#xff0c;更希望大佬们帮忙纠错啦~侵权立删。 ✨完整代码在我的github上&#xff0c;有需要的朋友可以康康✨ https://github.com/tt-s-t/Deep-Learning.git 目录 一、DenseNet网…

深度学习——语言模型(笔记)

语言模型&#xff1a;NLP经典的模型 1.语言模型 ①长度为T的文本序列中词元依次是x1,…,xT&#xff0c;xT被认为是文本序列在时间t处的观测或标签。在给定文本序列&#xff0c;语言模型的目标是估计序列的联合概率p(x1,…,xT) ②序列模型的核心是整个序列文本所出现的概率 应…

国家基础地理信息中心行政边界等矢量数据免费下载保姆级教程--关于地理数据收集与处理的基本工具推荐(7)

关于地理数据收集与处理的基本工具推荐系列&#xff0c;有导航&#xff0c;不迷路&#xff1a; 关于地理数据收集与处理的基本工具推荐(1) —高分辨率卫星影像数据免费下载方式关于地理数据收集与处理的基本工具推荐(2)—10m精度的全球土地覆盖数据下载关于地理数据收集与处理…

勿忘2022,迎接2023

2022真的可以说是很不平凡的一年&#xff0c;很多想做的事情也因为一些原因没有做成。不过2022年已经过去&#xff0c;一年一度的总结还是要来写的。废话不多说&#xff0c;还是定关键词。2017年是“小确幸”和“在路上”&#xff0c;感谢师兄师姐的帮助&#xff0c;接触了很多…

write和fwrite

如果只是普通地以O_RDWR的flag去open一个文件朝里write&#xff08;不考虑创建、扩增&#xff09;&#xff0c;那默认内核会把文件的这个页面读进来缓存在内核里的&#xff0c;也即所谓的page cache。随后再发起新的write syscall写相同的页面时&#xff0c;只要写在page cache…

【博学谷学习记录超强总结,用心分享|产品经理基础总结和感悟13】

这里写目录标题第一章、概述第二章&#xff0c;内容服务产品分析框架&#xff1a;用户-平台-创作者内容服务平台优化思考第一章、概述 在分析文字类内容产品之前&#xff0c;我们先来思考一下内容产品的本质是什么&#xff1f;笔者认为&#xff0c;所有满足用户需求的信息服务…

aws beanstalk 使用docker平台部署beanstalk应用程序

参考资料 使用 Docker 平台分支 之前的文章分享过如何使用eb cli工具创建application和eb环境&#xff0c;本文介绍beanstalk支持的docker容器部署 关于beanstalk环境创建相关的资源和部署逻辑&#xff0c;参考之前的文章《aws beanstalk 使用eb cli配置和启动环境》 $ eb …

指南帮手——协议栈

通过 DNS 获取到 IP 后&#xff0c;就可以把 HTTP 的传输工作交给操作系统中的协议栈。协议栈的内部分为几个部分&#xff0c;分别承担不同的工作。上下关系是有一定的规则的&#xff0c;上面的部分会向下面的部分委托工作&#xff0c;下面的部分收到委托的工作并执行。应用程序…

PyTorch源码编译(windows)

1.打开pytorch源码仓库: https://github.com/pytorch/pytorch#from-source2.PyTorch用途与安装方法:3.Python与编译器版本要求 (Python3.7或者更高,编译器要求支持C17)4.如果要支持CUDA编程,要安装NVIDIA CUDA 11或者更高版本, 安装NVIDIA cuDNN v7或者更高版本注:CUDA不支持Ma…

使用 Flask 快速部署 PyTorch 模型

对于数据科学项目来说&#xff0c;我们一直都很关注模型的训练和表现&#xff0c;但是在实际工作中如何启动和运行我们的模型是模型上线的最后一步也是最重要的工作。 今天我将通过一个简单的案例&#xff1a;部署一个PyTorch图像分类模型&#xff0c;介绍这个最重要的步骤。 …

用一串Python代码爬取网站数据

如觉得博主文章写的不错或对你有所帮助的话&#xff0c;还望大家多多支持呀&#xff01;关注、点赞、收藏、评论。 目录一.编码问题二、文件编码三、基本方法四、登录五、断线重连六、正则匹配Excel操作转换网页特殊字符一.编码问题 因为涉及到中文&#xff0c;所以必然地涉及…

MV*系列架构模型

下文仅代表个人理解&#xff0c;可能会有偏差或错误&#xff0c;欢迎评论或私信讨论。 MVC 从软件架构模型角度 MVC 是比较“古老”的架构模型&#xff0c;后面的 MV* 都是基于它进行拓展。MVC 出现的意义是为了提高程序的可维护性与拓展性。在 View 层与 Model 层中添加了 C…

如何分享让人眼前一亮的代码

作为一名软件工程师&#xff0c;会经常需要在工作和写作中粘贴代码片段以作示例&#xff0c;如果不关注代码的格式随手一粘&#xff0c;别人看到的画风就可能是这样&#xff1a;那么&#xff0c;该如何才能快速且优雅地分享代码片段呢&#xff1f;Raycast ray.so 或许是一个值…

2020-12-31 学习74HC595真值表与时序图

考资料教你74hc595时序图怎么看知识详解 - 电子常识 - 电子发烧友网 74HC595是串行输入并行/串行输出的移位锁存器。SHCP是移位脉冲&#xff0c;前沿&#xff08;上升沿&#xff09;有效&#xff0c;STCP是锁存脉冲&#xff0c;前沿有效&#xff0c;DS是输入信号&#xff0c;M…

动态规划算法刷题笔记【线性dp】

递推 斐波那契(Fibonacii)数列的递推公式&#xff1a;F(n) F(n -1) F(n - 2) 错排问题&#xff1a;F(n) (n-1) * [F(n-1)F(n-2)] 解释 例题 一只青蛙一次可以跳上1级台阶&#xff0c;也可以跳上2级台阶。求该青蛙跳上一个 10 级的台阶总共有多少种跳法 思路 要想跳到第…

代码随想录算法训练营第4天 24.两两交换链表中的节点、19. 删除链表的倒数第N个节点、160.链表相交

代码随想录算法训练营第4天 24.两两交换链表中的节点、19. 删除链表的倒数第N个节点、160.链表相交 两两交换链表中的节点 力扣题目链接(opens new window) 给定一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后的链表。 你不能只是单纯的改变节点内部…