XML如何使用progressDrawable属性将水平进度条修改为圆形进度条?
How does XML modify a horizontal progress bar to a circular one with progressDrawable property?
我有这个 ProgressBar
xml:
<ProgressBar
android:id="@+id/progressBar"
style="?android:progressBarStyleHorizontal"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_marginBottom="32dp"
android:progress="0"
android:progressDrawable="@drawable/bg_circular_progress_bar"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:elevation="11dp"/>
可以看出,style="?android:progressBarStyleHorizontal"
指定它是一个单杠。但是,对于 progressDrawable
属性,我可以通过以下可绘制文件以某种方式将其形状更改为圆形:
<?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="4dp"
android:useLevel="true">
<solid android:color="@color/colorPrimary" />
</shape>
- 当进度为 100% 时,该可绘制文件如何将水平的东西变成圆形的东西,它如何决定如何将进度条从 0 度设置为 360 度以形成一个完整的环?另外,有没有办法操纵动画的开始(比如从正 x 轴 90 度开始)?
- 如何制作另一个自定义形状,例如从底部到顶部填充了不变背景色的矩形(以表示填充前的矩形形状)?
- How does that drawable file change a horizontal thing into a circular thing and how does it decide how to animate the progress bar from 0degrees to 360degress forming a full ring when the progress is 100%?
当您指定 style="?android:progressBarStyleHorizontal"
时,您实际上是在说 ProgressBar 将是确定的。从 documentation for ProgressBar:
To indicate determinate progress, you set the style of the progress bar to R.style.Widget_ProgressBar_Horizontal
and set the amount of progress.
默认情况下,ProgressBar 是水平的,但正如您所指出的,可以使用您的可绘制文件将其更改为圆形。
<shape
android:shape="ring"
android:innerRadiusRatio="2.5"
android:thickness="4dp"
android:useLevel="true">
<solid android:color="@color/colorPrimary" />
</shape>
注意行 android:useLevel="true"
。这指定 drawable 可以接受范围从 0 到 100 的 level。drawable 知道根据级别集绘制多少自身:0 是不绘制,100 是绘制 100%。通过更改进度,您正在更改为可绘制对象设置的级别。尝试设置 android:useLevel="false"
看看会发生什么。
- Also, is there a way to manipulate the start of the animation (like from 90degrees from the positive x-axis)?
在 XML 中,设置 android:rotation="90"
使环从底部开始。
- How do I make another custom shape, like a rectangle being filled from bottom to top with a background color (to signify the rectangle shape before being filled) that doesn't change?
有几种(也许更多)方法可以做到这一点。一种方法是定义一个 layer-list drawable 来定义背景矩形和可绘制比例的进度矩形。由于 ProgressBar 依赖于它们,因此必须指定 ID。
<layer-list>
<item
android:id="@android:id/background">
<shape android:shape="rectangle">
<solid android:color="@android:color/darker_gray" />
</shape>
</item>
<item
android:id="@android:id/progress">
<scale
android:scaleHeight="100%"
android:scaleGravity="bottom">
<shape android:shape="rectangle">
<solid android:color="@android:color/holo_red_light" />
</shape>
</scale>
</item>
您还可以在图层列表中使用剪辑可绘制对象:
<layer-list>
<item android:id="@android:id/background">
<shape android:shape="rectangle">
<solid android:color="@android:color/darker_gray" />
</shape>
</item>
<item android:id="@android:id/progress">
<clip
android:clipOrientation="vertical"
android:gravity="bottom">
<shape android:shape="rectangle">
<solid android:color="@android:color/holo_red_light" />
</shape>
</clip>
</item>
</layer-list>
这是一个将所有这些放在一起的示例布局:
activity_main.xml
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ProgressBar
android:id="@+id/progressBar"
style="?android:progressBarStyleHorizontal"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_marginTop="16dp"
android:progress="0"
android:progressDrawable="@drawable/bg_circular_progress_bar"
android:rotation="90"
app:layout_constraintVertical_chainStyle="packed"
app:layout_constraintBottom_toTopOf="@+id/progressBar2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ProgressBar
android:id="@+id/progressBar2"
style="?android:progressBarStyleHorizontal"
android:layout_width="20dp"
android:layout_height="80dp"
android:layout_marginTop="16dp"
android:progress="0"
android:progressDrawable="@drawable/rectangular_progress_with_scale_drawable"
app:layout_constraintBottom_toTopOf="@+id/progressBar3"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/progressBar" />
<ProgressBar
android:id="@+id/progressBar3"
style="?android:progressBarStyleHorizontal"
android:layout_width="20dp"
android:layout_height="80dp"
android:layout_marginTop="16dp"
android:progress="0"
android:progressDrawable="@drawable/rectangular_progress_with_clip_drawable"
app:layout_constraintBottom_toTopOf="@+id/textView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/progressBar2" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="0/ 100"
app:layout_constraintBottom_toTopOf="@+id/button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/progressBar3" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:onClick="onClick"
android:text="Start"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView" />
</androidx.constraintlayout.widget.ConstraintLayout>
MainActivity.kt
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
fun onClick(view: View) {
view.isEnabled = false
var progress = 0
val handler = Handler()
Thread(Runnable {
while (progress < 100) {
progress += 5
handler.post {
progressBar.progress = progress
progressBar2.progress = progress
progressBar3.progress = progress
textView.text = "$progress/ ${progressBar.max}"
}
try {
Thread.sleep(100)
} catch (e: InterruptedException) {
e.printStackTrace()
}
}
runOnUiThread { view.isEnabled = true }
}).start()
}
}
我有这个 ProgressBar
xml:
<ProgressBar
android:id="@+id/progressBar"
style="?android:progressBarStyleHorizontal"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_marginBottom="32dp"
android:progress="0"
android:progressDrawable="@drawable/bg_circular_progress_bar"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:elevation="11dp"/>
可以看出,style="?android:progressBarStyleHorizontal"
指定它是一个单杠。但是,对于 progressDrawable
属性,我可以通过以下可绘制文件以某种方式将其形状更改为圆形:
<?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="4dp"
android:useLevel="true">
<solid android:color="@color/colorPrimary" />
</shape>
- 当进度为 100% 时,该可绘制文件如何将水平的东西变成圆形的东西,它如何决定如何将进度条从 0 度设置为 360 度以形成一个完整的环?另外,有没有办法操纵动画的开始(比如从正 x 轴 90 度开始)?
- 如何制作另一个自定义形状,例如从底部到顶部填充了不变背景色的矩形(以表示填充前的矩形形状)?
- How does that drawable file change a horizontal thing into a circular thing and how does it decide how to animate the progress bar from 0degrees to 360degress forming a full ring when the progress is 100%?
当您指定 style="?android:progressBarStyleHorizontal"
时,您实际上是在说 ProgressBar 将是确定的。从 documentation for ProgressBar:
To indicate determinate progress, you set the style of the progress bar to
R.style.Widget_ProgressBar_Horizontal
and set the amount of progress.
默认情况下,ProgressBar 是水平的,但正如您所指出的,可以使用您的可绘制文件将其更改为圆形。
<shape
android:shape="ring"
android:innerRadiusRatio="2.5"
android:thickness="4dp"
android:useLevel="true">
<solid android:color="@color/colorPrimary" />
</shape>
注意行 android:useLevel="true"
。这指定 drawable 可以接受范围从 0 到 100 的 level。drawable 知道根据级别集绘制多少自身:0 是不绘制,100 是绘制 100%。通过更改进度,您正在更改为可绘制对象设置的级别。尝试设置 android:useLevel="false"
看看会发生什么。
- Also, is there a way to manipulate the start of the animation (like from 90degrees from the positive x-axis)?
在 XML 中,设置 android:rotation="90"
使环从底部开始。
- How do I make another custom shape, like a rectangle being filled from bottom to top with a background color (to signify the rectangle shape before being filled) that doesn't change?
有几种(也许更多)方法可以做到这一点。一种方法是定义一个 layer-list drawable 来定义背景矩形和可绘制比例的进度矩形。由于 ProgressBar 依赖于它们,因此必须指定 ID。
<layer-list>
<item
android:id="@android:id/background">
<shape android:shape="rectangle">
<solid android:color="@android:color/darker_gray" />
</shape>
</item>
<item
android:id="@android:id/progress">
<scale
android:scaleHeight="100%"
android:scaleGravity="bottom">
<shape android:shape="rectangle">
<solid android:color="@android:color/holo_red_light" />
</shape>
</scale>
</item>
您还可以在图层列表中使用剪辑可绘制对象:
<layer-list>
<item android:id="@android:id/background">
<shape android:shape="rectangle">
<solid android:color="@android:color/darker_gray" />
</shape>
</item>
<item android:id="@android:id/progress">
<clip
android:clipOrientation="vertical"
android:gravity="bottom">
<shape android:shape="rectangle">
<solid android:color="@android:color/holo_red_light" />
</shape>
</clip>
</item>
</layer-list>
这是一个将所有这些放在一起的示例布局:
activity_main.xml
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ProgressBar
android:id="@+id/progressBar"
style="?android:progressBarStyleHorizontal"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_marginTop="16dp"
android:progress="0"
android:progressDrawable="@drawable/bg_circular_progress_bar"
android:rotation="90"
app:layout_constraintVertical_chainStyle="packed"
app:layout_constraintBottom_toTopOf="@+id/progressBar2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ProgressBar
android:id="@+id/progressBar2"
style="?android:progressBarStyleHorizontal"
android:layout_width="20dp"
android:layout_height="80dp"
android:layout_marginTop="16dp"
android:progress="0"
android:progressDrawable="@drawable/rectangular_progress_with_scale_drawable"
app:layout_constraintBottom_toTopOf="@+id/progressBar3"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/progressBar" />
<ProgressBar
android:id="@+id/progressBar3"
style="?android:progressBarStyleHorizontal"
android:layout_width="20dp"
android:layout_height="80dp"
android:layout_marginTop="16dp"
android:progress="0"
android:progressDrawable="@drawable/rectangular_progress_with_clip_drawable"
app:layout_constraintBottom_toTopOf="@+id/textView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/progressBar2" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="0/ 100"
app:layout_constraintBottom_toTopOf="@+id/button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/progressBar3" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:onClick="onClick"
android:text="Start"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView" />
</androidx.constraintlayout.widget.ConstraintLayout>
MainActivity.kt
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
fun onClick(view: View) {
view.isEnabled = false
var progress = 0
val handler = Handler()
Thread(Runnable {
while (progress < 100) {
progress += 5
handler.post {
progressBar.progress = progress
progressBar2.progress = progress
progressBar3.progress = progress
textView.text = "$progress/ ${progressBar.max}"
}
try {
Thread.sleep(100)
} catch (e: InterruptedException) {
e.printStackTrace()
}
}
runOnUiThread { view.isEnabled = true }
}).start()
}
}