Utilisation du «cercle animé» dans une ImageView lors du chargement de trucs

219

J'utilise actuellement dans mon application une liste qui nécessite peut-être une seconde pour s'afficher.

Ce que je fais actuellement, c'est utiliser la propriété @ id / android: empty de la listview pour créer un texte de "chargement".

 <TextView android:id="@id/android:empty"
           android:layout_width="match_parent"
           android:layout_height="match_parent"
           android:background="#FF0000"
           android:text="Loading..."/>

Maintenant, je voudrais remplacer cela par le cercle animé qui est utilisé dans une boîte de dialogue de chargement au lieu de ce texte, je suppose que vous savez tous ce que je veux dire:

Edit: je ne veux pas de dialogue. Je veux montrer cela dans ma mise en page.

http://flexfwd.com/DesktopModules/ATI_Base/resources/images/loading_blue_circle.gif

Merci beaucoup pour votre aide!

Waza_Be
la source

Réponses:

443

Mettez simplement ce bloc de xml dans votre fichier de mise en page d'activité:

<RelativeLayout
    android:id="@+id/loadingPanel"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center" >

    <ProgressBar
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:indeterminate="true" />
</RelativeLayout>

Et lorsque vous avez terminé le chargement, appelez cette ligne:

findViewById(R.id.loadingPanel).setVisibility(View.GONE);

Le résultat (et ça tourne aussi):

entrez la description de l'image ici

user1032613
la source
17
fracassé le bouton +1
TSR
Vous ne voyez pas comment cela résout le problème de l'affichage d'un cercle animé dans une ImageView.
Gustavo
4
@ Gustavo, c'est ce qu'il veut, pour montrer une "animation de progression indéterminée", donc je pense que cela résout le problème. ; -]
Thalis Vilela
143

Vous pouvez le faire en utilisant le xml suivant

<RelativeLayout
    style="@style/GenericProgressBackground"
    android:id="@+id/loadingPanel"
    >
    <ProgressBar
        style="@style/GenericProgressIndicator"/>
</RelativeLayout>

Avec ce style

<style name="GenericProgressBackground" parent="android:Theme">
    <item name="android:layout_width">fill_parent</item>    
    <item name="android:layout_height">fill_parent</item>
    <item name="android:background">#DD111111</item>    
    <item name="android:gravity">center</item>  
</style>
<style name="GenericProgressIndicator" parent="@android:style/Widget.ProgressBar.Small">
    <item name="android:layout_width">wrap_content</item>
    <item name="android:layout_height">wrap_content</item>
    <item name="android:indeterminate">true</item> 
</style>

Pour l'utiliser, vous devez masquer vos éléments d'interface utilisateur en définissant la valeur de visibilité sur GONE et chaque fois que les données sont chargées, appelez setVisibility(View.VISIBLE)toutes vos vues pour les restaurer. N'oubliez pas d'appeler findViewById(R.id.loadingPanel).setVisiblity(View.GONE)pour masquer l'animation de chargement.

Si vous n'avez pas d'événement / fonction de chargement mais que vous souhaitez simplement que le panneau de chargement disparaisse après x secondes, utilisez une poignée pour déclencher le masquage / affichage.

Kurru
la source
4
Très bonne réponse. Trouvé via la recherche Google et a également résolu mon problème. Merci!
Dave
En utilisant cette méthode, j'obtiens une NullPointerException sur la findViewById(...).setVisibility(View.GONE)ligne lorsque je fais pivoter l'écran. Fonctionne comme un charme dans une seule orientation, mais une idée de pourquoi cela pourrait se briser?
Kalina
J'ai une question. Ma RelativeLayout est entre deux boutons à l'intérieur d'une disposition linéaire également entre les boutons. Lorsque je lance cela, il occupe tout l'écran. Des conseils pour garder cette barre de chargement entre les deux boutons?
Alioo
Eh bien, où dois-je mettre le code findViewById(R.id.loadingPanel).setVisiblity(View.GONE)dans la deuxième activité? Il ne peut pas trouver le viewpuisqu'il n'y a pas de setContnetView()méthode dans l'activité du 2e fragment. Merci!
Alston
10

Ceci est généralement appelé une barre de progression indéterminée progression indéterminée ou d'une boîte de dialogue de progression indéterminée.

Combinez cela avec un thread et un gestionnaire pour obtenir exactement ce que vous voulez. Il existe un certain nombre d'exemples sur la façon de le faire via Google ou ici sur SO. Je recommanderais fortement de passer du temps à apprendre à utiliser cette combinaison de classes pour effectuer une tâche comme celle-ci. Il est incroyablement utile dans de nombreux types d'applications et vous donnera un excellent aperçu de la façon dont les threads et les gestionnaires peuvent fonctionner ensemble.

Je vais vous expliquer comment cela fonctionne:

L'événement de chargement ouvre la boîte de dialogue:

//maybe in onCreate
showDialog(MY_LOADING_DIALOG);
fooThread = new FooThread(handler);
fooThread.start();

Maintenant, le thread fait le travail:

private class FooThread extends Thread {
    Handler mHandler;

    FooThread(Handler h) {
        mHandler = h;
    }

    public void run() { 
        //Do all my work here....you might need a loop for this

        Message msg = mHandler.obtainMessage();
        Bundle b = new Bundle();                
        b.putInt("state", 1);   
        msg.setData(b);
        mHandler.sendMessage(msg);
    }
}

Enfin récupérez l'état du thread lorsqu'il est terminé:

final Handler handler = new Handler() {
    public void handleMessage(Message msg) {
        int state = msg.getData().getInt("state");
        if (state == 1){
            dismissDialog(MY_LOADING_DIALOG);
            removeDialog(MY_LOADING_DIALOG);
        }
    }
};
user432209
la source
2
Votre réponse semble vraiment sympa, mais j'aimerais insérer cela dans ma mise en page ... La réponse de Venkatesh semble plus appropriée à mon utilisation. J'essaierai d'envoyer des commentaires. Merci beaucoup pour votre temps!
Waza_Be
Merci pour celui-ci, c'est vraiment bien d'avoir une solution à la fois pour XML et pour la manière programmatique de faire les choses.
Neon Warge
1

Si vous ne souhaitez pas gonfler une autre vue uniquement pour indiquer les progrès, procédez comme suit:

  1. Créez ProgressBar dans la même disposition XML de la vue de liste.
  2. Faites-le centré
  3. Donnez-lui un identifiant
  4. Attachez-le à votre variable d'instance listview en appelant setEmptyView

Android veillera à la visibilité de la barre de progression.

Par exemple, dans 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:orientation="vertical"
    tools:context="com.fcchyd.linkletandroid.MainActivity">

    <ListView
        android:id="@+id/list_view_xml"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:divider="@color/colorDivider"
        android:dividerHeight="1dp" />

   <ProgressBar
        android:id="@+id/loading_progress_xml"
        style="?android:attr/progress"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true" />

</RelativeLayout>

Et dans MainActivity.java:

package com.fcchyd.linkletandroid;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.ArrayAdapter;
import android.widget.ListView;

import java.util.ArrayList;
import java.util.List;

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

public class MainActivity extends AppCompatActivity {

final String debugLogHeader = "Linklet Debug Message";
Call<Links> call;
List<Link> arraylistLink;
ListView linksListV;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    linksListV = (ListView) findViewById(R.id.list_view_xml);
    linksListV.setEmptyView(findViewById(R.id.loading_progress_xml));
    arraylistLink = new ArrayList<>();

    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl("https://api.links.linklet.ml")
            .addConverterFactory(GsonConverterFactory
                    .create())
            .build();

    HttpsInterface HttpsInterface = retrofit
            .create(HttpsInterface.class);

    call = HttpsInterface.httpGETpageNumber(1);

    call.enqueue(new Callback<Links>() {
        @Override
        public void onResponse(Call<Links> call, Response<Links> response) {
            try {
                arraylistLink = response.body().getLinks();

                String[] simpletTitlesArray = new String[arraylistLink.size()];
                for (int i = 0; i < simpletTitlesArray.length; i++) {
                    simpletTitlesArray[i] = arraylistLink.get(i).getTitle();
                }
                ArrayAdapter<String> simpleAdapter = new ArrayAdapter<>(MainActivity.this, android.R.layout.simple_list_item_1, simpletTitlesArray);
                linksListV.setAdapter(simpleAdapter);
            } catch (Exception e) {
                Log.e("erro", "" + e);
            }
        }

        @Override
        public void onFailure(Call<Links> call, Throwable t) {

        }
    });


}

}

Md_Zubair Ahmed
la source
ProgressBar doit être au deuxième endroit dans le RelativeLayout, sinon il est rendu derrière la vue au deuxième endroit (une ImageView dans mon et le ListView dans votre cas)
Dominikus K.
1

Vous pouvez utiliser ce code à partir d' exemples de github Firebase .

Vous n'avez pas besoin de modifier les fichiers de mise en page ... créez simplement une nouvelle classe "BaseActivity"

package com.example;

import android.app.ProgressDialog;
import android.support.annotation.VisibleForTesting;
import android.support.v7.app.AppCompatActivity;


public class BaseActivity extends AppCompatActivity {

    @VisibleForTesting
    public ProgressDialog mProgressDialog;

    public void showProgressDialog() {
        if (mProgressDialog == null) {
            mProgressDialog = new ProgressDialog(this);
            mProgressDialog.setMessage("Loading ...");
            mProgressDialog.setIndeterminate(true);
        }

        mProgressDialog.show();
    }


    public void hideProgressDialog() {
        if (mProgressDialog != null && mProgressDialog.isShowing()) {
            mProgressDialog.dismiss();
        }
    }

    @Override
    public void onStop() {
        super.onStop();
        hideProgressDialog();
    }

}

Dans votre activité que vous souhaitez utiliser la boîte de dialogue de progression.

public class MyActivity extends BaseActivity

Avant / Après la fonction qui prend du temps

showProgressDialog();
.... my code that take some time
showProgressDialog();
khateeb
la source
0

Pour ceux qui développent dans Kotlin, il existe une méthode douce fournie par la bibliothèque Anko qui rend le processus d'affichage ProgressDialogun jeu d'enfant!

Sur la base de ce lien:

val dialog = progressDialog(message = "Please wait a bit…", title = "Fetching data")
dialog.show()
//....
dialog.dismiss()

Cela affichera une boîte de dialogue de progression avec le% de progression affiché (pour lequel vous devez passer le init paramètre pour calculer la progression).

Il existe également la indeterminateProgressDialog()méthode, qui fournit l'animation Spinning Circle indéfiniment jusqu'à son rejet:

indeterminateProgressDialog("Loading...").show()

Merci à ce blog qui m'a conduit à cette solution.

DarkCygnus
la source