水平进度条添加圆形指示器

Horizontal progressbar add circle indicators

我正在尝试创建一个自定义水平进度条,其中将包含一定数量的圆形指示器,如下所示:

谁能告诉我如何实现这种效果(添加圆形指示器)?

您需要为进度条创建自定义 xml 布局,并在 Runnable 或使用 AsyncTask 中进行计算

最好使用 custom view 来实现。要设置进度,您可以定义如下所示的 setter,这会使视图无效并调用 onDraw()。

public class CustomProgressBar extends View {

    // constructors etc...

    void setProgress(int progress) {
        if (progress < 0 || progress > 100) {
            throw new IllegalArgumentException("Progress must be between 0-100!");
        }

        this.progress = progress.
        invalidate(); // tell view to redraw itself
    }
}

下一步是绘制视图中指示进度的部分和指示剩余工作的部分。

final Paint progressPaint = new Paint();
progressPaint.setColor(Color.RED); // could draw a bitmap or whatever, this is a simple example

@Override protected void onDraw(Canvas canvas) {
    canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); // clear previous contents
    float progressW = getWidth() * (progress / 100);
    float remainingW = getWidth() - progressPortion;

    canvas.drawRect(0, 0, progressW, getHeight(), progressPaint);
    canvas.drawRect(progressW, 0, remainingW, getHeight(), remainingPaint);

}

最后,您可以计算圆圈指示器的位置,在 onDraw() 中将它们绘制到 canvas。

final float radius = 5;
final float circleCount = 6;

float unit = getWidth() / circleCount;
float offset = 0;

for (int i=0; i<6; i++) {
    canvas.drawCircle(offset + (radius / 2), getHeight() / 2, radius, circlePaint);
}

如果您需要有条件地显示指标,您可以在 onDraw() 方法中添加一个检查,以查看进度是否超过某个阈值。

假设你的圆圈指标都在一个设定的间隔(相隔相同的距离)以下在我看来是最合乎逻辑的解决方案

  1. 创建自定义视图
  2. 扩展 ProgressBar,这样您就可以继承所有当前功能,而不必创建自己的 setProgress 方法(
  3. 创建一个自定义 属性 'tickInterval'(我建议将其作为 % 价值点而不是 dp 视图,但您可以使用任一 )
  4. 如果您想使用来自 xml
  5. 的视图,请为自定义属性创建一个 XML 文件
  6. 绘制视图时,每隔一段时间绘制指示器

您可能需要调整视图中的填充以确保您的圈子有空间。以下是您需要的简要说明:

public class TickedProgressBarView extends ProgressBar {

    private static final float DEFAULT_INTERVAL = 25f;
    private float INDICATOR_RADIUS;
    private Paint mTickPaint;
    private float mInterval; //%

    public TickedProgressBarView(Context context) {
        super(context);
        initPainters(context, null); //because draw is called a lot of times, don't want to do loads of allocations in onDraw
    }

    public TickedProgressBarView(Context context, AttributeSet attrs) {
        super(context, attrs);
         initPainters(context, attrs);
    }

    public TickedProgressBarView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initPainters(context, attrs);
    }

    private void initPainters(Context context, @Nullable AttributeSet attrs) {
        if (attrs != null) {
            TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TickedProgressBarView, 0, 0);
            mInterval = a.getFloat(R.styleable.TickedProgressBarView_tickInterval, DEFAULT_INTERVAL);
        } else {
            mInterval = DEFAULT_INTERVAL;
        }
        //5 on the line below is HALF how many Dp wide you want the circles - ie a 10 Dp circle results from this
        INDICATOR_RADIUS = 5 * getResources().getDisplayMetrics().density + 0.5f;
        mTickPaint = new Paint();
        mTickPaint.setColor(ContextCompat.getColor(getContext(), R.color.my_color));
        mTickPaint.setStyle(Paint.Style.FILL);
        mTickPaint.setStrokeCap(Paint.Cap.ROUND);
    }

    public void setTickInterval(float intervalPercentage) {
        mInterval = intervalPercentage;
        invalidate();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (mInterval > 0f) {
            final float midHeight = canvas.getHeight() / 2f;
            final int end = canvas.getWidth();
            final int intervalPx = (int) ((end / 100f) * mInterval);
            int nextInterval = intervalPx;
            while (nextInterval <= end) {
                canvas.drawCircle(nextInterval, midHeight, INDICATOR_RADIUS, mTickPaint);
                nextInterval += intervalPx;
            }
        }
    }

}

attrs.xml

<declare-styleable name="TickedProgressBarView">
    <attr name="tickInterval" format="float" />
</declare-styleable>

attr 声明允许您使用来自 xml

的视图
<!-- draw a circle every 10% along the bar -->
<com.my.packge.TickedProgressBarView
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:tickInterval="10.0"
/>

试试这个-

你的xml带进度条-

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
  android:id="@+id/progress_frame" xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:paddingEnd="16dp"
  android:layout_marginTop="10dp"
  android:paddingLeft="16dp"
  android:paddingRight="16dp"
  android:paddingStart="16dp">
  <ProgressBar
    android:id="@+id/flight_progress"
    style="@style/flght.progress.style"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_centerVertical="true"
    android:layout_marginBottom="10dp"
    android:layout_marginTop="10dp"
    android:max="100"
    android:visibility="visible"/>
  <LinearLayout android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:orientation="horizontal">
    <LinearLayout android:layout_width="0dp"
                  android:layout_weight="1"
                  android:layout_height="wrap_content">
      <ImageView android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_gravity="right|end"
                 android:src="@drawable/blue_circle"/>
    </LinearLayout>
    <LinearLayout android:layout_width="0dp"
                  android:layout_weight="1"
                  android:layout_height="wrap_content">
      <ImageView android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_gravity="right|end"
                 android:src="@drawable/blue_circle"/>
    </LinearLayout>

    <LinearLayout android:layout_width="0dp"
                  android:layout_weight="1"
                  android:layout_height="wrap_content">
      <ImageView android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_gravity="right|end"
                 android:src="@drawable/blue_circle"/>
    </LinearLayout>
    <LinearLayout android:layout_width="0dp"
                  android:layout_weight="1"
                  android:layout_height="wrap_content">
      <ImageView android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_gravity="right|end"
                 android:src="@drawable/blue_circle"/>
    </LinearLayout>

    <LinearLayout android:layout_width="0dp"
                  android:layout_weight="1"
                  android:layout_height="wrap_content">
      <ImageView android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_gravity="right|end"
                 android:src="@drawable/blue_circle"/>
    </LinearLayout>
    <ImageView android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:layout_gravity="right|end"
               android:src="@drawable/blue_circle"/>

  </LinearLayout>
</RelativeLayout>

将此添加到 styles.xml-

<style name="flght.progress.style" parent="android:Widget.ProgressBar.Horizontal">
    <item name="android:indeterminateOnly">false</item>
    <item name="android:progressDrawable">@drawable/flight_cylinder_progress_bar</item>
    <item name="android:minHeight">8dip</item>
    <item name="android:maxHeight">24dip</item>
    <item name="android:minWidth">20dip</item>
    <item name="android:maxWidth">80dip</item>
  </style>

接下来在 drawable 文件夹中添加这个 flight_cylinder_progress_bar-

<?xml version="1.0" encoding="UTF-8"?>
<layer-list
  xmlns:android="http://schemas.android.com/apk/res/android">
  <item
    android:id="@android:id/background">
    <shape>
      <corners
        android:radius="5dip"/>
      <gradient
        android:angle="270"
        android:centerColor="#ffdddddd"
        android:centerY="0.50"
        android:endColor="#ffdddddd"
        android:startColor="#ffdddddd"/>
    </shape>
  </item>
  <item
    android:id="@android:id/secondaryProgress">
    <clip>
      <shape>
        <corners
          android:radius="5dip"/>
        <gradient
          android:angle="90"
          android:endColor="@color/orange_dark"
          android:startColor="@color/my_orange"/>
      </shape>
    </clip>
  </item>
  <item
    android:id="@android:id/progress">
    <clip>
      <shape>
        <corners
          android:radius="5dip"/>
        <gradient
          android:angle="90"
          android:endColor="@color/my_orange"
          android:startColor="@color/orange_dark"/>
      </shape>
    </clip>
  </item>
</layer-list>

最后 blue_circle.xmldrawable 文件夹中-

<?xml version="1.0" encoding="utf-8"?>
<shape
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:shape="oval">
  <solid android:color="@color/goibibo_blue"/>
  <size android:width="10dp"
        android:height="10dp"/>
</shape>

现在您可以简单地使用进度条来设置进度。

以上是输出。您现在可以简单地调整颜色。