Is there any possibility to show a spinning progress bar in a button? e.g. as background drawable?
Progress Button is one of the options to show non-blocking progress in the app that Google introduced in its Material Guidelines.
Android ProgressBar is a graphical view indicator that shows some progress. Android progress bar displays a bar representing the completing of the task. Progress bar in android is useful since it gives the user an idea of time to finish its task.
Android Progress Bar using ProgressDialog. Progress bars are used to show progress of a task. For example, when you are uploading or downloading something from the internet, it is better to show the progress of download/upload to the user. In android there is a class called ProgressDialog that allows you to create progress bar.
android: progress – It sets the default progress of the progress bar, which can be set from 0 to max. android:interpolar – It is used to set an acceleration curve for the indeterminate progress bars. android: min – It defines the minimum value for the progress bar. android: progressTint – It applies Tint on progress indicator in the progress bar.
Progress bars are used to show progress of a task. For example, when you are uploading or downloading something from the internet, it is better to show the progress of download/upload to the user.
In this example, we will create a progress bar using the ProgressDialog class. In the activity_main.xml file, we will drag one button from the pallet. In the MainActivity.java file, we will write the code to display the progress bar dialog box.
I was having the same problem, so I created a specialized button for this: LoadingProgressButton
Include the button like this:
<br.com.simplepass.loading_button_lib.CircularProgressButton
android:id="@+id/btn_id"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/circular_border_shape"
app:spinning_bar_width="4dp" <!-- Optional -->
app:spinning_bar_color="#FFF" <!-- Optional -->
app:spinning_bar_padding="6dp" <!-- Optional -->
And use it like this:
CircularProgressButton btn = (CircularProgressButton) findViewById(R.id.btn_id)
btn.startAnimation();
[do some async task. When it finishes]
//You can choose the color and the image after the loading is finished
btn.doneLoagingAnimation(fillColor, bitmap);
[or just revert de animation]
btn.revertAnimation();
Yes.
You can create an AnimationDrawable, as described here, and then use the drawableLeft
tag (for example) in your button's XML. like so:
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/your_background_drawable_resource"
android:drawableLeft="@drawable/your_animation_drawable_resource"
android:text="@string/your_text_res">
</Button>
Yes... Just wrap around both the button and progressBar inside a Relative Layout, like so...
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:weightSum="1">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal">
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/progressBar"
android:layout_gravity="right"
android:layout_alignTop="@+id/btnConnect"
android:layout_alignRight="@+id/btnConnect"
android:layout_alignEnd="@+id/btnConnect" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Connect"
android:id="@+id/btnConnect"
android:layout_gravity="center_horizontal"
android:layout_marginTop="30dp"
android:width="200dp"
android:focusable="false"
android:focusableInTouchMode="false" />
</RelativeLayout>
<TextView
android:id="@+id/txtConnectStatus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/btnConnect"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:text="Status : Not connected"
android:textSize="12dp"
android:layout_gravity="center_horizontal" />
<LinearLayout
android:orientation="vertical"
Wanted to post the sample image, but I don't have enough reputation just yet... ;)
I made a sample code like below.. I hope that my codes help you :)
[main.xml]
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center"
>
<Button
android:id="@+id/wheel_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/icon_spin_animation"
/>
</LinearLayout>
[icon_spin_animation.xml]
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/selected" android:oneshot="false">
<item android:drawable="@drawable/wheel_db_update01" android:duration="50"/>
<item android:drawable="@drawable/wheel_db_update02" android:duration="50"/>
<item android:drawable="@drawable/wheel_db_update03" android:duration="50"/>
<item android:drawable="@drawable/wheel_db_update04" android:duration="50"/>
<item android:drawable="@drawable/wheel_db_update05" android:duration="50"/>
<item android:drawable="@drawable/wheel_db_update06" android:duration="50"/>
</animation-list>
[Activity Code]
public class ProgressOnTheButtonActivity extends Activity implements OnClickListener {
/** Called when the activity is first created. */
AnimationDrawable mFrameAnimation = null;
boolean mbUpdating = false;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button btnWheel = (Button)findViewById(R.id.wheel_button);
btnWheel.setOnClickListener(this);
mFrameAnimation = (AnimationDrawable) btnWheel.getBackground();
}
public void onClick(View v) {
if(v.getId() == R.id.wheel_button) {
if(!mbUpdating) {
mbUpdating = true;
new AsyncTaskForUpdateDB().execute("");
}
}
}
private class AsyncTaskForUpdateDB extends AsyncTask<String, Integer, ResultOfAsyncTask> {
@Override
protected void onPreExecute() {
mFrameAnimation.start();
super.onPreExecute();
}
@Override
protected ResultOfAsyncTask doInBackground(String... strData) {
ResultOfAsyncTask result = new ResultOfAsyncTask();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return result;
}
@Override
protected void onPostExecute(ResultOfAsyncTask result) {
mFrameAnimation.stop();
mbUpdating = false;
}
@Override
protected void onCancelled() {
mFrameAnimation.stop();
mbUpdating = false;
super.onCancelled();
}
@Override
protected void onProgressUpdate(Integer... progress) {
}
}
private class ResultOfAsyncTask {
int iErrorCode = 0;
}
}
To make Animatable
drawables work, you need to extend the Button
class and call Animatable.start()
for drawables. I've made an implementation for this:
package com.example.yourapplication;
import android.content.Context;
import android.graphics.drawable.Animatable;
import android.graphics.drawable.Drawable;
import android.support.v7.widget.AppCompatButton;
import android.util.AttributeSet;
public class AnimateCompoundDrawableButton extends AppCompatButton {
public AnimateCompoundDrawableButton(Context context) {
super(context);
}
public AnimateCompoundDrawableButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
public AnimateCompoundDrawableButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public void setCompoundDrawables(Drawable left, Drawable top, Drawable right, Drawable bottom) {
super.setCompoundDrawables(left, top, right, bottom);
startIfAnimatable(left);
startIfAnimatable(top);
startIfAnimatable(right);
startIfAnimatable(bottom);
}
@Override
public void setCompoundDrawablesRelative(Drawable start, Drawable top, Drawable end, Drawable bottom) {
super.setCompoundDrawablesRelative(start, top, end, bottom);
startIfAnimatable(start);
startIfAnimatable(top);
startIfAnimatable(end);
startIfAnimatable(bottom);
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
// Makes a copy of the array, however we cannot do this otherwise.
for (Drawable drawable : getCompoundDrawables()) {
startIfAnimatable(drawable);
}
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
// Makes a copy, however we cannot do this otherwise.
for (Drawable drawable : getCompoundDrawables()) {
stopIfAnimatable(drawable);
}
}
private void startIfAnimatable(Drawable drawable) {
if (drawable instanceof Animatable) {
((Animatable) drawable).start();
}
}
private void stopIfAnimatable(Drawable drawable) {
if (drawable instanceof Animatable) {
((Animatable) drawable).stop();
}
}
}
I have solved this problem by this way: first I have added progressBar
and Button
to common FrameLayout
.
<FrameLayout
android:layout_width="match_parent"
android:layout_height="75dp"
android:background="@color/white"
android:layout_marginRight="20dp"
android:layout_marginLeft="20dp">
<Button
android:id="@+id/buttonOnOff"
android:layout_width="match_parent"
android:layout_height="75dp"
android:text="Включить"
android:layout_gravity="center"
android:visibility="visible"
android:textColor="#FFFFFF"
android:onClick="onClickIn"
tools:ignore="OnClick" />
<ProgressBar
android:id="@+id/loading"
android:layout_width="35dp"
android:layout_height="35dp"
android:layout_gravity="center"
android:indeterminate="true"
android:indeterminateTintMode="src_atop"
android:theme="@style/ActionBarProgress"
/>
</FrameLayout>
And after that I have turned on and turned off visibility of progressBar
and changed text of Button
where I need it.
final Button buttonOnOff = findViewById(R.id.buttonOnOff);
final ProgressBar pB = findViewById(R.id.pB);
buttonOnOff.setEnabled(false);
buttonOnOff.setText("");
pB.setVisibility(false);
Another Option is to use the nifty Spezi-Views, it contains a ProgressButton which is quite easy to use:
<de.halfreal.spezi.views.ProgressButton
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Press me"
app:selectedText="I am loaded"
app:unselectedText="Press me again"
app:loadingDrawable="@drawable/spinner"
/>
and in code:
...
//show a rotation spinner, and no text (or the loading text)
progressButton.enableLoadingState();
//show no animation, but the selected/ unselected text
progressButton.disableLoadingState();
...
With Jetpack Compose you can use something like:
var progressIndicatorVisible by remember { mutableStateOf(false) }
Button(onClick = {
scope.launch {
progressIndicatorVisible = true
// Just for example
delay(5000)
progressIndicatorVisible = false
}
}, modifier = Modifier.animateContentSize()){
if (progressIndicatorVisible) {
CircularProgressIndicator(
color = White,
strokeWidth = 2.dp,
modifier = Modifier.size(15.dp)
)
}
Text ("Button",
modifier = Modifier.padding(start = if (progressIndicatorVisible) 8.dp else 0.dp))
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With