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.