Utilizzo del "cerchio animato" in ImageView durante il caricamento di elementi


219

Attualmente sto usando nella mia applicazione una visualizzazione elenco che può richiedere forse un secondo per essere visualizzata.

Quello che attualmente sto facendo è usare la proprietà @ id / android: empty della lista per creare un testo di "caricamento".

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

Ora, vorrei sostituirlo con il cerchio animato che viene utilizzato in una finestra di dialogo di caricamento anziché in questo testo, immagino che tutti voi sappiate cosa intendo:

Modifica: non voglio una finestra di dialogo. Voglio mostrarlo nel mio layout.

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

Grazie mille per il tuo aiuto!

Risposte:


443

Basta inserire questo blocco di xml nel file di layout dell'attività:

<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>

E al termine del caricamento, chiama questa linea:

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

Il risultato (e gira anche):

inserisci qui la descrizione dell'immagine


17
ha fracassato il pulsante +1
TSR

Non riesco a vedere come questo risolva il problema di mostrare un cerchio animato in ImageView.
Gustavo,

4
@Gustavo, questo è quello che vuole, per mostrare una "animazione di progresso indeterminata", quindi penso che risolva il problema. ; -]
Thalis Vilela,

143

Puoi farlo usando il seguente xml

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

Con questo stile

<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>

Per utilizzarlo, è necessario nascondere gli elementi dell'interfaccia utente impostando il valore di visibilità su GONE e ogni volta che vengono caricati i dati, chiamare setVisibility(View.VISIBLE)tutte le visualizzazioni per ripristinarli. Non dimenticare di chiamare findViewById(R.id.loadingPanel).setVisiblity(View.GONE)per nascondere l'animazione di caricamento.

Se non si dispone di un evento / funzione di caricamento ma si desidera semplicemente che il pannello di caricamento scompaia dopo x secondi, utilizzare una maniglia per attivare il nascondiglio / visualizzazione.


4
Bella risposta. Trovato tramite la ricerca di Google e risolto anche il mio problema. Grazie!
Dave,

Usando questo metodo, ottengo una NullPointerException sulla findViewById(...).setVisibility(View.GONE)linea quando ruoto lo schermo. Funziona come un incantesimo con un orientamento, ma hai idea del perché questo potrebbe rompersi?
Kalina,

Ho una domanda. My RelativeLayout è tra due pulsanti all'interno di un layout lineare anche tra i pulsanti. Quando eseguo questo occupa l'intero schermo. Qualche consiglio su come mantenere questa barra di caricamento tra i due pulsanti?
Alioo,

Bene, dove dovrei inserire il codice findViewById(R.id.loadingPanel).setVisiblity(View.GONE)nella seconda attività? Non riesce a trovare il viewdato che non esiste alcun setContnetView()metodo nell'attività del 2 ° frammento. Grazie!
Alston,

10

Questo è generalmente indicato come barra di avanzamento indeterminata o finestra di dialogo di avanzamento indeterminato.

Combina questo con un thread e un gestore per ottenere esattamente quello che vuoi. Esistono numerosi esempi su come eseguire questa operazione tramite Google o qui su SO. Consiglio vivamente di dedicare del tempo ad imparare come usare questa combinazione di classi per svolgere un compito come questo. È incredibilmente utile in molti tipi di applicazioni e ti darà una visione completa di come thread e gestori possano lavorare insieme.

Ti farò iniziare su come funziona:

L'evento di caricamento avvia la finestra di dialogo:

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

Ora il thread funziona:

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);
    }
}

Infine, ripristina lo stato dal thread al termine:

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);
        }
    }
};

2
La tua risposta sembra davvero carina, ma vorrei inserirla nel mio layout ... La risposta di Venkatesh sembra più adatta al mio uso. Cercherò di inviare un feedback. Grazie mille per il tuo tempo!
Waza_Be

Grazie per questo, in realtà è buono avere una soluzione sia per XML che per il modo programmatico di fare le cose.
Neon Warge,

1

Se desideri non gonfiare un'altra vista solo per indicare l'avanzamento, procedi come segue:

  1. Crea ProgressBar nello stesso layout XML della vista elenco.
  2. Renderlo centrato
  3. Dagli un ID
  4. Collegalo alla variabile dell'istanza listview chiamando setEmptyView

Android si occuperà della visibilità della barra di avanzamento.

Ad esempio, in 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>

E in 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) {

        }
    });


}

}


ProgressBar deve trovarsi al secondo posto all'interno di RelativeLayout, altrimenti viene visualizzato dietro il View sul secondo spot (un ImageView nel mio e ListView nel tuo caso)
Dominikus K.,

1

È possibile utilizzare questo codice dagli esempi github di firebase .

Non è necessario modificarlo nei file di layout ... basta creare una nuova 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();
    }

}

Nella tua attività che desideri utilizzare la finestra di dialogo di avanzamento.

public class MyActivity extends BaseActivity

Prima / Dopo la funzione che richiede tempo

showProgressDialog();
.... my code that take some time
showProgressDialog();

0

Per quelli in via di sviluppo a Kotlin, esiste un metodo dolce fornito dalla libreria Anko che rende il processo di visualizzazione un gioco ProgressDialogda ragazzi!

Basato su quel link:

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

Questo mostrerà una finestra di avanzamento con la percentuale di avanzamento visualizzata (per la quale è necessario passare il initparametro anche per calcolare l'avanzamento).

C'è anche il indeterminateProgressDialog()metodo, che fornisce l'animazione Spinning Circle indefinitamente fino a quando non viene respinta:

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

Grida a questo blog che mi ha portato a questa soluzione.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.