Usar el "círculo animado" en un ImageView mientras carga cosas

219

Actualmente estoy usando en mi aplicación una vista de lista que necesita quizás un segundo para mostrarse.

Lo que actualmente hago es usar la propiedad @ id / android: empty de la vista de lista para crear un texto de "carga".

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

Ahora, me gustaría reemplazar eso con el círculo animado que se usa en un diálogo de carga en lugar de este texto, supongo que todos saben a qué me refiero:

Editar: no quiero un diálogo. Quiero mostrar eso dentro de mi diseño.

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

Muchas gracias por tu ayuda!

Waza_Be
fuente

Respuestas:

443

Simplemente ponga este bloque de xml en su archivo de diseño de actividad:

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

Y cuando termine de cargar, llame a esta línea:

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

El resultado (y también gira):

ingrese la descripción de la imagen aquí

usuario1032613
fuente
17
rompió el botón +1
TSR
No puedo ver cómo esto resuelve el problema de mostrar un círculo animado en un ImageView.
Gustavo
44
@Gustavo, esto es lo que quiere, para mostrar una "animación de progreso indeterminado", así que creo que resuelve el problema. ; -]
Thalis Vilela
143

Puede hacer esto usando el siguiente xml

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

Con este estilo

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

Para usar esto, debe ocultar sus elementos de la IU configurando el valor de visibilidad en GONE y cada vez que se carguen los datos, invoque setVisibility(View.VISIBLE)todas sus vistas para restaurarlos. No olvides llamar findViewById(R.id.loadingPanel).setVisiblity(View.GONE)para ocultar la animación de carga.

Si no tiene un evento / función de carga, pero solo quiere que el panel de carga desaparezca después de x segundos, use una Manija para activar la ocultación / visualización.

Kurru
fuente
44
Gran respuesta. Encontré a través de la búsqueda de Google y resolvió mi problema también. ¡Gracias!
Dave
Usando este método, obtengo una NullPointerException en la findViewById(...).setVisibility(View.GONE)línea cuando giro la pantalla. Funciona como un encanto en una orientación, pero ¿alguna idea de por qué esto podría estar rompiendo?
Kalina
Tengo una pregunta. My RelativeLayout es entre dos botones dentro de un diseño lineal también entre los botones. Cuando ejecuto esto, ocupa toda la pantalla. ¿Algún consejo para mantener esta barra de carga entre los dos botones?
Alioo
Bueno, ¿dónde debo poner el código findViewById(R.id.loadingPanel).setVisiblity(View.GONE)en la segunda actividad? No puede encontrar el viewdado que no hay ningún setContnetView()método en la actividad del segundo fragmento. ¡Gracias!
Alston
10

Esto generalmente se conoce como una barra de progreso indeterminado o diálogo de progreso indeterminado.

Combina esto con un hilo y un controlador para obtener exactamente lo que quieres. Hay una serie de ejemplos sobre cómo hacer esto a través de Google o aquí mismo en SO. Recomiendo encarecidamente pasar el tiempo para aprender a usar esta combinación de clases para realizar una tarea como esta. Es increíblemente útil en muchos tipos de aplicaciones y le dará una gran idea de cómo los subprocesos y los controladores pueden trabajar juntos.

Comenzaré a explicar cómo funciona esto:

El evento de carga inicia el diálogo:

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

Ahora el hilo hace el trabajo:

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

Finalmente recupere el estado del hilo cuando esté completo:

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
fuente
2
Su respuesta parece realmente agradable, pero me gustaría insertarla dentro de mi diseño ... La respuesta de Venkatesh parece más apropiada para mi uso. Intentaré enviar comentarios. Muchas gracias por tu tiempo!
Waza_Be
Gracias por esto, es realmente bueno tener una solución tanto para XML como para la forma programática de hacer las cosas.
Neon Warge
1

Si desea no inflar otra vista solo para indicar el progreso, haga lo siguiente:

  1. Cree ProgressBar en el mismo diseño XML de la vista de lista.
  2. Hazlo centrado
  3. Dale una identificación
  4. Adjúntelo a su variable de instancia listview llamando a setEmptyView

Android se encargará de la visibilidad de la barra de progreso.

Por ejemplo, en 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>

Y en 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
fuente
ProgressBar tiene que estar en el segundo lugar dentro del RelativeLayout, de lo contrario, se representa detrás de la Vista en el segundo lugar (una ImageView en mi y la ListView en su caso)
Dominikus K.
1

Puede usar este código de las muestras de Firebase Github .

No necesita editar en los archivos de diseño ... solo cree una nueva clase "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();
    }

}

En su actividad que desea utilizar el diálogo de progreso ...

public class MyActivity extends BaseActivity

Antes / después de la función que lleva tiempo

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

Para los que se desarrollan en Kotlin, existe un método dulce proporcionado por la biblioteca Anko que hace que el proceso de mostrar unProgressDialog muy fácil.

Basado en ese enlace:

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

Esto mostrará un cuadro de diálogo de progreso con el% de progreso que se muestra (para el cual debe pasar el init parámetro para calcular el progreso).

También existe el indeterminateProgressDialog()método, que proporciona la animación del Círculo giratorio indefinidamente hasta que se descarta:

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

Un saludo a este blog que me llevó a esta solución.

DarkCygnus
fuente