如何在 Android 中创建一个可以旋转的圆形进度条?

我正在尝试创建一个圆形进度条。这就是我想要达到的

有一个灰色的背景圈。在它的顶部,会出现一个蓝色进度条,在60秒或任意数量的秒内沿圆形路径从0移动到360。

enter image description here

下面是我的示例代码。


为了做到这一点,在可绘制的“progressBarBG”中,我创建了一个图层列表,在该图层列表中,我给出了如下所示的两个项目。




















现在,第一个灰色环已经生成了。然而,蓝色环从可绘制对象的左侧开始,然后向右移动,就像线性进度条的工作方式一样。这就是它如何显示50%的进度,并用红色箭头显示方向。

enter image description here

我想按预期的那样在圆形路径中移动蓝色进度条。

336357 次浏览

https://github.com/passsy/android-HoloCircularProgressBar是这样做的库的一个例子。正如Tenfour04所述,它必须是有些自定义的,因为这是不直接开箱即用的。如果这个库没有像您希望的那样运行,您可以对其进行分叉并修改细节,使其按照您的喜好工作。如果您实现了一些其他人可以重用的东西,您甚至可以提交一个pull请求来重新合并!

这是我的两个解决方案。

简短的回答:

我没有创建layer-list,而是将它分离为两个文件。一个用于ProgressBar,另一个用于它的背景。

这是ProgressDrawable文件(@drawable文件夹):circular_progress_bar.xml

<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromDegrees="270"
android:toDegrees="270">
<shape
android:innerRadiusRatio="2.5"
android:shape="ring"
android:thickness="1dp"
android:useLevel="true"><!-- this line fixes the issue for lollipop api 21 -->


<gradient
android:angle="0"
android:endColor="#007DD6"
android:startColor="#007DD6"
android:type="sweep"
android:useLevel="false" />
</shape>
</rotate>

这是它的background(@drawable文件夹):circle_shape.xml

<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="ring"
android:innerRadiusRatio="2.5"
android:thickness="1dp"
android:useLevel="false">


<solid android:color="#CCC" />


</shape>

最后,在你正在工作的布局中:

<ProgressBar
android:id="@+id/progressBar"
android:layout_width="200dp"
android:layout_height="200dp"
android:indeterminate="false"
android:progressDrawable="@drawable/circular_progress_bar"
android:background="@drawable/circle_shape"
style="?android:attr/progressBarStyleHorizontal"
android:max="100"
android:progress="65" />

结果如下:

result 1

长一点的回答:

使用继承android.view.View . xml的自定义视图

result 2

下面是完整的项目github上

尝试此方法来创建一个位图并将其设置为图像视图。

private void circularImageBar(ImageView iv2, int i) {




Bitmap b = Bitmap.createBitmap(300, 300,Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(b);
Paint paint = new Paint();


paint.setColor(Color.parseColor("#c4c4c4"));
paint.setStrokeWidth(10);
paint.setStyle(Paint.Style.STROKE);
canvas.drawCircle(150, 150, 140, paint);


paint.setColor(Color.parseColor("#FFDB4C"));
paint.setStrokeWidth(10);
paint.setStyle(Paint.Style.FILL);
final RectF oval = new RectF();
paint.setStyle(Paint.Style.STROKE);
oval.set(10,10,290,290);


canvas.drawArc(oval, 270, ((i*360)/100), false, paint);
paint.setStrokeWidth(0);
paint.setTextAlign(Align.CENTER);
paint.setColor(Color.parseColor("#8E8E93"));
paint.setTextSize(140);


canvas.drawText(""+i, 150, 150+(paint.getTextSize()/3), paint);


iv2.setImageBitmap(b);
}

我是新来的,所以我不能评论,但我想分享懒惰修复。我也使用了Pedram最初的方法,并遇到了同样的Lollipop问题。但是另一篇文章中的alanv有一行修复。这是API21的某种错误或疏忽。字面上只是添加android:useLevel="true"到你的循环进度xml。Pedram的新方法仍然是正确的解决方案,但我只是想分享懒惰的解决方案。

@Pedram,你的旧解决方案实际上在棒棒糖中也很好(比新解决方案更好,因为它在任何地方都可用,包括在远程视图中),只需将你的circular_progress_bar.xml代码更改为:

<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromDegrees="270"
android:toDegrees="270">
<shape
android:innerRadiusRatio="2.5"
android:shape="ring"
android:thickness="1dp"
android:useLevel="true"> <!-- Just add this line -->
<gradient
android:angle="0"
android:endColor="#007DD6"
android:startColor="#007DD6"
android:type="sweep"
android:useLevel="false" />
</shape>
</rotate>

我实现了一个GitHub上的开源库 < >强CircularProgressBar < / >强,它完全是你想要的最简单的方式:

Gif demo CircularProgressBar

使用

要制作一个循环的ProgressBar,在你的布局XML中添加CircularProgressBar,并在你的投影仪中添加CircularProgressBar图书馆,或者你也可以通过Gradle获取它:

compile 'com.mikhaellopez:circularprogressbar:1.0.0'

XML

<com.mikhaellopez.circularprogressbar.CircularProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:background_progressbar_color="#FFCDD2"
app:background_progressbar_width="5dp"
app:progressbar_color="#F44336"
app:progressbar_width="10dp" />

您必须在XML中使用以下属性来更改CircularProgressBar。

属性:

  • app:progress (integer) >>默认0
  • app:progressbar_color (color) >>默认为黑色
  • app:background_progressbar_color (color) >>默认灰色
  • app:progressbar_width (dimension) >>默认7dp
  • app:background_progressbar_width (dimension) >>默认3dp

JAVA

CircularProgressBar circularProgressBar = (CircularProgressBar)findViewById(R.id.yourCircularProgressbar);
circularProgressBar.setColor(ContextCompat.getColor(this, R.color.progressBarColor));
circularProgressBar.setBackgroundColor(ContextCompat.getColor(this, R.color.backgroundProgressBarColor));
circularProgressBar.setProgressBarWidth(getResources().getDimension(R.dimen.progressBarWidth));
circularProgressBar.setBackgroundProgressBarWidth(getResources().getDimension(R.dimen.backgroundProgressBarWidth));
int animationDuration = 2500; // 2500ms = 2,5s
circularProgressBar.setProgressWithAnimation(65, animationDuration); // Default duration = 1500ms

Fork或下载此库>> <强> https://github.com/lopspower/CircularProgressBar < / >强

我已经用简单的方法做到了:

请检查屏幕截图相同。

 ></a></p>


<p><strong>CustomProgressBarActivity.java</strong>:</p>


<pre><code>public class CustomProgressBarActivity extends AppCompatActivity {


private TextView txtProgress;
private ProgressBar progressBar;
private int pStatus = 0;
private Handler handler = new Handler();


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_custom_progressbar);


txtProgress = (TextView) findViewById(R.id.txtProgress);
progressBar = (ProgressBar) findViewById(R.id.progressBar);


new Thread(new Runnable() {
@Override
public void run() {
while (pStatus <= 100) {
handler.post(new Runnable() {
@Override
public void run() {
progressBar.setProgress(pStatus);
txtProgress.setText(pStatus +

activity_custom_progressbar.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.skholingua.android.custom_progressbar_circular.MainActivity" >




<RelativeLayout
android:layout_width="wrap_content"
android:layout_centerInParent="true"
android:layout_height="wrap_content">


<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="250dp"
android:layout_height="250dp"
android:layout_centerInParent="true"
android:indeterminate="false"
android:max="100"
android:progress="0"
android:progressDrawable="@drawable/custom_progressbar_drawable"
android:secondaryProgress="0" />




<TextView
android:id="@+id/txtProgress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/progressBar"
android:layout_centerInParent="true"
android:textAppearance="?android:attr/textAppearanceSmall" />
</RelativeLayout>






</RelativeLayout>

custom_progressbar_drawable.xml:

<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromDegrees="-90"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="270" >


<shape
android:shape="ring"
android:useLevel="false" >
<gradient
android:centerY="0.5"
android:endColor="#FA5858"
android:startColor="#0099CC"
android:type="sweep"
android:useLevel="false" />
</shape>


</rotate>

希望这对你有所帮助。

我在我的博客demonuts.com上写了关于android中的循环进度条的详细示例。你也可以喜欢完整的源代码和解释在那里。

下面是我如何在没有任何库的纯代码中使用百分比制作循环进度条。

enter image description here

首先创建一个名为circular.xml的可绘制文件

<?xml version="1.0" encoding="utf-8"?>


<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/secondaryProgress">
<shape
android:innerRadiusRatio="6"
android:shape="ring"
android:thicknessRatio="20.0"
android:useLevel="true">




<gradient
android:centerColor="#999999"
android:endColor="#999999"
android:startColor="#999999"
android:type="sweep" />
</shape>
</item>


<item android:id="@android:id/progress">
<rotate
android:fromDegrees="270"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="270">


<shape
android:innerRadiusRatio="6"
android:shape="ring"
android:thicknessRatio="20.0"
android:useLevel="true">




<rotate
android:fromDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="360" />


<gradient
android:centerColor="#00FF00"
android:endColor="#00FF00"
android:startColor="#00FF00"
android:type="sweep" />


</shape>
</rotate>
</item>
</layer-list>

现在在你的activity_main.xml中添加以下内容:

  <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/dialog"
tools:context="com.example.parsaniahardik.progressanimation.MainActivity">


<ProgressBar


android:id="@+id/circularProgressbar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="250dp"
android:layout_height="250dp"
android:indeterminate="false"
android:max="100"
android:progress="50"
android:layout_centerInParent="true"
android:progressDrawable="@drawable/circular"
android:secondaryProgress="100"
/>


<ImageView
android:layout_width="90dp"
android:layout_height="90dp"
android:background="@drawable/whitecircle"
android:layout_centerInParent="true"/>


<TextView
android:id="@+id/tv"
android:layout_width="250dp"
android:layout_height="250dp"
android:gravity="center"
android:text="25%"
android:layout_centerInParent="true"
android:textColor="@color/colorPrimaryDark"
android:textSize="20sp" />


</RelativeLayout>

activity_main.xml中,我使用了一个白色背景的圆形图像来显示白色背景的百分比。这是图片:

enter image description here

您可以更改此图像的颜色,以设置自定义的百分比文本颜色。

现在,最后向MainActivity.java添加以下代码:

import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.animation.DecelerateInterpolator;
import android.widget.ProgressBar;
import android.widget.TextView;


public class MainActivity extends AppCompatActivity {


int pStatus = 0;
private Handler handler = new Handler();
TextView tv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);


Resources res = getResources();
Drawable drawable = res.getDrawable(R.drawable.circular);
final ProgressBar mProgress = (ProgressBar) findViewById(R.id.circularProgressbar);
mProgress.setProgress(0);   // Main Progress
mProgress.setSecondaryProgress(100); // Secondary Progress
mProgress.setMax(100); // Maximum Progress
mProgress.setProgressDrawable(drawable);


/*  ObjectAnimator animation = ObjectAnimator.ofInt(mProgress, "progress", 0, 100);
animation.setDuration(50000);
animation.setInterpolator(new DecelerateInterpolator());
animation.start();*/


tv = (TextView) findViewById(R.id.tv);
new Thread(new Runnable() {


@Override
public void run() {
// TODO Auto-generated method stub
while (pStatus < 100) {
pStatus += 1;


handler.post(new Runnable() {


@Override
public void run() {
// TODO Auto-generated method stub
mProgress.setProgress(pStatus);
tv.setText(pStatus + "%");


}
});
try {
// Sleep for 200 milliseconds.
// Just to display the progress slowly
Thread.sleep(8); //thread will take approx 1.5 seconds to finish
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
}
如果你想制作水平进度条,请点击这个链接,它有许多有价值的示例和源代码 http://www.skholingua.com/android-basic/user-interface/form-widgets/progressbar < / p >
package com.example.ankitrajpoot.myapplication;


import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.ProgressBar;




public class MainActivity extends Activity {


private ProgressBar spinner;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
spinner=(ProgressBar)findViewById(R.id.progressBar);
spinner.setVisibility(View.VISIBLE);
}
}

xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/loadingPanel"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center">


<ProgressBar
android:id="@+id/progressBar"


android:layout_width="48dp"
style="?android:attr/progressBarStyleLarge"
android:layout_height="48dp"
android:indeterminateDrawable="@drawable/circular_progress_bar"
android:indeterminate="true" />
</RelativeLayout>










<?xml version="1.0" encoding="utf-8"?>
<rotate
xmlns:android="http://schemas.android.com/apk/res/android"
android:pivotX="50%"
android:pivotY="50%"
android:fromDegrees="0"
android:toDegrees="1080">
<shape
android:shape="ring"
android:innerRadiusRatio="3"
android:thicknessRatio="8"
android:useLevel="false">


<size
android:width="56dip"
android:height="56dip" />


<gradient
android:type="sweep"
android:useLevel="false"
android:startColor="@android:color/transparent"
android:endColor="#1e9dff"
android:angle="0"
/>


</shape>
</rotate>

改变

android:useLevel="false"

android:useLevel="true"

为第二个sahpe id="@android:id/progress

希望它有用

下面是一个简单的自定义视图,用于显示圆圈进度。您可以修改和优化更多,以适合您的项目。

class CircleProgressBar @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
private val backgroundWidth = 10f
private val progressWidth = 20f


private val backgroundPaint = Paint().apply {
color = Color.LTGRAY
style = Paint.Style.STROKE
strokeWidth = backgroundWidth
isAntiAlias = true
}


private val progressPaint = Paint().apply {
color = Color.RED
style = Paint.Style.STROKE
strokeWidth = progressWidth
isAntiAlias = true
}


var progress: Float = 0f
set(value) {
field = value
invalidate()
}


private val oval = RectF()
private var centerX: Float = 0f
private var centerY: Float = 0f
private var radius: Float = 0f


override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
centerX = w.toFloat() / 2
centerY = h.toFloat() / 2
radius = w.toFloat() / 2 - progressWidth
oval.set(centerX - radius,
centerY - radius,
centerX + radius,
centerY + radius)
super.onSizeChanged(w, h, oldw, oldh)
}


override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
canvas?.drawCircle(centerX, centerY, radius, backgroundPaint)
canvas?.drawArc(oval, 270f, 360f * progress, false, progressPaint)
}
}

示例使用

xml

<com.example.androidcircleprogressbar.CircleProgressBar
android:id="@+id/circle_progress"
android:layout_width="200dp"
android:layout_height="200dp" />

芬兰湾的科特林

class MainActivity : AppCompatActivity() {
val TOTAL_TIME = 10 * 1000L


override fun onCreate(savedInstanceState: Bundle?) {
...


timeOutRemoveTimer.start()
}


private var timeOutRemoveTimer = object : CountDownTimer(TOTAL_TIME, 10) {
override fun onFinish() {
circle_progress.progress = 1f
}


override fun onTick(millisUntilFinished: Long) {
circle_progress.progress = (TOTAL_TIME - millisUntilFinished).toFloat() / TOTAL_TIME
}
}
}

结果

在材质组件库中,你可以使用CircularProgressIndicator:

喜欢的东西:

<com.google.android.material.progressindicator.CircularProgressIndicator
app:indicatorColor="@color/...."
app:trackColor="@color/...."
app:indicatorSize="64dp"/>

你可以使用这些属性:

  • indicatorSize:定义圆形进度指示器的半径
  • trackColor:用于进度轨道的颜色。如果没有定义,它将被设置为indicatorColor并应用主题中的android:disabledAlpha
  • indicatorColor:在确定/不确定模式下用于指示器的单一颜色。默认情况下,它使用主题原色

enter image description here

使用progressIndicator.setProgressCompat((int) value, true);更新指示器中的值。

注意:它至少需要版本1.3.0-alpha04

好消息是现在材料设计库也支持循环进度条:

<com.google.android.material.progressindicator.CircularProgressIndicator
android:layout_width="wrap_content"
android:layout_height="wrap_content" />

有关此的更多信息,请参阅在这里

enter image description here

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ProgressBar
android:id="@+id/progress_circular_id"
android:layout_width="250dp"
android:layout_height="250dp"
android:layout_centerInParent="true"
android:indeterminate="false"
android:progress="30"
android:progressDrawable="@drawable/circular_progress_bar"
android:background="@drawable/circle_shape"
style="?android:attr/progressBarStyleHorizontal"
android:max="100">
</ProgressBar>
<TextView
android:id="@+id/textview_progress_status_id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="50%"
android:layout_centerInParent="true"
android:textStyle="bold"
android:textColor="@color/blue"
android:textSize="35dp">
</TextView>


<Button
android:id="@+id/check"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="50dp"
android:text="click me"
android:textColor="@color/white"
android:layout_below="@+id/progress_circular_id"
android:layout_centerHorizontal="true"
>
</Button>
</RelativeLayout>

创建一个名为circle_shape.xml的可绘制文件

<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="ring"
android:innerRadiusRatio="2.5"
android:thickness="25dp"
android:useLevel="false">
<solid android:color="#CCC" />


</shape>

circular_progress_bar.xml创建一个文件

<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromDegrees="270"
android:toDegrees="270">
<shape
android:innerRadiusRatio="2.5"
android:shape="ring"
android:thickness="25dp"
android:useLevel="true"><!-- this line fixes the issue for lollipop api 21 -->


<gradient
android:angle="0"
android:endColor="#007DD6"
android:startColor="#007DD6"
android:type="sweep"
android:useLevel="false" />
</shape>
</rotate>

在java文件为例,目的使用fragmet。

public class FragmentRegistration extends BaseFragmentHelper {
View registrationFragmentView;
ProgressBar progressBar;
Button button;
int count=0;
@Override
public void onAttachFragment(@NonNull Fragment childFragment) {
super.onAttachFragment(childFragment);
}


@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}


@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
registrationFragmentView = inflater.inflate(R.layout.new_device_registration, container, false);
progressBar=(ProgressBar)registrationFragmentView.findViewById(R.id.progress_circular_id);
button=(Button) registrationFragmentView.findViewById(R.id.check);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
count=count+10;
progressBar.setProgress(count);
}
});
return registrationFragmentView;
}


@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}


@Override
public void onStart() {
super.onStart();
}


@Override
public void onResume() {
super.onResume();
}


@Override
public void onDetach() {
super.onDetach();
}


@Override
public void onDestroy() {
super.onDestroy();
}


@Override
public void onDestroyView() {
super.onDestroyView();
}
}

如果你想在一个时钟方向上设置进度,那么使用下面的图像来设置progressDrawble xml中的fromDegreetoDegree的值。

enter image description here

<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromDegrees="270"
android:toDegrees="-90">
<shape
android:innerRadiusRatio="2"
android:shape="ring"
android:thickness="1dp">
<gradient
android:angle="0"
android:endColor="#007DD6"
android:startColor="#007DD6"
android:type="sweep" />
</shape>
</rotate>

这段代码将让你的进度逆时针和从顶部开始。

.

.

.

你可以使用这个库https://github.com/xYinKio/ArcCircleProgressBar

这是最灵活的循环进度条之一

这张照片显示了lib的权力