Używanie „animowanego koła” w ImageView podczas ładowania rzeczy


219

Obecnie używam w mojej aplikacji widoku listy, który może potrzebować jednej sekundy do wyświetlenia.

Obecnie używam @ id / android: pusta właściwość widoku listy, aby utworzyć tekst „ładujący”.

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

Teraz chciałbym zastąpić to animowanym kołem używanym w oknie dialogowym ładowania zamiast tego tekstu, chyba wszyscy wiecie, co mam na myśli:

Edycja: Nie chcę okna dialogowego. Chcę to pokazać w moim układzie.

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

Bardzo dziękuję za pomoc!

Odpowiedzi:


443

Wystarczy umieścić ten blok xml w pliku układu aktywności:

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

A kiedy skończysz ładować, zadzwoń na tę linię:

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

Wynik (i obraca się również):

wprowadź opis zdjęcia tutaj


17
rozbił przycisk +1
TSR

Nie widzę, jak to rozwiązuje problem wyświetlania animowanego koła w ImageView.
Gustavo

4
@Gustavo, właśnie tego chce, aby pokazać „nieokreśloną animację postępu”, więc myślę, że to rozwiązuje problem. ; -]
Thalis Vilela

143

Możesz to zrobić za pomocą następującego kodu xml

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

Z tym stylem

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

Aby tego użyć, musisz ukryć elementy interfejsu użytkownika, ustawiając wartość widoczności na BRAK i za każdym razem, gdy dane są ładowane, wzywaj setVisibility(View.VISIBLE)wszystkie swoje widoki, aby je przywrócić. Nie zapomnij zadzwonić, findViewById(R.id.loadingPanel).setVisiblity(View.GONE)aby ukryć animację ładowania.

Jeśli nie masz zdarzenia / funkcji ładowania, ale po prostu chcesz, aby panel ładowania zniknął po x sekundach, użyj uchwytu, aby uruchomić ukrywanie / wyświetlanie.


4
Świetna odpowiedź. Znaleziono za pomocą wyszukiwarki Google i rozwiązałem również mój problem. Dzięki!
Dave

Korzystając z tej metody, otrzymuję NullPointerException w findViewById(...).setVisibility(View.GONE)wierszu podczas obracania ekranu. Działa jak urok w jednej orientacji, ale masz pojęcie, dlaczego to może się zepsuć?
Kalina,

Mam pytanie. Mój RelativeLayout znajduje się między dwoma przyciskami w układzie liniowym, również między przyciskami. Po uruchomieniu zajmuje cały ekran. Czy masz jakieś wskazówki dotyczące utrzymywania paska ładowania między dwoma przyciskami?
Alioo

Gdzie powinienem umieścić kod findViewById(R.id.loadingPanel).setVisiblity(View.GONE)w drugiej czynności? Nie może znaleźć, viewponieważ nie ma setContnetView()metody w aktywności drugiego fragmentu. Dzięki!
Alston

10

Jest to ogólnie określane jako Nieokreślony pasek postępu lub Nieokreślony dialog postępu.

Połącz to z Wątkiem i Uchwytem, aby uzyskać dokładnie to, czego chcesz. Istnieje wiele przykładów tego, jak to zrobić za pośrednictwem Google lub tutaj na SO. Gorąco polecam poświęcenie czasu na nauczenie się, jak korzystać z tej kombinacji klas, aby wykonać takie zadanie. Jest niezwykle przydatny w wielu typach aplikacji i daje doskonały wgląd w to, jak wątki i handlowcy mogą ze sobą współpracować.

Zacznę od tego, jak to działa:

Ładowanie zdarzenia uruchamia okno dialogowe:

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

Teraz wątek działa:

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

Wreszcie odzyskaj stan z wątku, gdy jest on gotowy:

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
Twoja odpowiedź wydaje się bardzo ładna, ale chciałbym wstawić ją do mojego układu ... Odpowiedź Venkatesha wydaje się bardziej odpowiednia do mojego zastosowania. Spróbuję przesłać opinię. Dziękuję bardzo za poświęcony czas!
Waza_Be

Dzięki za to dobrze jest mieć rozwiązanie zarówno dla XML, jak i programowego sposobu robienia rzeczy.
Neon Warge

1

Jeśli nie chcesz zawyżać innego widoku tylko w celu wskazania postępu, wykonaj następujące czynności:

  1. Utwórz pasek postępu w tym samym układzie XML widoku listy.
  2. Ustaw go na środku
  3. Podaj identyfikator
  4. Dołącz go do zmiennej instancji listview, wywołując setEmptyView

Android zadba o widoczność paska postępu.

Na przykład w 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>

I w 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) {

        }
    });


}

}


Pasek postępu musi znajdować się na drugim miejscu w RelativeLayout, w przeciwnym razie zostanie renderowany za widokiem na drugim miejscu (ImageView w moim i ListView w twoim przypadku)
Dominikus K.,

1

Możesz użyć tego kodu z próbek github Firebase ..

Nie musisz edytować plików układu ... po prostu utwórz nową klasę „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();
    }

}

W swoim działaniu chcesz użyć okna postępu.

public class MyActivity extends BaseActivity

Przed / Po funkcji, która wymaga czasu

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

0

Dla tych, którzy rozwijają się w Kotlinie, istnieje słodka metoda dostarczona przez bibliotekę Anko, która sprawia, że ​​proces wyświetlania ProgressDialogjest dziecinnie prosty!

Na podstawie tego linku:

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

Spowoduje to wyświetlenie okna dialogowego Postęp z wyświetlonym procentem postępu (dla którego należy przekazać initparametr, aby obliczyć postęp).

Istnieje również indeterminateProgressDialog()metoda, która zapewnia animację Spinning Circle w nieskończoność, dopóki nie zostanie odrzucona:

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

Krzycz na tym blogu, który doprowadził mnie do tego rozwiązania.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.