Usando o "círculo animado" em um ImageView ao carregar itens

219

Atualmente, estou usando no meu aplicativo uma lista de exibição que talvez precise de um segundo para ser exibida.

O que atualmente faço é usar a propriedade @ id / android: empty da listview para criar um texto "carregando".

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

Agora, gostaria de substituir isso pelo círculo animado usado em uma caixa de diálogo de carregamento, em vez deste texto, acho que todos sabem o que quero dizer:

Edit: Eu não quero um diálogo. Eu quero mostrar isso dentro do meu layout.

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

Muito obrigado pela sua ajuda!

Waza_Be
fonte

Respostas:

443

Basta colocar este bloco de xml no seu arquivo de layout de atividade:

<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 quando terminar de carregar, chame esta linha:

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

O resultado (e também gira):

insira a descrição da imagem aqui

user1032613
fonte
17
quebrou o botão +1
TSR
Não é possível ver como isso resolve o problema de mostrar um círculo animado em um ImageView.
1175 Gustavo Gustavo
4
@Gustavo, é isso que ele quer, para mostrar uma "animação de progresso indeterminado", então acho que resolve o problema. ; -]
Thalis Vilela
143

Você pode fazer isso usando o seguinte xml

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

Com esse 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 isso, você deve ocultar seus elementos da interface do usuário configurando o valor de visibilidade como GONE e, sempre que os dados forem carregados, chame setVisibility(View.VISIBLE)todas as suas visualizações para restaurá-las. Não esqueça de ligarfindViewById(R.id.loadingPanel).setVisiblity(View.GONE) para ocultar a animação de carregamento.

Se você não possui um evento / função de carregamento, mas apenas deseja que o painel de carregamento desapareça após x segundos, use um Handle para acionar a ocultação / exibição.

Kurru
fonte
4
Ótima resposta. Encontrado através da pesquisa do Google e resolvi meu problema também. Obrigado!
Dave
Usando esse método, recebo uma NullPointerException na findViewById(...).setVisibility(View.GONE)linha quando eu giro a tela. Funciona como um encanto em uma orientação, mas alguma idéia de por que isso pode estar quebrando?
21412 Kalina
Eu tenho uma pergunta. Meu RelativeLayout está entre dois botões dentro de um Layout Linear também entre os botões. Quando eu executo isso, ocupa toda a tela. Alguma dica sobre como manter essa barra de carregamento entre os dois botões?
Alioo 24/09
Bem, onde devo colocar o código findViewById(R.id.loadingPanel).setVisiblity(View.GONE)na segunda atividade? Não é possível encontrar o, viewpois não há setContnetView()método na atividade do 2º fragmento. Obrigado!
Alston
10

Isso geralmente é chamado de barra de progresso indeterminado progresso indeterminado ou caixa de diálogo de progresso indeterminado.

Combine isso com um Thread e um Handler para obter exatamente o que você deseja. Existem vários exemplos de como fazer isso via Google ou aqui no SO. Eu recomendo que dedique algum tempo para aprender como usar essa combinação de classes para executar uma tarefa como essa. É incrivelmente útil em muitos tipos de aplicativos e oferece uma ótima visão de como Threads e Manipuladores podem trabalhar juntos.

Vou ajudá-lo a saber como isso funciona:

O evento de carregamento inicia o diálogo:

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

Agora o thread faz o trabalho:

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

Por fim, recupere o estado do thread quando estiver concluído:

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
fonte
2
Sua resposta parece muito boa, mas eu gostaria de inseri-la no meu layout ... A resposta de Venkatesh parece mais apropriada ao meu uso. Tentarei enviar um feedback. Muito obrigado pelo seu tempo!
Waza_Be 26/03
Obrigado por este, é realmente bom ter solução para XML e maneira programática de fazer as coisas.
Neon Warge
1

Se você não deseja aumentar outra visão apenas para indicar progresso, faça o seguinte:

  1. Crie ProgressBar no mesmo layout XML da exibição de lista.
  2. Torne-o centrado
  3. Dê um ID
  4. Anexe-o à sua variável de instância listview chamando setEmptyView

O Android cuidará da visibilidade da barra de progresso.

Por exemplo, em 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 em 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
fonte
ProgressBar tem que estar na segunda posição dentro do RelativeLayout, caso contrário ele é renderizado por trás da exibição no segundo lugar (um ImageView na minha ea ListView no seu caso)
Dominikus K.
1

Você pode usar esse código em amostras do firebase github .

Você não precisa editar os arquivos de layout ... basta criar uma nova 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();
    }

}

Na sua atividade que você deseja usar a caixa de diálogo de progresso.

public class MyActivity extends BaseActivity

Antes / depois da função que leva tempo

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

Para os que estão desenvolvendo em Kotlin, existe um método interessante fornecido pela biblioteca Anko que facilita o processo de exibição ProgressDialog!

Com base nesse link:

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

Isso exibirá uma caixa de diálogo Progresso com o% de progresso exibido (para o qual você deve passar o initparâmetro também para calcular o progresso).

Há também o indeterminateProgressDialog()método, que fornece a animação Spinning Circle indefinidamente até ser descartada:

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

Grite para este blog que me levou a esta solução.

DarkCygnus
fonte