Android自定义ProgressBar及自定义不确定进度条的实现与使用方法咨询
Hey there! Let's walk through how to build custom ProgressBars in Android, covering both determinate (the one with a clear progress percentage) and indeterminate (the spinning/animated one for unknown wait times) versions. I'll include practical code snippets you can copy-paste and tweak for your app.
Determinate progress bars are perfect for scenarios like file downloads, uploads, or tasks where you know exactly how much progress has been made. Here's how to customize yours:
Step 1: Create a Custom Progress Drawable
First, make a new drawable file in res/drawable/ (name it custom_progress_bar.xml). We'll use a layer-list to stack the background track and the progress fill:
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <!-- Background track --> <item android:id="@android:id/background"> <shape> <corners android:radius="8dp" /> <solid android:color="#E0E0E0" /> </shape> </item> <!-- Progress fill --> <item android:id="@android:id/progress"> <clip> <shape> <corners android:radius="8dp" /> <solid android:color="#2196F3" /> <!-- Use ?attr/colorPrimary for theme consistency --> </shape> </clip> </item> </layer-list>
Step 2: Use the Custom ProgressBar in Your Layout
Add the ProgressBar to your layout file, and point its progressDrawable to the drawable we just created. Make sure to use the horizontal style since we're making a determinate bar:
<ProgressBar android:id="@+id/customProgressBar" style="@android:style/Widget.ProgressBar.Horizontal" android:layout_width="match_parent" android:layout_height="8dp" android:layout_margin="16dp" android:progressDrawable="@drawable/custom_progress_bar" android:max="100" />
Step 3: Control Progress in Code
In your Activity/Fragment, you can update the progress programmatically. For example, simulating a download with a coroutine:
// In Kotlin val progressBar = findViewById<ProgressBar>(R.id.customProgressBar) // Simulate progress update lifecycleScope.launch { repeat(100) { progress -> delay(50) // Simulate work being done progressBar.setProgress(progress + 1, true) // The second parameter enables smooth animation } }
Indeterminate progress bars are for when you don't know how long a task will take—like loading data from a server. You can customize their animation or appearance in a few ways:
Method 1: Custom Rotating Drawable
Create a rotating shape drawable for a simple, customizable spinner. Make res/drawable/custom_indeterminate_progress.xml:
<rotate xmlns:android="http://schemas.android.com/apk/res/android" android:fromDegrees="0" android:toDegrees="360" android:pivotX="50%" android:pivotY="50%" android:repeatCount="infinite" android:duration="1000"> <!-- Adjust speed by changing duration --> <shape android:innerRadiusRatio="3" android:shape="ring" android:thicknessRatio="8" android:useLevel="false"> <gradient android:type="sweep" android:startColor="#2196F3" android:centerColor="#BB2196F3" android:endColor="#002196F3" android:angle="0" /> </shape> </rotate>
Then use it in your layout:
<ProgressBar android:id="@+id/customIndeterminateBar" android:layout_width="48dp" android:layout_height="48dp" android:indeterminateDrawable="@drawable/custom_indeterminate_progress" />
Method 2: Custom Property Animation
If you want a more unique animation (like pulsing or scaling), you can use property animations directly in code. For example, a pulsing spinner:
// In Kotlin val customSpinner = findViewById<View>(R.id.customSpinnerView) // Use a simple View as your spinner // Create scale animation val scaleAnimator = ObjectAnimator.ofPropertyValuesHolder( customSpinner, PropertyValuesHolder.ofFloat(View.SCALE_X, 0.8f, 1.2f), PropertyValuesHolder.ofFloat(View.SCALE_Y, 0.8f, 1.2f) ) scaleAnimator.duration = 800 scaleAnimator.repeatCount = ValueAnimator.INFINITE scaleAnimator.repeatMode = ValueAnimator.REVERSE // Create rotate animation val rotateAnimator = ObjectAnimator.ofFloat(customSpinner, View.ROTATION, 0f, 360f) rotateAnimator.duration = 1500 rotateAnimator.repeatCount = ValueAnimator.INFINITE // Play both animations together val animatorSet = AnimatorSet() animatorSet.playTogether(scaleAnimator, rotateAnimator) animatorSet.start()
For this, your layout would have a simple View (like an ImageView or a shaped View):
<View android:id="@+id/customSpinnerView" android:layout_width="48dp" android:layout_height="48dp" android:background="@drawable/round_spinner_shape" /> <!-- A simple circle shape drawable -->
Using the Custom Indeterminate ProgressBar
To show/hide it, just toggle its visibility:
// Show the spinner customIndeterminateBar.visibility = View.VISIBLE // Hide when task is done customIndeterminateBar.visibility = View.GONE
Pro Tips
- For theme consistency, use
?attr/colorPrimaryinstead of hardcoded colors—this will automatically adapt to light/dark themes. - Adjust animation durations to match your app's feel (faster for snappy apps, slower for more relaxed UIs).
- For accessibility, make sure to set
android:contentDescriptionso screen readers can announce what the progress bar is for.
内容的提问来源于stack exchange,提问作者Hossein Mansouri




