android-DecoView-charting:实践指南

作者:袖梨 2026-09-10

如果把android-DecoView-charting放进候选清单,不能只看热度;它的定位是DecoView:Android基于弧线的动画图表库。实际做日常自动化时,经常会碰到输入边界、依赖和失败处理如果不清楚就很难稳定复用,所以功能列表并不能代替验证。我建议用一项范围明确的真实任务完成最小试跑,重点记录配置时间、输出质量、异常信息和维护痕迹,再与现有方案比较。我的判断是,它更适合愿意先做小范围验证并复查原始文档的团队;若眼下没有这类需求,先保留观察即可。

DecoView

为 Android 开发者提供的强大的动画圆轮图表库。

DecoView 是一个功能强大的库,可以在您的 Android 应用程序中创建高度可配置的动画圆形图表。它可以让您在自己的 Android 应用程序中轻松重现 Google Fit 圆形滚轮视图等用户体验。借助广泛的自定义选项,可以简单快速地更改图表的外观和风格以匹配您的 UI。

要了解 DecoView 的实际效果,请观看宣传视频。

Play 商店提供示例应用程序。

在您的项目中包含 DecoView

步骤1.将存储库添加到您的build.gradle中

repositories {
    // ...
    maven { url "https://jitpack.io" }
}

步骤2.在表单中添加依赖

dependencies {
    compile 'com.github.bmarrdev:android-DecoView-charting:v1.2'
}

用途

DecoView 是 Android View 类的子类。就像其他 View 子类(例如 TextView 和 ImageView)一样,它可以从布局 XML 添加和配置,然后在 Activity 代码中进行控制。

该存储库包含许多用于构建和动画 DecoView 的示例。您可以在 示例应用程序项目 中找到示例的代码。

您需要了解的主要概念是:

  • DecoView 是一个 View,它是 android.view.View 的子类
  • 使用 SeriesItem.Builder 构建一个或多个数据系列,否则您的 DecoView 将不可见
  • 使用 DecoEvent.Builder 安排每个数据系列的动画事件

将 DecoView 添加到您的 xml 布局

<com.hookedonplay.decoviewlib.DecoView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/dynamicArcView"/>

在您的Java代码中配置DecoView数据系列

DecoView arcView = (DecoView)findViewById(R.id.dynamicArcView);

// Create background track
arcView.addSeries(new SeriesItem.Builder(Color.argb(255, 218, 218, 218))
        .setRange(0, 100, 100)
        .setInitialVisibility(false)
        .setLineWidth(32f)
        .build());

//Create data series track
SeriesItem seriesItem1 = new SeriesItem.Builder(Color.argb(255, 64, 196, 0))
        .setRange(0, 100, 0)
        .setLineWidth(32f)
        .build();

int series1Index = arcView.addSeries(seriesItem1);

添加事件以动画数据系列

arcView.addEvent(new DecoEvent.Builder(DecoEvent.EventType.EVENT_SHOW, true)
        .setDelay(1000)
        .setDuration(2000)
        .build());

arcView.addEvent(new DecoEvent.Builder(25).setIndex(series1Index).setDelay(4000).build());
arcView.addEvent(new DecoEvent.Builder(100).setIndex(series1Index).setDelay(8000).build());
arcView.addEvent(new DecoEvent.Builder(10).setIndex(series1Index).setDelay(12000).build());

图表形状和方向

图表可以是完整的圆(360 度)或圆的一部分。度数和方向可以在 DecoView 中设置。

void DecoView.configureAngles(int totalAngle, int rotateAngle);

decoView.configureAngles(360, 0);

要将 DecoView 设置为完整的圆,请传递 360 作为 totalAngle。或者,300 度将产生马蹄形,180 度将产生半圆形。

默认情况下,当使用整圆时,数据系列将源自屏幕顶部。通过传递 90 作为旋转角度,图表的初始点将顺时针移动 90 度,从圆的最右点开始。

当视图不是完整的圆形时,默认初始点是视图的底部。传递 90 会将初始点设置为最左边的点,传递 180 会将初始点设置为最上面的点。

图表重力

默认情况下,无论布局中 DecoView 的尺寸如何,图表都将保持正方形形状。

您可以将图表的重力定义为向左、居中、向右或水平填充,也可以将垂直重力定义为顶部、中间、底部或填充。

重力可以在布局 XML 中定义:

<com.hookedonplay.decoviewlib.DecoView
    xmlns:custom="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/dynamicArcView"
    custom:dv_arc_gravity_horizontal="Fill"
    custom:dv_arc_gravity_vertical="Bottom"
    android:layout_margin="8dp"/>

或者,可以在 Java 源代码中定义重力:

decoView.setHorizGravity(DecoView.HorizGravity.GRAVITY_HORIZONTAL_FILL);
decoView.setVertGravity(DecoView.VertGravity.GRAVITY_VERTICAL_BOTTOM);

构建数据系列

DecoView 中可以添加一个或多个数据系列。它们是使用 SeriesItem.Builder(...) 类创建的。

构造一个新系列所需的最低限度如下:

decoView.addSeries(new SeriesItem.Builder(Color.argb(255, 218, 218, 218)).build());

Builder 类允许您配置所有选项来自定义视图,使其外观和行为符合您的要求。下面是 SeriesItem 的更详细构造,它覆盖了更多默认设置

SeriesItem seriesItem1 = new SeriesItem.Builder(Color.argb(255, 64, 196, 0))
        .setRange(0, seriesMax, 0)
        .setInitialVisibility(false)
        .setLineWidth(32f)
        .addEdgeDetail(new EdgeDetail(EdgeDetail.EdgeType.EDGE_OUTER, Color.parseColor("#22000000"), 0.4f))
        .setSeriesLabel(new SeriesLabel.Builder("Percent %.0f%%").build())
        .setInterpolator(new OvershootInterpolator())
        .setShowPointWhenEmpty(false)
        .setCapRounded(false)
        .setInset(new PointF(32f, 32f))
        .setDrawAsPoint(false)
        .setSpinClockwise(true)
        .setSpinDuration(6000)
        .setChartStyle(SeriesItem.ChartStyle.STYLE_DONUT)
        .build();

向数据系列添加器

创建 SeriesItem 后,您可以选择添加 SeriesItem.SeriesItemListener(),它允许您使用回调来监视数据系列的动画进度。

向数据系列添加侦听器的最常见原因是显示数据系列的当前百分比或值。

String format = "%.0f%%";

seriesItem.addArcSeriesItemListener(new SeriesItem.SeriesItemListener() {
    @Override
    public void onSeriesItemAnimationProgress(float percentComplete, float currentPosition) {
        if (format.contains("%%")) {
            float percentFilled = ((currentPosition - seriesItem.getMinValue()) / (seriesItem.getMaxValue() - seriesItem.getMinValue()));
            view.setText(String.format(format, percentFilled * 100f));
        } else {
            view.setText(String.format(format, currentPosition));
        }
    }

    @Override
    public void onSeriesItemDisplayProgress(float percentComplete) {

    }
});

请注意,进度回调包含 percentComplete 参数。这是当前正在执行的动画的完成百分比,您可以使用当前位置计算填充百分比。

动画数据系列

DecoView 中的每个数据系列都可以通过多种方式进行动画处理。

public enum EventType {
    EVENT_MOVE, /* Move the current position of the chart series */
    EVENT_SHOW, /* Show the chart series using reveal animation */
    EVENT_HIDE, /* Hide the chart series using an animation */
    EVENT_EFFECT, /* Apply effect animation on the series */
    EVENT_COLOR_CHANGE /* Change the color of the series over time */
}

EventManager 允许您对数据系列执行上述操作。这些可以立即执行,也可以在将来触发。

要移动数据系列的当前位置,请创建一个新的 DecoEvent 并将其传递给 DecoView:

decoView.addEvent(new DecoEvent.Builder(50).setIndex(mSeriesIndex).build());

如果您想在将来某个时间执行该事件,可以通过 DecoEvent.Builder.setDelay(long ms) 函数将延迟添加到 DecoEvent。

decoView.addEvent(new DecoEvent.Builder(50).setIndex(mSeriesIndex).setDelay(8000).build());

在上面的例子中,需要注意的一些要点是:

  • 传递给构建器函数的参数“50”是与使用 SeriesItem.Builder().setRange(min, max, initial) 函数调用初始化的数据范围相关的位置
  • 传递的索引是从 DecoView.addSeries(...) 函数调用返回的
  • 所有持续时间均以毫秒为单位指定

向 DecoEvent 添加器

将侦听器添加到 DecoEvent 对于在事件开始和事件结束时获取回调非常有用。

decoView.addEvent(new DecoEvent.Builder(EventType.EVENT_HIDE, false)
        .setDelay(19500)
        .setDuration(2000)
        .setLinkedViews(linkedViews)
        .setListener(new DecoEvent.ExecuteEventListener() {
            @Override
            public void onEventStart(DecoEvent event) {
                Log.d(TAG, "Hide of DecoView Starting");
            }

            @Override
            public void onEventEnd(DecoEvent event) {
                Log.d(TAG, "Hide of DecoView Complete");
            }
        })
        .build());

配置动画

移动数据系列的当前位置时的运动动画是使用内置的 Android 插值器类 完成的。

这允许您设置一系列不同的运动,甚至使用您自己的算法来控制变化率。

可以配置在两个不同阶段使用的 Interpolator 类。第一个机会是您可以在最初添加数据系列时设置插值器。如果您在创建时设置插补器,则该数据系列的所有动画都将使用您指定的插补器,除非您在创建 DecoEvent 时覆盖插补器。

decoView.addSeries(new SeriesItem.Builder(Color.argb(255, 218, 218, 218))
        .setRange(0, seriesMax, 0)
        .setInterpolator(new AccelerateInterpolator())
        .build());

如果创建数据系列时未设置插值器,则所有动画将使用默认的 AccelerateDecelerateInterpolator()。

还可以覆盖应用于数据系列的每个事件的插值器。这将覆盖创建数据系列期间设置的插值器(如果有)。

decoView.addEvent(new DecoEvent.Builder(10)
        .setIndex(mSeries1Index)
        .setDelay(3000)
        .setInterpolator(new OvershootInterpolator())
        .build());

配置动画持续时间

与配置插值器非常相似,可以在创建数据系列时设置完成动画所需的总持续时间,或者为每个事件覆盖。

decoView.addSeries(new SeriesItem.Builder(Color.argb(255, 218, 218, 218))
        .setRange(0, seriesMax, 0)
        .setSpinDuration(3000)
        .build());

SpinDuration 是完整旋转一圈所需的持续时间。这是动画从系列开始到结束的移动所花费的时间。根据此持续时间,当 DecoEvent 移动当前位置时,会根据所需的旋转量自动计算持续时间。

为了举例说明这一点,如果将旋转持续时间设置为 3 秒(3000 毫秒),然后将当前位置移动到总弧线范围的 50%,则动画将需要 1.5 秒才能完成。

还可以覆盖应用于数据系列的每个 DecoEvent 的持续时间。

decoView.addEvent(new DecoEvent.Builder(10)
        .setIndex(mSeries1Index)
        .setDelay(3000)
        .setDuration(2000)
        .build());

向数据系列添加标签

可以将标签添加到一个或多个数据系列。仅当数据系列可见时才会显示标签。

使用 SeriesLabel.Builder(String) 函数创建 SeriesLabel。可以选择设置文本和背景的颜色以及字体。

SeriesItem seriesItem = new SeriesItem.Builder(Color.argb(255, 64, 196, 0))
        .setRange(0, seriesMax, 0)
        .setSeriesLabel(new SeriesLabel.Builder("Percent %.0f%%")
                .setColorBack(Color.argb(218, 0, 0, 0))
                .setColorText(Color.argb(255, 255, 255, 255))
                .setTypeface(customTypeface)
                .build())
        .build();

可以对数据标签上使用的文本使用自定义字体。从 Android 资产文件夹加载字体并使用 SeriesLabel.Builder().setTypeface(...) 设置字体。

注意:DecoViews 目前不支持标签,该标签具有逆时针方向移动的数据系列。

插入圆弧半径

默认情况下,系列中的每个弧将位于最宽数据系列的中心。其结果是,将以距视图中心相同的半径绘制两条具有相同线宽的圆弧。

创建数据系列时可以通过设置插入来调整每个系列的中心半径。下图演示了更改每个系列的插图时可能发生的情况。

要在系列创建期间设置插图,请使用 SeriesItem.Builder#setInset(PointF)

SeriesItem seriesItem = new SeriesItem.Builder(Color.parseColor("#FF00FF00")
        .setRange(0, 100, 0)
        .setInset(new PointF(20f, 20f))
        .build();

还可以使用负插入将数据系列向外移动。为此,您需要确保不会将数据系列移动到视图的可视区域之外。

动画颜色变化

纯色变化可以通过动画从一种颜色变为另一种颜色。这可以作为独立事件或在移动事件期间完成。

要在移动事件期间对颜色变化进行动画处理,请使用构建器 setColor(int color) 函数构造该事件:

decoView.addEvent(new DecoEvent.Builder(10)
        .setIndex(mSeries1Index)
        .setDelay(3000)
        .setColor(Color.parseColor("#FF555555"))
        .build());

再例如,样本贴合跟踪器 演示了移动事件期间的颜色变化。

以下代码演示了如何将颜色变化动画化为独立事件。创建 EVENT_COLOR_CHANGE 事件时,必须调用 setDuration(...)。

decoView.addEvent(new DecoEvent.Builder(EventType.EVENT_COLOR_CHANGE, Color.parseColor("#FF555555"))
        .setIndex(index)
        .setDelay(10000)
        .setDuration(2000)
        .build());

注意:无法使用颜色渐变对系列上的颜色变化进行动画处理。

将 EdgeDetail 添加到数据系列

EdgeDetail 类允许您将效果应用到数据系列的边缘。下图显示了应用于每个数据系列的 EdgeDetail。

通过传递要应用细节的圆弧的哪条边以及边缘细节的颜色和大小来构造 EdgeDetail 对象。边缘细节的大小被指定为范围从 0f 到 1.0f 的浮点数,其中 1.0f 将覆盖整个弧。

使用 SeriesItem.Builder.addEdgeDetail(EdgeDetail) 函数将边缘添加到系列中。

SeriesItem seriesItem = new SeriesItem.Builder(Color.argb(255, 64, 196, 0))
        .setRange(0, seriesMax, 0)
        .addEdgeDetail(new EdgeDetail(EdgeDetail.EdgeType.EDGE_OUTER, Color.parseColor("#22000000"), 0.4f))
        .build();

请注意,在上面的示例中,颜色使用透明度为圆弧边缘提供比现有圆弧颜色更深的色调。

NOTE:在 Android 4.0 至 4.3 上,将 EdgeDetail 添加到数据系列将导致该 DecoView 的硬件加速被关闭。这是因为这些平台不支持具有硬件加速的 clipPath() 函数。这会导致视图性能出现明显差异,这是不寻常的。

向 SeriesItem 添加阴影

DecoView 1.1 中引入了阴影,在添加阴影之前请检查 gradle 依赖关系。

在添加阴影之前有一些非常重要的注意事项。

创建带有阴影的 DecoView 时,必须调用“java DecoView.disableHardwareAccelerationForDecoView();”来禁用视图的硬件加速。硬件加速不支持 Android 画布操作中内置的阴影功能。请注意,如果您同时对多个视图进行动画处理,这可能会导致性能问题。

如果您要设置阴影,您很可能还想将阴影的大小添加到系列项目的插图中。原因是 decoView 无法在给定视图画布之外进行绘制。如果您不插入系列,那么在视图的顶部和侧边缘,阴影将被剪掉。

mDecoView = (DecoView) findViewById(R.id.dynamicArcView);
mDecoView.disableHardwareAccelerationForDecoView();

final SeriesItem seriesItem = new SeriesItem.Builder(Color.parseColor("#FFFF8800"))
        .setRange(0, mSeriesMax, 0)
        .setInset(new PointF(30, 30))
        .setShadowSize(30)
        .setShadowColor(Color.DKGRAY)
        .setInitialVisibility(false)
        .build();

健身追踪器示例

除了此存储库中构建的示例之外,GitHub 上还提供了 [健身追踪器示例。

以下文章详细介绍了构建此示例所需的步骤:

https://androidbycode.wordpress.com/2015/08/16/creating-a-google-fit-style-circular-animated-view/

要求

安卓2.2+

制作人员

  • 持续集成由 Travis CI 提供。
  • Jake Wharton 的 NineOldAndroids 允许支持 Android 2.2+ 设备。
  • 由 Freepik 设计的信息图表矢量
  • 由 Freepik 设计的头像

许可证

Copyright 2016 Brent Marriott

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

相关文章

精彩推荐