Pasek postępu pod paskiem akcji


79

Podsumowanie pytania: Jak mogę zrobić ProgressBarintegrację wewnątrz ActionBar, tak jak w aplikacji Chrome?

Szczegóły: spójrz na ten zrzut ekranu z Chrome:

Zrzut ekranu Chrome na Androida

Chcę utworzyć pasek akcji, tak jak ten. Tuż pod paskiem akcji znajduje się pasek postępu, który wypełnia się zgodnie z ładowaniem strony. Widziałem ten przykład z wielu aplikacji, takich jak Feedly, ale nie byłem w stanie stworzyć własnej implementacji. Próbowałem użyć własnych interfejsów API Androida, aby go utworzyć:

@Override
protected void onCreate(Bundle savedInstanceState) {
    //Request Permission to display the Progress Bar...
    this.requestWindowFeature(Window.FEATURE_PROGRESS);
            this.setWindowContentView(R.layout.activity_main)
    super.onCreate(savedInstanceState);

    this.setProgressBarIndeterminate(true);
}

Ale ten kod powoduje tylko wyświetlenie ProgressBar nad paskiem akcji, na przykład:

Zrzut ekranu mojej aplikacji

Jak więc mogę sprawić, by mój pasek ProgressBar pojawił się pod paskiem akcji, tak jak w aplikacji Chrome?


możliwe powtórzenie pytania tej odpowiedzi: stackoverflow.com/a/10755545/794088
petey

znalazłeś już rozwiązanie?
Eric

zrzuty ekranu dla mojej babci
IlyaEremin

Odpowiedzi:


7

Jest to teraz natywne zachowanie, które można uzyskać za pomocą SwipeRefreshLayout .

Możesz zawinąć przewijalny widok za pomocą, SwipeRefreshLayouta następnie wystarczy odsłuchać zdarzenia onRefresh :

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

    swipeLayout = (SwipeRefreshLayout) findViewById(R.id.swipe_container);
    swipeLayout.setOnRefreshListener(this);
    swipeLayout.setColorScheme(android.R.color.holo_blue_bright, 
            android.R.color.holo_green_light, 
            android.R.color.holo_orange_light, 
            android.R.color.holo_red_light);
}


@Override public void onRefresh() {
    new Handler().postDelayed(new Runnable() {
        @Override public void run() {
            swipeLayout.setRefreshing(false);
        }
    }, 5000);
}

Ładny i prosty poradnik można znaleźć na tym blogu .


56

Nie byłem w pełni zadowolony z zaakceptowanej odpowiedzi powyżej, więc sam przeprowadziłem dodatkowe badania.

Uważam, że sztuczka, której użyli, polega na tym, że pobrali widok z góry w wywołanej hierarchii widoków DecorViewi dodali tam pasek postępu. W ten sposób pasek postępu wyświetla się zarówno nad paskiem akcji, jak i obszarem zawartości. Zwróć uwagę, że odpowiedź SD umieszcza pasek postępu w obszarze zawartości i „kradnie” miejsce z rzeczywistej treści, co może prowadzić do nieoczekiwanych wyników.

Przykładowe zrzuty ekranu tej implementacji:

Pasek postępu

ProgressBarIndeterminate

Kod

Po prostu wstaw ten kod do onCreatemetody jakiejś aktywności i powinno zadziałać:

// create new ProgressBar and style it
final ProgressBar progressBar = new ProgressBar(this, null, android.R.attr.progressBarStyleHorizontal);
progressBar.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, 24));
progressBar.setProgress(65);

// retrieve the top view of our application
final FrameLayout decorView = (FrameLayout) getWindow().getDecorView();
decorView.addView(progressBar);

// Here we try to position the ProgressBar to the correct position by looking
// at the position where content area starts. But during creating time, sizes 
// of the components are not set yet, so we have to wait until the components
// has been laid out
// Also note that doing progressBar.setY(136) will not work, because of different
// screen densities and different sizes of actionBar
ViewTreeObserver observer = progressBar.getViewTreeObserver();
observer.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
        View contentView = decorView.findViewById(android.R.id.content);
        progressBar.setY(contentView.getY() - 10);

        ViewTreeObserver observer = progressBar.getViewTreeObserver();
        observer.removeOnGlobalLayoutListener(this);
    }
});

Możesz grać z argumentem wysokości LayoutParams, aby ustawić pasek postępu na szerszy lub węższy, ale może być konieczne dostosowanie -10przesunięcia.

Stylizacja

Niestety widać brzydkie szare tło paska postępu. Aby go usunąć, po prostu wyszukując tło według identyfikatora i próbując go ukryć, nie działa. Aby usunąć tło, musiałem stworzyć identyczny rysunek wersji systemu i usunąć element tła.

TL; DR: Utwórz plik progress_horizontal_holo_no_background_light.xmli wklej to do rysowania:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:id="@android:id/secondaryProgress">
        <scale android:scaleWidth="100%"
               android:drawable="@drawable/progress_secondary_holo_light" />
    </item>

    <item android:id="@android:id/progress">
        <scale android:scaleWidth="100%"
               android:drawable="@drawable/progress_primary_holo_light" />
    </item>

</layer-list>

Skopiuj odpowiednie rysunki .png z sdk/platforms/android-xx/data/res/drawable-xxx/do swojego projektu, a następnie w kodzie możesz dodać:

progressBar.setProgressDrawable(getResources().getDrawable(R.drawable.progress_horizontal_holo_no_background_light));

Dodatkowo: nieokreślony pasek postępu

Wersje nieokreślonych pasków postępu sprzed KitKata są dość brzydkie i opóźnione. Możesz pobrać nowy płynny pasek postępu o nazwie ButteryProgressBar. Po prostu wyszukaj go w google (nie mogę już dodawać linków, ponieważ jestem nowy tutaj: [), dodaj klasę do swojego projektu i możesz po prostu zastąpić poprzedni ProgressBar tym kodem i mieć chrupiący nieokreślony pasek postępu:

final ButteryProgressBar progressBar = new ButteryProgressBar(this);
progressBar.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, 24));

Konieczne może być również uproszczenie tego kodu:

final TypedArray ta = c.obtainStyledAttributes(attrs, R.styleable.ButteryProgressBar);
try {
    mBarColor = ta.getColor(R.styleable.ButteryProgressBar_barColor,
            c.getResources().getColor(android.R.color.holo_blue_light));
    mSolidBarHeight = ta.getDimensionPixelSize(
            R.styleable.ButteryProgressBar_barHeight,
            Math.round(DEFAULT_BAR_HEIGHT_DP * mDensity));
    mSolidBarDetentWidth = ta.getDimensionPixelSize(
            R.styleable.ButteryProgressBar_detentWidth,
            Math.round(DEFAULT_DETENT_WIDTH_DP * mDensity));
} finally {
    ta.recycle();
}

do tego kodu:

mBarColor = c.getResources().getColor(android.R.color.holo_blue_light);
mSolidBarHeight = Math.round(DEFAULT_BAR_HEIGHT_DP * mDensity);
mSolidBarDetentWidth = Math.round(DEFAULT_DETENT_WIDTH_DP * mDensity);

Mam nadzieję, że pomogłem :)


Metoda removeGlobalOnLayoutListener (ViewTreeObserver.OnGlobalLayoutListener) z typu ViewTreeObserver jest przestarzała
Frozen Crayon

@ArjunU. czego powinniśmy użyć zamiast tego>
Patrick Geyer


Przetestowałem nieokreślony pasek postępu ( ButteryProgressBar) z, ActionBarActivityale to nie działa. Jak mogę umieścić nieokreślony pasek postępu pod ActionBar/Toolbar? To jest układ, którego używam: stackoverflow.com/a/26440880/1480019
user1480019

2
@GerritHoekstra: Jeśli getSupportActionBar().getHeight()funkcja działa, prawie gotowe . progressBar.setY()Funkcja ustawia Stanowisko w stosunku do górnej części ekranu, w tym na pasku stanu. Więc co musisz zrobić, to setY(supportActionBarHeight + Math.ceil(25 * context.getResources().getDisplayMetrics().density)). Pasek stanu ma wysokość 25 pikseli (mdpi) i skaluje się z wyższą gęstością (hdpi / xhdpi / ...). Spróbuj i powiedz, czy działa.
Antimonit

25

Rozszerz Działania z następującej klasy, aby mieć ProgressBar na górze (poniżej ActionBar) każdej z nich i getProgressBar()metodę:

Klasa nadrzędna:

public abstract class ProgressActivity extends Activity {
    private ProgressBar mProgressBar;

    @Override
    public void setContentView(View view) {
        init().addView(view);
    }

    @Override
    public void setContentView(int layoutResID) {
        getLayoutInflater().inflate(layoutResID,init(),true);
    }

    @Override
    public void setContentView(View view, ViewGroup.LayoutParams params) {
        init().addView(view,params);
    }

    private ViewGroup init(){
        super.setContentView(R.layout.progress);
        mProgressBar = (ProgressBar) findViewById(R.id.activity_bar);
        return (ViewGroup) findViewById(R.id.activity_frame);
    }

    protected ProgressBar getProgressBar(){
        return mProgressBar;
    }
}

Układ (progress.xml):

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical"
    android:layout_width="match_parent" android:layout_height="match_parent">
<ProgressBar android:id="@+id/activity_bar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="-8dp"
    style="@android:style/Widget.DeviceDefault.ProgressBar.Horizontal"
    />
  <FrameLayout android:id="@+id/activity_frame"
      android:layout_width="match_parent"
      android:layout_height="fill_parent"
      />
</LinearLayout>

1
To działa ... w większości. ProgressBar wygląda oddzielnie od paska akcji. Musiałem dodać android:layout_marginTop="-8dp"do ProgressBar, aby zasymulować efekt „cienia”. Ale w przypadku tej metody prawdopodobnie bardziej wydajne jest dodanie jej do samego głównego układu. Jednak teraz działa zgodnie z przeznaczeniem. Dzięki za hack.
zubietaroberto

@zubietaroberto Tak, możesz dodać go do głównego układu, jeśli używasz go tylko do jednej czynności. Jeśli chcesz, aby wiele działań miało tę funkcję, możesz po prostu rozszerzyć klasę pokazaną powyżej.
SD

1
To działa dla mnie, ale pasek postępu pojawia się pod hostem karty, jak mogę zrobić to nad tabhostem i pod paskiem akcji?
DeckyFx


3

Proszę użyć poniższego kodu. po prostu użyj jednego domyślnego stylu na pasku postępu jakostyle="?android:attr/progressBarStyleHorizontal"

<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"
    >
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/hello_world" />
    <ProgressBar 
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        style="?android:attr/progressBarStyleHorizontal"
        android:indeterminate="true"

        />

</RelativeLayout>

0

Cóż, zrobiłem coś podobnego dla jednej z moich aplikacji dla zwierząt domowych i nie jestem pewien, czy to jedyny lub najlepszy sposób, aby to zrobić, ale zdecydowanie działa.

Na początek użyj paska akcji nakładki, a następnie ustaw tło, które można rysować na „null”, aby pasek akcji nakładki był przezroczysty.

Teraz w swoim układzie aktywności ustaw górny margines widoku głównego na „wysokość paska akcji”. Możesz to zrobić w ten sposób.

<RelativeLayout
    ...
    android:layout_marginTop="?android:attr/actionBarSize" />

Teraz akcja nie będzie ukrywać żadnej zawartości Twojej aktywności.

Następną rzeczą, którą musisz teraz zrobić, jest - dodaj widok nagłówka na górze widoku głównego o wysokości takiej samej jak pasek akcji. Ustaw kolor tła. Byłby to teraz kolor twojego paska akcji, a ponieważ pasek akcji jest idealnie wyrównany na górze tego widoku nagłówka.

Teraz możesz łatwo umieścić pasek postępu w widoku nagłówka i wyrównać go do dołu widoku nagłówka. Dla użytkownika wyglądałoby to tak, jakby pasek postępu znajdował się na samym pasku akcji, podobnie jak chrome.

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.