如何在Android中创建一个在其上旋转的圆形进度条?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21333866/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to Create a circular progressbar in Android which rotates on it?
提问by Saurav Srivastava
I am trying to create a rounded progressbar. This is what I want to achieve
我正在尝试创建一个圆形的进度条。这就是我想要实现的
There is a grey color background ring. On top of it, a blue color progressbar appears which moves in a circular path from 0 to 360 in 60 or whatever amount of seconds.
有一个灰色的背景环。在它的顶部,会出现一个蓝色进度条,它在 60 秒或任何秒数内从 0 到 360 的圆形路径中移动。
Here is my example code.
这是我的示例代码。
<ProgressBar
android:id="@+id/ProgressBar"
android:layout_width="match_parent"
android:layout_height="match_parent"
style="?android:attr/progressBarStyleLarge"
android:indeterminateDrawable="@drawable/progressBarBG"
android:progress="50"
/>
To do this, in the drawable "progressBarBG", I am creating a layerlist and inside that layer list I am giving two items as shown.
为此,在可绘制的“progressBarBG”中,我创建了一个图层列表,并在该图层列表中提供了两个项目,如图所示。
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/background">
<shape
android:shape="ring"
android:innerRadius="64dp"
android:thickness="8dp"
android:useLevel="false">
<solid android:color="@color/grey" />
</shape>
</item>
<item android:id="@android:id/progress">
<clip>
<shape
android:shape="ring"
android:innerRadius="64dp"
android:thickness="8dp"
android:useLevel="false">
<solid android:color="@color/blue" />
</shape>
</clip>
</item>
Now, the first grey ring is generated fine. The blue ring however starts from the left of the drawable and goes to the right just like how a linear progressbar works. This is how it shows at 50% progress with the red color arrow showing direction.
现在,第一个灰色环生成得很好。然而,蓝色环从 drawable 的左侧开始,然后像线性进度条一样向右移动。这是它以 50% 的进度显示的方式,红色箭头表示方向。
I want to move the blue progressbar in circular path as expected.
我想按预期在圆形路径中移动蓝色进度条。
回答by M. Reza Nasirloo
Here are my two solutions.
这是我的两个解决方案。
Short answer:
简短的回答:
Instead of creating a layer-list
, I separated it into two files. One for ProgressBar
and one for its background.
layer-list
我没有创建,而是将其分成两个文件。一为ProgressBar
一为背景。
This is the ProgressDrawable
file (@drawable folder): circular_progress_bar.xml
这是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>
And this is for its background
(@drawable folder): circle_shape.xml
这是它的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>
And at the end, inside the layout that you're working:
最后,在您正在工作的布局中:
<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" />
Here's the result:
结果如下:
Long Answer:
长答案:
Use a custom view which inherits the android.view.View
使用继承了 android.view.View
Here is the full project on github
这是github上的完整项目
回答by Hiren Patel
I have done with easy way:
我用简单的方法完成了:
Please check screen shot for the same.
请检查相同的屏幕截图。
CustomProgressBarActivity.java:
CustomProgressBarActivity.java:
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 + " %");
}
});
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
pStatus++;
}
}
}).start();
}
}
activity_custom_progressbar.xml:
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:
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>
Hope this will help you.
希望这会帮助你。
回答by Parsania Hardik
I have written detailed example on circular progress bar in androidhere on my blog demonuts.com. You can also fond full source code and explanation there.
我在我的博客demonuts.com上写了关于android 循环进度条的详细示例。您还可以在那里喜欢完整的源代码和解释。
Here's how I made circular progressbar with percentage inside circle in pure code without any library.
这是我在没有任何库的纯代码中制作圆形进度条的方法。
first create a drawable file called circular.xml
首先创建一个名为的可绘制文件 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>
Now in your activity_main.xml
add following:
现在在您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>
In activity_main.xml
I have used one circular image with white background to show white background around percentage. Here is the image:
在activity_main.xml
我使用了一张白色背景的圆形图像来显示百分比周围的白色背景。这是图像:
You can change color of this image to set custom color around percentage text.
您可以更改此图像的颜色以设置百分比文本周围的自定义颜色。
Now finally add following code to MainActivity.java
:
现在最后将以下代码添加到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();
}
}
If you want to make horizontal progressbar, follow this link, it has many valuable examples with source code:
http://www.skholingua.com/android-basic/user-interface/form-widgets/progressbar
如果你想制作水平进度条,请点击这个链接,它有很多有价值的源代码示例:http:
//www.skholingua.com/android-basic/user-interface/form-widgets/progressbar
回答by lopez.mikhael
I realized a Open Source library on GitHubCircularProgressBarthat does exactly what you want the simplest way possible:
我在 GitHub CircularProgressBar上实现了一个开源库,它可以以最简单的方式完成您想要的操作:
USAGE
用法
To make a circular ProgressBar add CircularProgressBarin your layout XML and add CircularProgressBar libraryin your projector or you can also grab it via Gradle:
为了使一个圆形进度添加CircularProgressBar在布局XML,并添加CircularProgressBar库在您的投影机,或者您也可以通过摇篮抓住它:
compile 'com.mikhaellopez:circularprogressbar:1.0.0'
XML
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" />
You must use the following properties in your XML to change your CircularProgressBar.
您必须在 XML 中使用以下属性来更改 CircularProgressBar。
Properties:
特性:
app:progress
(integer) >> default 0app:progressbar_color
(color) >> default BLACKapp:background_progressbar_color
(color) >> default GRAYapp:progressbar_width
(dimension) >> default 7dpapp:background_progressbar_width
(dimension) >> default 3dp
app:progress
(整数)>> 默认 0app:progressbar_color
(颜色)>> 默认黑色app:background_progressbar_color
(颜色)>>默认灰色app:progressbar_width
(尺寸)>> 默认 7dpapp:background_progressbar_width
(尺寸)>> 默认 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 or Download this library here >> https://github.com/lopspower/CircularProgressBar
在此处分叉或下载此库 >> https://github.com/lopspower/CircularProgressBar
回答by Phan Van Linh
Here is a simple customview for display circle progress. You can modify and optimize more to suitable for your project.
这是一个用于显示圆圈进度的简单自定义视图。您可以修改和优化更多以适合您的项目。
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)
}
}
Example using
使用示例
xml
xml
<com.example.androidcircleprogressbar.CircleProgressBar
android:id="@+id/circle_progress"
android:layout_width="200dp"
android:layout_height="200dp" />
kotlin
科特林
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
}
}
}
Result
结果
回答by Miao Liu
I'm new so I can't comment but thought to share the lazy fix. I use Pedram's original approach as well, and just ran into the same Lollipop issue. But alanvover in another post had a one line fix. Its some kind of bug or oversight in API21. Literally just add android:useLevel="true"
to your circle progress xml. Pedram's new approach is still the proper fix, but I just thought I share the lazy fix as well.
我是新来的,所以我不能发表评论,但想分享这个懒惰的修复。我也使用 Pedram 的原始方法,但遇到了同样的 Lollipop 问题。但是alanv在另一篇文章中有一个一行修复。它是 API21 中的某种错误或疏忽。从字面上看,只需添加android:useLevel="true"
到您的圈子进度 xml。Pedram 的新方法仍然是正确的修复,但我只是想我也分享了懒惰的修复。
回答by mani
try this method to create a bitmap and set it to image view.
试试这个方法来创建一个位图并将其设置为图像视图。
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);
}
回答by Travis
https://github.com/passsy/android-HoloCircularProgressBaris one example of a library that does this. As Tenfour04 stated, it will have to be somewhatcustom, in that this is not supported directly out of the box. If this library doesn't behave as you wish, you can fork it and modify the details to make it work to your liking. If you implement something that others can then reuse, you could even submit a pull request to get that merged back in!
https://github.com/passsy/android-HoloCircularProgressBar是执行此操作的库的一个示例。正如 Tenfour04 所说,它必须有点自定义,因为这不直接支持开箱即用。如果这个库没有按照你的意愿运行,你可以 fork 它并修改细节以使其按你的喜好工作。如果你实现了一些其他人可以重用的东西,你甚至可以提交一个拉取请求来合并它!
回答by Ankit Rajpoot
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
<?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>
回答by mim
@Pedram, your old solution works actually fine in lollipop too (and better than new one since it's usable everywhere, including in remote views) just change your circular_progress_bar.xml
code to this:
@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>