I need to display progress icon in button so that user can interact other GUI elements while background task is processing.
I have searched in Android developer site and found that we can use animated drawables but don't know how to use them. Please advise on the same.
The very simple way to do this without using the animated drawable is to use "PregressBar" component in the design layout xml. When u need to show it, just set it's visibility property to visible and when you need to hide it, u can set it's visibility property to GONE. But remember this is UI task so when u need to do this with non-UI thread, u need to use Handler to set the status of "ProgressBar" component at runtime.
Below id the component in the layout file.
<ProgressBar
android:id="#+id/progressBar1"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</ProgressBar>
Below is the code written in java file
ProgressBar prg;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main1);
prg=(ProgressBar)findViewById(R.id.ProgressBar1);
prg.setVisibility(ProgressBar.GONE);
}
public void start_background_process()
{
// starting the process
prg.setVisibility(ProgressBar.VISIBLE);
new Thread(new Runnable()
{ public void run()
{
// Do your background stuff here which takes indefinite time
mHandlerUpdateProgress.post(mUpdateUpdateProgress);
}
} ).start();
}
final Handler mHandlerUpdateProgress= new Handler();
final Runnable mUpdateUpdateProgress = new Runnable() {
public void run() {
// ending the process
prg.setVisibility(ProgressBar.GONE);
}
};
If the default progress indicator is good enough for you (i.e. the spinning wheel), then you can just use ProgressBar. To change it from a normal progress bar to a spinning wheel, use progressBar.setIndeterminate(true).
Related
I'm trying to implement a recyclerView showing the progress of some Activities, I decided to use android ProgressBar to represent the progress.
The problem is that the progressBar View does not hold the represented data when i set the progress in onBindViewHolder() or does even show at all sometimes.
I tried some suggestions, e.g. setting the visibility and "setIndeterminate()" in a separate AsyncTask, nothing works.
PS: I'm using a custom drawable, but it does work also with normal Horizontal ProgressBar.
Screenshot of the preview in Android Studio :
#Override
public void onBindViewHolder(ObjectivesViewHolder holder, int position) {
Objective objective = objectives.get(position);
holder.objectiveTextView.setText(objective.getObjectiveTitle());
holder.goalTextView.setText(objective.getGoal() + "");
holder.achievedTextView.setText(String.valueOf(objective.getAchieved()));
new pbUiThread(holder.objectiveProgressBar).execute();
holder.objectiveProgressBar.getProgressDrawable().mutate();
holder.objectiveProgressBar.setProgress((int)objective.getProgress());
if (objective.isDone()) holder.objectivesRow.setAlpha((float) 0.3);
else holder.objectivesRow.setAlpha((float) 1.0);
}
AsyncTask:
public class pbUiThread extends AsyncTask<ProgressBar, Void, Void> {
ProgressBar progressBar;
public pbUiThread(ProgressBar progressBar) {
this.progressBar = progressBar;
}
#Override
protected Void doInBackground(ProgressBar... progressBars) {
progressBar.setVisibility(View.VISIBLE);
progressBar.setIndeterminate(false);
return null;
}
}
ProgressBar in the XML Layout
<ProgressBar
android:id="#+id/objectiveProgressBar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="90dp"
android:layout_height="90dp"
android:layout_marginVertical="10dp"
android:layout_marginHorizontal="20dp"
android:max="100"
android:progress="50"
android:visibility="visible"
android:progressDrawable="#drawable/pb_circle"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"/>
I used the same layout in another Fragment without RecyclerView and it works like it should.
Any Help ?
Update:
After hours of debugging i found that the problem was in my data modelI have set the progress field to be ignored by the DB using Room's #Ignore annotation since I thought i only need it for the UI)
#Ignore
private float progress;
PS: I'm still kept a handler to update the progress
new Handler().post(new Runnable() {
#Override
public void run() {
holder.objectiveProgressBar.setProgress(progress);;
}
});
you shouldnt save progress in your view especially in recycler view because it will be reused other information will be set to it and your information will be lost. instead try save it in any model that makes sense and set progress from that model in onBindViewHolder.
I am using a custom ProgressBar. Now while a task is going on, I am showing the progress bar, but user can still interact with the views and controls.
How do I disable the user interaction on whole view just like a ProgressDialog does , when it is visible.
Do I need to use a transparent view on top of main view and show the progress bar on that view and hide that view once a task is completed.
Or just get the id of my parentView and set it disabled ? But then I won't be able to dim the background, just like what happens when a dialog appears on the view/Activity/Fragment. Right?
I just want to know the way to disallow the user from any interaction while the progressbar is visible.
Thanks
Your question: How to disable the user interaction while ProgressBar is visible in android?
To disable the user interaction you just need to add the following code
getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
To get user interaction back you just need to add the following code
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
Here is an example:
Note:I am giving you just an example to show how to disable or retain user interaction
Add a progress bar in your xml.Something like this
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/progressBar"
android:visibility="gone"/>
In MainActivity when a button pressed you show the progressbar and disable the user interaction.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mImageView = (ImageView) findViewById(R.id.imageView);
mProgressBar = (ProgressBar) findViewById(R.id.progressBar);
mImageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mProgressBar.setVisibility(View.VISIBLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
}
});
}
And when user backPressed you remove the progressbar again retain the user interaction.Something like this
#Override
public void onBackPressed() {
super.onBackPressed();
mProgressBar.setVisibility(View.GONE);
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
}
If you want to add a feature of disable and greyed out display, you need to add in your xml layout file a linear layout that fills the parent. Set its background to #B0000000 and its visibilty to GONE. Then programmatically set its visibility to VISIBLE.
Hope this help!
I have fixed this issue by adding root layout to the ProgressBar.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:clickable="true"
android:gravity="center"
android:visibility="gone"
android:id="#+id/progress">
<ProgressBar
style="?android:attr/progressBarStyleLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:indeterminate="true"
android:indeterminateTintMode="src_atop"
android:indeterminateTint="#color/primary"/>
</LinearLayout>
Made the root layout clickable
android:clickable="true"
NOTE: In my main view, I had RelativeLayout as root and have added above-mentioned code inside the root layout at the last position (last child).
Hope this helps!!
just set:
android:clickable="true"
in your xml
<ProgressBar...
Only this makes magic!
To extend (pun intended) on the accepted Answer :
When you use kotlin you can use extension functions. That way you have a quick and nice looking method for blocking and unblocking UI.
fun AppCompatActivity.blockInput() {
window.setFlags(
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE)
}
fun AppCompatActivity.unblockInput() {
window.clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE)
}
fun AppCompatActivity.blockInputForTask(task: () -> Unit) {
blockInput()
task.invoke()
unblockInput()
}
You can use the blocking and unblocking functions in your activity. Also, you can add more functionality like showing a Toast or something.
When using it in a custom view or any other view, you can simply cast the context to activity and use the functions.
Use blockInputForTask to surround simple linear tasks and blockInputand unblockInput when they are needed in different scopes.
You can use blockInputForTask like this:
blockInputForTask {
// Your lines of code
// Can be multiple lines
}
Use document default method progressbar.setCancelable(false)
Make a dialog with transparent background. The issue with getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE); is that when app will go in background and come back user will be able to interact with UI components, a lot more handling. So for blocking UI make a transparent dialog and if you want to set time for hide/show. Do this in a runnable thread. So the solution will be
public class TransparentDialogHelper {
private Dialog overlayDialog;
#Inject
public TransparentDialogHelper() {
}
public void showDialog(Context context) {
if (AcmaUtility.isContextFinishing(context)) {
return;
}
if (overlayDialog == null) {
overlayDialog = new Dialog(context, android.R.style.Theme_Panel);
overlayDialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED);
}
overlayDialog.show();
}
public void hideDialog() {
if (overlayDialog == null || AcmaUtility.isContextFinishing(overlayDialog.getContext())) {
return;
}
overlayDialog.cancel();
}
}
-------- Timer
Handler handler = new Handler();
handler.postDelayed( () -> {
view.hideProgress();
}, 2000);
Make your parent layout as Relative Layout & add this :
<RelativeLayout ... >
<other layout elements over which prog bar will appear>
<RelativeLayout android:id="#+id/rl_progress_bar"
android:layout_width="match_parent" android:clickable="true"
android:layout_height="match_parent" >
<ProgressBar android:id="#+id/pb"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:indeterminateOnly="true"
style="#android:style/Widget.DeviceDefault.ProgressBar"
android:theme="#style/AppTheme.MyProgressBar"
/>
</RelativeLayout>
If you have floating buttons in your UI, they still grab all the focus & remain clickable when the progress bar is visible. for this use : (when your prog bar is visible & re-enable them when you make your prog bar invisible/gone)
fb.setEnabled(false);
I would hide navigation bar and action bar of my app after some second that display don't get touched, and expand current view to fullscreen.
Then if user touch the screen (or better if he swipe down), make visible both again. How to?
You can use a Handler to delay certain actions.
Handler h = new Handler();
h.postDelayed(new Runnable() {
#Override
public void run() {
// DO DELAYED STUFF
getActionBar().hide();
}
}, delaytime); // e.g. 3000 milliseconds
The actions you take inside the run() method will be executed after
the delay-time you set.
If you are using Eclipse, just create a new project and select "Fullscreen Activity": this is a good example on how to do what you want.
I want to show image only when user scratch on that, image will be overlay with colors. So when user scratch on it they can see the image. I will finished that part by using this link.
But what i need is while user scratch on that image, progress bar want to show the current progress. if user scratches all the portion of image progress bar should finish 100%.
If you use Android-WScratchView library, you can register OnScratchCallback and assign the percentage of cleared part to your progressbar
scratchView.setOnScratchCallback(new WScratchView.OnScratchCallback() {
#Override
public void onScratch(float percentage) {
yourProgressBar.setProgress(percentage);//Assign progressbar value here
}
#Override
public void onDetach(boolean fingerDetach) {
if(mPercentage > 50){
scratchView.setScratchAll(true);
updatePercentage(100);
}
}
});
You can check full sample at here
I have a Layout with a TextView, and I want to make the text or the View itself to be presented for a defined time at run time.
How can I do that?
I tried with Animation: I've placed the TextView inside an Animation tag in the main.xml, but when i use:
animation = AnimationUtils.loadAnimation(this, R.id.msg_anim);
and later:
animation.startNow();
I get an exception.
So How to make the text or the TextView visible for a second?
Thank You.
You can use handlers to handle timed UI elements during runtime.
TextView myTV;
Handler uiHandler = new Handler();
Runnable makeTextGone = new Runable(){
#Override
public void run(){
myTv.setVisibility(View.GONE);
}
};
#Override
public void onCreate(Bundle icicle){
.... code ....
myTv = (TextView) findViewById(R.id.myTextView);
uiHandler.postDelayed(makeTextGone, 1000);
... code ...
}
The call to uiHandler.postDelayed(makeTextGone, 1000); will call the runnable only once after one second. Put it immediately after you make the text visible and it should disappear after a second.
You need to make sure that your activity is instantiated before you call any animations or resources.
Make sure you are calling this AFTER super.onCreate();
Hope this helped.
You might be getting the exception because you are trying to start the animation in onCreate().
As per the documentation, the recommended place to start animations is in onResume(). If that's not the problem, post some more information about your Exception (like the stack trace)