Android自定义简单仿QQ运动步数进展圆环

news2024/11/16 13:28:20

实现效果主要效果分为三个部分:
1.固定蓝色的大圆弧 color borderWidth
2.可以变化的小圆弧(红色) color borderWidth
3.中间的步数文字 color textSize
在这里插入图片描述

drawArc方法
startAngle 确定角度的起始位置
sweepAngle 确定扫过的角度
useCenter 是否使用中心:true,连接矩形中心及弧;false不显示,(是否显示半径连线,true表示显示圆弧与圆心的半径连线,false表示不显示)(Paint.Style.FILL时)连接弧的起点终点

    public void drawArc(@NonNull RectF oval, float startAngle, float sweepAngle, boolean useCenter,
            @NonNull Paint paint) {
        super.drawArc(oval, startAngle, sweepAngle, useCenter, paint);
    }

在这里插入图片描述
顺时针,起点从135度开始扫了270度的距离到终点

在这里插入图片描述
左边距离=控件宽度的一半减去文字宽度的一半
具体代码

public class QQStepView extends View {

    private int mOuterColor = Color.RED;
    private int mInnerColor = Color.BLUE;
    private int mBorderWidth = 20;//20px
    private int mStepTextSize;
    private int mStepTextColor;
    private Paint mOutPaint, mInnerPaint, mTextPaint;

    //总共的,当前的步数
    private int mStepMax = 100;//默认值
    private int mCurrentStep = 50;

    public QQStepView(Context context) {
        this(context, null);
    }

    public QQStepView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public QQStepView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        //1.分析效果:
        //2.确定自定义属性,编写attrs.xml
        //3.在布局中使用
        //4.在自定义View中获取自定义属性
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.QQStepView);
        mOuterColor = array.getColor(R.styleable.QQStepView_outerColor, mOuterColor);
        mInnerColor = array.getColor(R.styleable.QQStepView_innerColor, mInnerColor);
        mBorderWidth = (int) array.getDimension(R.styleable.QQStepView_borderWidth, mBorderWidth);
        mStepTextSize = array.getDimensionPixelSize(R.styleable.QQStepView_stepTextSize, mStepTextSize);
        mStepTextColor = array.getColor(R.styleable.QQStepView_stepTextColor, mStepTextColor);
        array.recycle();
        mOutPaint = new Paint();
        mOutPaint.setAntiAlias(true);
        mOutPaint.setStrokeWidth(mBorderWidth);
        mOutPaint.setColor(mOuterColor);
        mOutPaint.setStrokeCap(Paint.Cap.ROUND);//设置头部和尾部为圆形
        mOutPaint.setStyle(Paint.Style.STROKE);//空心

        mInnerPaint = new Paint();
        mInnerPaint.setAntiAlias(true);
        mInnerPaint.setStrokeWidth(mBorderWidth);
        mInnerPaint.setColor(mInnerColor);
        mInnerPaint.setStrokeCap(Paint.Cap.ROUND);//设置头部和尾部为圆形
        mInnerPaint.setStyle(Paint.Style.STROKE);//空心

        mTextPaint = new Paint();
        mTextPaint.setAntiAlias(true);
        mTextPaint.setColor(mStepTextColor);
        mTextPaint.setTextSize(mStepTextSize);
        //7.其他
    }

    //5.onMeasure
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //调用者在布局文件中可能 wrap_content,这个时候你可以去判断模式如果是AT-MOST去设置一个默认值,或者抛出异常让用户不可以设置wrap_content
        //这里我默认设置为100dp
        int width = MeasureSpec.getSize(widthMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        if (widthMode == MeasureSpec.AT_MOST) {
            width = dip2px(getContext(), 100);
        }
        if (heightMode == MeasureSpec.AT_MOST) {
            height = dip2px(getContext(),100);
        }
        //获取模式 AT_MOST 40dp
        //宽高不一致 取最小值 确保是个正方形,正方向才好画圆
        setMeasuredDimension(width > height ? height : width, width > height ? height : width);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //6.画外圆弧,
        //区域
        //getWidth和getHeight是获取自定义View的宽和高在onMeasure执行完后才能调用
        int center = getWidth() / 2;
        int radius = center - mBorderWidth / 2;//mBorderWidth如果不除与2的话也行
        //center - radius和center + radius是考虑描边宽度的问题,如果直接是用右边getWidth和下边getHeight,左边和上边为0的话,这样画出来的圆弧会出边界
        //因此我们要考虑描边宽度的问题,让他小一点,画的时候不要出界。
        RectF rectF = new RectF(center - radius, center - radius, center + radius, center + radius);
        //起始角度135到270顺时针扫
        canvas.drawArc(rectF, 135, 270, false, mOutPaint);
        //7.画内圆弧,
        if (mStepMax == 0) {
            //如果没设置总步数就不让他往下执行
            return;
        }
        //不能向外圆弧一样写死  百分比 是使用者设置的从外面传
        float sweepAngle = (float) mCurrentStep / mStepMax;
        canvas.drawArc(rectF, 135, 270 * sweepAngle, false, mInnerPaint);

        //8.画文字
        String stepText = mCurrentStep + "";
        Rect textBounds = new Rect();
        //文字的宽度需要画笔去测量
        mTextPaint.getTextBounds(stepText, 0, stepText.length(), textBounds);
        int dx = getWidth() / 2 - textBounds.width() / 2;//左边距离=控件宽度的一半减去文字宽度的一半
        //基线
        Paint.FontMetricsInt fontMetrics = mTextPaint.getFontMetricsInt();
        int dy = (fontMetrics.bottom - fontMetrics.top) / 2 - fontMetrics.bottom;
        int baseLine = getHeight() / 2 + dy;
        canvas.drawText(stepText, dx, baseLine, mTextPaint);
    }

    //7.其他 写几个方法动起来
    public void setStepMax(int stepMax) {
        this.mStepMax = stepMax;
    }

    public void setCurrentStep(int currentStep) {
        this.mCurrentStep = currentStep;
        //不断绘制  调用onDraw
        invalidate();
    }
}

布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="16dp"
    android:paddingLeft="16dp"
    android:paddingRight="16dp"
    android:paddingTop="16dp"
    xmlns:yiran="http://schemas.android.com/apk/res-auto">

<com.example.customview.customview.qqstep.QQStepView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/step_view"
    yiran:outerColor="@color/mainColor"
    yiran:innerColor="@color/purple_700"
    yiran:borderWidth="6dp"
    yiran:stepTextColor="@color/purple_700"
    yiran:stepTextSize="16sp"
    />
</LinearLayout>

使用

public class ViewActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_qqstepview);
        QQStepView qqStepView=(QQStepView) findViewById(R.id.step_view);
        qqStepView.setStepMax(4000);//设置最大值4000
        //属性动画
        //1秒钟从0变化到3000
        ValueAnimator valueAnimator= ObjectAnimator.ofFloat(0,3000);
        valueAnimator.setDuration(1000);
        valueAnimator.setInterpolator(new DecelerateInterpolator());//设置动画效果前面快后面慢一点
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float currentStep=(float) animation.getAnimatedValue();
                qqStepView.setCurrentStep((int) currentStep);
            }
        });
        valueAnimator.start();
    }
}

效果图
在这里插入图片描述

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

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

相关文章

MyBatis XML配置文件(下)

MyBatis的开发有两种方式&#xff1a;1、注解 2、XML。使用MyBatis的注解方式&#xff0c;主要是来完成一些简单的增删改查功能。如果需要实现复杂的SQL功能&#xff0c;建议使用XML来配置映射语句&#xff0c;也就是将SQL语句写在XML配置文件中。 MyBatis XML开发的方式需要以…

UE5学习笔记17-让人物的视线和鼠标移动时的方向一致,并且不让人物模型旋转,只改变视线方向

一、创建标准动画帧 1.我想让人物在装备武器后根据鼠标的移动方向改变人物的视线方向&#xff0c;并且人物模型不会改变朝向 2.我的动画中存在一个四个方向瞄准的动画&#xff0c;将左下&#xff0c;坐上&#xff0c;左转&#xff0c;右上&#xff0c;右下&#xff0c;右转&…

C++ 设计模式——组合模式

C 设计模式——组合模式 C 设计模式——组合模式1. 主要组成成分2. 逐步构建透明组合模式1. 定义抽象组件&#xff08;Component&#xff09;2. 实现叶子组件&#xff08;Leaf&#xff09;3. 实现组合组件&#xff08;Composite&#xff09;4. 主函数&#xff08;Main&#xff…

Nacos踩坑

最近遇到项目部署&#xff0c;遇到Nacos中的配置读取不到&#xff0c;导致服务起不来。服务器银河麒麟x86&#xff0c;Nacos版本2.3.2, openJdk8u43 报错如下&#xff1a; java.lang.UnsatisfiedLinkError: no com_alibaba_nacos_shaded_io_grpc_netty_shaded_netty_transport…

Linux磁盘操作之du命令

使用du命令&#xff0c;您可以查看指定目录或文件的磁盘使用量总计。这对于了解特定目录或文件占用的磁盘空间大小非常有用&#xff0c;可以帮助您进行磁盘空间管理和清理。 参数说明 du是一个用于显示目录或文件的磁盘使用情况的命令&#xff0c;du是disk usage的缩写&#…

从图像到视频:Web Codecs API编码技术解析

初探Web Codecs API 三 前言 在之前的文章中,咱们简单的介绍了解码相关的东西,这一节咱们来简单聊聊编码相关的东西。 编码的目的就是为了压缩,去除空间、时间维度的冗余。 这里又不得不提起前面所说的I 帧、P 帧、B 帧和 IDR 帧。 众所周知,视频是连续的图像序列,由…

【添加核心机械臂动力学】Model and Control a Manipulator Arm with Robotics and Simscape

机械臂动力学 为了设计控制器&#xff0c;机械臂动力学必须表示给定力矩输入的关节位置。这在机械臂动力学子系统中通过一个前向动力学块实现&#xff0c;该块将关节力矩转换为给定当前状态的关节加速度&#xff0c;然后通过两次积分得到完整的关节配置。积分器初始化为q0和dq…

自闭症托管托养机构:星贝育园的优势与使命

在当今社会&#xff0c;自闭症儿童作为一群需要特别关注和照顾的群体&#xff0c;其教育与康复问题日益受到社会各界的重视。自闭症托管托养机构作为这一领域的重要力量&#xff0c;承担着为自闭症儿童提供全方位、个性化支持的重任。星贝育园&#xff0c;作为一所全日寄宿制的…

使用libsvm时遇到MATLAB has encountered an internal problem and needs to close

最近在MATLAB中使用libsvm跑别人的程序&#xff0c;该程序在大部分数据集上可以正常运行&#xff0c;但在有一个数据集上运行时MATLAB会报“MATLAB has encountered an internal problem and needs to close”的错误&#xff1a; 凭直觉猜应该是数据集有啥问题&#xff0c;但又…

AI人的列表!《中国人工智能学会推荐国际学术会议和国际/国内期刊目录》正式发布

在全球科技迅猛发展的今天&#xff0c;人工智能&#xff08;AI&#xff09;已成为推动社会进步的关键力量。为了更好地指导AI领域的科研方向&#xff0c;加强学术交流&#xff0c;促进学术成果的创新与应用&#xff0c;中国人工智能学会&#xff08;CAAI&#xff09;在2024年8月…

数据分析案例-2024年裁员数据集可视化分析

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

XFTP软件的使用 ---- 远程上传、下载文件

本文假设你的电脑里面已经有XFTP软件。 一、简介 是一个基于 windows 平台的功能强大的SFTP、FTP文件传输软件。通过Xftp软件&#xff0c;windows 用户能安全地在UNIX/Linux 和 Windows PC 之间传输文件。 二、 使用方法【步骤】 打开软件&#xff0c;得到如下图界面。 首先我…

STL--unordered_set和unordered_map的模拟实现

1.unordered系列关联式容器 在C98中&#xff0c;STL提供了底层为红黑树结构的一系列关联式容器&#xff0c;在查询时效率可达到&#xff0c;即最差情况下需要比较红黑树的高度次&#xff0c;当树中的节点非常多时&#xff0c;查询效率也不理想。最好的查询是&#xff0c;进行很…

如何使用ssm实现基于java斗车交易系统设计与实现+vue

TOC ssm082基于java斗车交易系统设计与实现vue 系统概述 1.1 概述 随着社会的快速发展&#xff0c;计算机的影响是全面且深入的。人们的生活水平不断提高&#xff0c;日常生活中人们对斗车交易方面的要求也在不断提高&#xff0c;需要咨询的人数更是不断增加&#xff0c;使得…

OpenCV 图像处理基础算法介绍c++

VS2022配置OpenCV环境 关于OpenCV在VS2022上配置的教程可以参考&#xff1a;VS2022 配置OpenCV开发环境详细教程 图像处理 图像处理是一个广泛的领域&#xff0c;它涉及到对图像数据进行分析、修改和改进的各种技术。以下是一些基本的图像处理操作&#xff0c;这些操作通常可…

模型 蒂蒙斯创业过程

系列文章 分享 模型&#xff0c;了解更多&#x1f449; 模型_思维模型目录。机会、团队、资源&#xff1a;创业成功的三角。 1 蒂蒙斯创业过程的应用 1.1 京东&#xff1a;蒂蒙斯模型下创业成功的典范 京东是中国知名的电子商务平台&#xff0c;其早期发展阶段充分体现了蒂蒙…

接口基础知识12:cookie、session和token

​课程大纲 ‌Cookie、Session和Token是Web应用中常用的身份验证和会话管理机制&#xff0c;各有特点&#xff0c;适用于不同的应用场景。 一、Cookie 1.1 什么是Cookie Cookie是存储在客户端浏览器中的小段数据&#xff0c;通常用于存储用户偏好设置或用于跟踪用户活动。 C…

51单片机——数码管控制

1、数码管介绍 LED数码管&#xff1a;数码管是一种简单、廉价的显示器&#xff0c;是由多个发光二极管封装在一起组成“8”字型的器件。 2、数码管驱动方式 单片机直接扫描&#xff1a;硬件设备简单&#xff0c;但会耗费大量的单片机CPU时间 专用驱动芯片&#xff1a;内部自…

8月24日笔记

ew的使用 EW&#xff08;EarthWorm&#xff09;是一套基于C语言开发的轻量级且功能强大的网络穿透工具&#xff0c;它支持Socks5代理、端口转发及端口映射等功能&#xff0c;能够在复杂的网络环境中实现高效稳定的网络穿透。这款全平台适用的工具&#xff08;包括Windows、Lin…

proc文件的写操作机制

“一切皆是文件”。 Linux的基本哲学之一。它是指linux系统中的所有一切都可以通过文件的方式访问、管理&#xff0c;即便不是文件&#xff0c;也以文件的形式来管理。例如硬件设备、进程、套接字等都抽象成文件&#xff0c;使用统一的用户接口&#xff0c;虽然文件类型各不相同…