美文网首页
自定义View_一个带悬浮窗的ProgressBar(中)

自定义View_一个带悬浮窗的ProgressBar(中)

作者: BraveJoy | 来源:发表于2024-02-04 22:29 被阅读0次

在上篇内容【自定义View_一个带悬浮窗的ProgressBar(上)】里,我们已经完成了自定义的进度条效果,那么本篇内容我们来介绍悬浮窗如何实现,先来看一下我们今天要实现的效果:

效果分析

  • 悬浮窗有边框,可以使用Path绘制。
  • 悬浮窗有填充色,可以使用Path绘制,Path填充。
  • 悬浮窗有文字,进度百分比,可以使用drawText绘制。
  • 悬浮窗的宽度可以随文字动态变化,这里我们就把文字的宽度作为悬浮窗的宽度(不考虑两端圆弧)。
  • 悬浮窗底部有箭头,并且箭头可以根据百分比进行位置偏移。

经过上面对效果的拆解分析,我们已经大概有了实现方案,那就是使用Path进行开发。那么Path该如何绘制?从哪里作为起点开始绘制,需要绘制那些片段,是我们需要分析重中之重。

Path轨迹

由于悬浮窗底部箭头的位置是需要根据百分比动态偏移的,它影响整个Path轨迹的绘制,也就是说它影响着较多的其他变量的变化,那么我们就把箭头的位置作为起点开始绘制,绘制过程示意如下:

动作分解

我们可以把上面的动图进行分解成下面7个片段:

①、从起点开始,向左上方画一条线段
②、紧接着往左方形画一条线段
③、再继续画一个半圆弧
④、往右画一条线段
⑤、再继续画一个半圆弧
⑥、继续往左画一条线段
⑦、闭合

如何开始?

下面的箭头,我们可以把它当成一个等边三角形,并且给它一个初始高度mArrowHeight。

再仔细看下悬浮窗的动效可以发现,底部箭头是需要根据当前的百分比而发生位置偏移的,如下:

当0%的时候,箭头在最左侧,随着百分比的增大,箭头逐渐移动到最右边:

我们需要知道,整个过程中箭头移动的总距离是多少,才能控制其偏移量。

已知箭头的高度是mArrowHeight,悬浮窗左右两个半圆弧的半径是radius。

假设底部起点坐标是(firstX, firstY),那么在上面这个过程中,我们需要明确firstX移动的范围,示意图如下:

根据示意图,也就得到了firstX移动范围是:[raidus+c , getWidth() - radius - c]
移动的总距离是:

// 箭头活动范围,对应的距离长度是:distance
float distance = getWidth() - 2 * radius - 2 * c

上面的计算中,还需要求出c的值,那么如何求出c可以使用三角函数公式:
根据:

tan30° = c / mArrowHeight

可以求出:

c =tan30° * mArrowHeight

即:

double rad = 30 * Math.PI / 180.0; // 角度转成弧度
c = (float) (Math.tan(rad) * mArrowHeight);

计算坐标,绘制

我们知道,起点坐标是动态偏移的,是和当前百分比(currentPercent)相关联的,那么当百分比在某个数值时,我们需要计算线段②的长度,即下图中的②:


上图中④的长度是等于文字的宽度的,即④=textWidth,那么②(leftDistance)就等于:

// 箭头左边的线段的长度
float leftDistance = (textWidth - 2 * c) * currentPercent;

其中,文字宽度计算如下:

// 获取当前文字
private String getText() {
    return "进度 " + df.format(this.currentPercent* 100) + " %";
}

// 计算文字的宽度
private float getTextWidth() {
    String text = getText();
    return paintProgress.measureText(text, 0, text.length());
}

接下来,我们就可以逐个计算出坐标了。

第1个坐标,即起点坐标:

// 1
float firstX = radius + c + (currentPercent* distance);
float firstY = getHeight();
path.moveTo(firstX, firstY);

第2个坐标:

// 2
float secondX = firstX - c;
float secondY = getHeight() - mArrowHeight;
path.lineTo(secondX, secondY);

第3个坐标:

// 3
float thirdX = firstX - c - leftDistance;
float thirdY = getHeight() - mArrowHeight;
path.lineTo(thirdX, thirdY);

第4个坐标:

// 4
float left = firstX - c - leftDistance - radius;
float top = 0;
float right = firstX - c - leftDistance + radius;
float bottom = getHeight() - mArrowHeight;
leftRect.set(left, top, right, bottom);
path.arcTo(leftRect, 90, 180);

第5个坐标:

// 5
float fourthX = firstX - c - leftDistance + textWidth;
float fourthY = 0;
path.lineTo(fourthX, fourthY);

第6个坐标:

//6
float left2 = firstX - c - leftDistance + textWidth - radius;
float top2 = 0;
float right2 = firstX - c - leftDistance + textWidth + radius;
float bottom2 = getHeight() - mArrowHeight;
rightRect.set(left2, top2, right2, bottom2);
path.arcTo(rightRect, -90, 180);

第7个坐标:

// 7
float fifthX = firstX + c;
float fifthY = getHeight() - mArrowHeight;
path.lineTo(fifthX, fifthY);
path.close();

绘制轨迹和文字:

//绘制轨迹-填充
canvas.drawPath(path, paintFill);
//绘制轨迹-边框
canvas.drawPath(path, paintStroke);

// 绘制文字,百分比
Paint.FontMetricsInt fontMetricsInt = paintProgress.getFontMetricsInt();
float dy2 = (fontMetricsInt.bottom - fontMetricsInt.top) / 2f - fontMetricsInt.bottom;
float baseLine = (getHeight() - mArrowHeight) / 2f + dy2;
canvas.drawText(getText(), thirdX, baseLine, paintProgress);

加动画:

/**
 * 设置当前进度的数据,带动画
 *
 * @param progress 百分比
 */
public void setProgressWithAnim(float progress) {
    ValueAnimator animator = ValueAnimator.ofFloat(0, progress).setDuration(ANIMATION_DURATION);
    animator.addUpdateListener(animation -> {
        currentPercent = (float) animation.getAnimatedValue() / 100.0f;
        invalidate();
    });
    animator.start();
}

至此,我们已经完成了今天要实现的效果。

相关文章

  • Android-解决WindowManager.addView背

    最近在项目当中使用到自定义悬浮窗,我们悬浮窗功能完善了。但是遇到了一个问题,我们想做一个椭圆且透明的悬浮窗,但是我...

  • iOS仿微信悬浮窗

    仿微信悬浮窗,可直接协议加入悬浮窗或者直接调用方法注册,可自定义转场动画 Github地址(WMZFloatVie...

  • Android中悬浮窗的适配

    在android中,经常会使用WindowManager来自定义悬浮窗样式,不同的android版本中,用法有所不...

  • 自定义progressbar

    progressbar 自定义progressbar 进度条 圆形progressbar 世界因为有了互相帮助,...

  • FloatWindow-优雅实现Android悬浮窗

    研究并写了一套悬浮窗实现方案,缩放,移动,关闭,点击,自定义某个页面显示,我采用的是内部view添加布局展示悬浮窗...

  • ProgressBar

    Android控件--ProgressBar 三种方式实现自定义圆形进度条ProgressBar

  • XFloatView 一个简易的悬浮窗实现方案

    XFloatView 项目地址 一个简易的悬浮窗实现方案 关于我 github csdn 特征 支持自定义布局...

  • Android常用控件之ProgressBar,圆形进度条

    目录:android.widget.ProgressBar 前言:中间带百分比的圆形进度条xml布局 自定义view:

  • android 悬浮窗

    安卓悬浮窗的书写,我们分为几个步骤: 1.添加悬浮窗权限 2.书写悬浮窗代码,搭建悬浮窗布局 3.判断悬浮窗权限是...

  • Flutter 带指示器的悬浮窗口

    一、需求 二、思路 先把下面的悬浮窗背景和三角形自定义绘制一个widget。然后再把标签和悬浮框做一个联动(Com...

网友评论

      本文标题:自定义View_一个带悬浮窗的ProgressBar(中)

      本文链接:https://www.haomeiwen.com/subject/qgpomdtx.html