#15 Aktywność wskazania ilości i kolejne poprawki

Ale tytuł posta 😉 Tak naprawdę to tylko tak zawile brzmi sprawa jest naprawdę prosta, mamy narysowany stos (a jakże) i wybieramy ile elementów się na nim znajduje 😉 Noo i oczywiście trzymając się konwencji mamy najpierw wprowadzenie, a następnie 5 prób na punkty. Oto jak to wygląda.

Sam widok tablicy numerycznej można by jeszcze poprawić, ale nie będzie to trudne 😉 Dzięki ostatnim poprawkom dodawanie tego typu zadanek to już naprawdę chwilka, wydaje mi się, że nie wiele więcej da się jeszcze tutaj zrobić. Ale wprowadziłem jeszcze dwie istotne poprawki, mianowicie, kiedy dodałem zadanka i chciałem je umieścić w innym miejscu na tej liście:

To okazało się, że musiałem edytować kilka klas, aby wiedziały jak się prawidłowo przełączać. Dlatego wyciągnąłem to wszystko w jedno miejsce, usunąłem z funkcji jeden argument, tak to wygląda:

Intent intent = new Intent(packageContext,
    getNextActivity(packageContext));
startActivity(intent);

...

private Class getNextActivity(Context context)
{
    if(context.getClass().equals(BricksActivity.class))
        return BricksOrderActivity.class;
    else if(context.getClass().equals(BricksOrderActivity.class))
        return ChoiceActivity.class;
    else if(context.getClass().equals(ChoiceActivity.class))
        return ChoiceCheckActivity.class;
    else if(context.getClass().equals(ChoiceCheckActivity.class))
        return CompareActivity.class;
    else if(context.getClass().equals(CompareActivity.class))
        return CompareCheckActivity.class;
    else if(context.getClass().equals(CompareCheckActivity.class))
        return AddingActivity.class;
    else if(context.getClass().equals(AddingActivity.class))
        return AddingCheckActivity.class;
    else
        return MenuActivity.class;
}

I teraz już kolejne elementy mam w jednym miejscu 😉 Dodanie następnego zadanka nie będzie wymagało edycji w innych aktywnościach.

Kolejną rzeczą którą poprawiłem jest niepowtarzanie się animacji fab przeniesione do samej obsługi animacji, dzięki temu nie musimy o to dbać w każdej aktywności osobno.

private boolean currentShapeIsDifferent(int resId)
{
    if(resId==previousAnim)
        return false;
    else
    {
        int pAnim = previousAnim;
        previousAnim = resId;
        if(resId==R.drawable.ic_line_to_undone&&
      pAnim==R.drawable.ic_done_to_undone)
            return false;
        else if(pAnim==R.drawable.ic_line_to_undone&&
      resId==R.drawable.ic_done_to_undone)
            return false;
        else if(resId==R.drawable.ic_line_to_done&&
      pAnim==R.drawable.ic_undone_to_done)
            return false;
        else if(pAnim==R.drawable.ic_line_to_done&&
      resId==R.drawable.ic_undone_to_done)
            return false;
        else
            return true;
    }
}

Jak widać logika nie jest taka całkiem prosta, ale ogólnie chodzi o to, że jeśli ostatnia figura w animacji jest taka sama, to nie trzeba animować, wizualnie wygląda to dobrze 😉 Przy okazji, Android Studio, czasem podpowiada jak można rozwiązać to w kodzie krócej, opcją simplify. Tym razem też podpowiedział:

return !(resId == R.drawable.ic_line_to_undone
&& pAnim == R.drawable.ic_done_to_undone)
&& !(pAnim == R.drawable.ic_line_to_undone
&& resId == R.drawable.ic_done_to_undone)
&& !(resId == R.drawable.ic_line_to_done
&& pAnim == R.drawable.ic_undone_to_done)
&& !(pAnim == R.drawable.ic_line_to_done
&& resId == R.drawable.ic_undone_to_done);
}

Sam dodałem entery, żeby nie był to jeden ciąg 😛 Simplify, że hej, oczywiście nie zostawiłem w tej wersji 😉

Ps. Aktualna liczba wyświetleń to: 4993, także wkrótce pyknie okrągłe 5000 odsłon bloga 😉 Dzięki wielkie 🙂 A po zakończeniu konkursu blog na pewno nie umrze, mam już kilka pomysłów na niego 😉 Ale o tym za jakiś czas, na razie mam 75% DSP wpisów 🙂

Projekt na github.

Pozdrawiam!

#9 Pierwsza lekcja dodawania

Pokazywaliśmy już liczby, jako ilości na wszelkie możliwe sposoby. Wyświetlając je na stosie, wyświetlając na ciągu stosów, przedstawiając je obok siebie. Najwyższy czas zrobić coś trudniejszego, mianowicie pora nauczyć się dodawać. Prezentację dodawania myślę, że zrobię innym razem, na razie przeszedłem dalej bezpośrednio do ćwiczeń dodawania. Mam nadzieję, że po takiej ilości prezentacji to, co chcemy osiągnąć będzie już dla ucznia jasne.

Aktywność w tym momencie działa w ten sposób, że losuje nam liczbę z przedziału 0 do 5 włącznie. Po wylosowaniu, wyświetla odpowiednią ilość belek. Użytkownik ma za zadanie dodać te belki przyciskami (+ i -) tak, aby wynik się zgadzał. Po wykonaniu tych operacji naciska na floating action buton, aby sprawdzić wynik. W przypadku, w którym wynik jest prawidłowy zostaje wyświetlona pełna gwiazdka. W przypadku błędnego wyniku, wyświetlona gwiazdka jest pusta w środku. Użytkownik ma pięć prób. Na ten moment nie ma żadnej animacji losowania belek, ponieważ zostaną one przykryte czymś extra, o czym w następnym wpisie 😉

A wygląda to tak:
Kodzik nie jest za bardzo złożony, tak naprawdę obsługę belek mamy już zrobioną, więc zrobiłem obsługę cyfr, ale ona i tak będzie obsłużona pewnie inaczej i w innym miejscu 😉

private void createReadyView() {
    firstRand = random.nextInt(6);
    secondRand = random.nextInt(6);
    if (firstRun) {
        bricksFirstArray = stackBricks.getBricksStack(includeFirstStack,
   firstRand);
        bricksSecondArray = stackBricks.getBricksStack(includeSecondStack,
   secondRand);
        bricksResultArray = stackBricks.getBricksStack(includeResultStack);
        firstRun = false;
    } else {
        bricksFirstArray = stackBricks.refreshStack(bricksFirstArray, 
   firstRand);
        bricksSecondArray = stackBricks.refreshStack(bricksSecondArray, 
   secondRand);
        bricksResultArray = stackBricks.refreshStack(bricksResultArray);
    }
    counter = 0;
    firstStackCounterTV.setText(String.valueOf(firstRand));
    secondStackCounterTV.setText(String.valueOf(secondRand));
    resultStackCounterTV.setText(String.valueOf(counter));
    result = firstRand + secondRand;
}
Wywołujemy tą metodę, która decyduje czy jest to pierwsze, czy kolejne jej uruchomienie. W przypadku pierwszego łączy widoki i wyświetla odpowiednią ilość belek, w przypadku kolejnego, po prostu losujemy ile belek ma się wyświetlać. Ponadto losujemy cyfrę, którą ustawiamy, jako napis pod stosem i po kliknięciu przez użytkownika sprawdzamy, czy suma cyfr zgadza się z wynikiem.
W tej aktywności po raz pierwszy zostały pokazane też operatory arytmetyczne dodawania i znaku równości. Mam nadzieję, że taki nieinwazyjny sposób uświadomi użytkownikom, co one oznaczają.

 

Pozdrawiam!

#7 Porównywanie stosów

W dwóch ostatnich postach pokazywałem jak zrobić animację na ścieżkach. Dzisiaj pokażę w jaki sposób wykorzystałem te animację.

Efekt który uzyskałem prezentuje się w ten sposób:

Chodziło o to, aby zwrócić uwagę dzieciaków na to, kiedy ilość jest w równowadze. Tzn, jeśli po lewej mamy tyle samo obiektów jak po prawej, to kolor FAB zmienia się na zielony. Jeśli zmieniamy te ilości przycisk odpowiednio reaguje.
Kodzik do tego nie jest zbytnio skomplikowany, wszystko dokładnie można obejrzeć na gicie, wkleję tylko kawałki:
public void onClickCompareOperations(View view) {
    switch (view.getId()) {
        case R.id.plusLeftBtn:
            if (counterLeft < 10) {
                counterLeft++;
                stackBricksViewGroup.refreshView(counterLeft, bricksLeftArray, 
      getApplicationContext());
            }
            break;
        case R.id.minusLeftBtn:
            if (counterLeft > 0) {
                counterLeft--;
                stackBricksViewGroup.refreshView(counterLeft, bricksLeftArray,
              getApplicationContext());
            }
            break;
        case R.id.plusRightBtn:
            if (counterRight < 10) {
                counterRight++;
                stackBricksViewGroup.refreshView(counterRight, bricksRightArray, 
      getApplicationContext());
            }
            break;
        case R.id.minusRightBtn:
            if (counterRight > 0) {
                counterRight--;
                stackBricksViewGroup.refreshView(counterRight, bricksRightArray, 
     getApplicationContext());
            }
            break;
    }
    if(counterLeft!=counterRight&&firstChange) {
        morphAnim.animFab(R.drawable.ic_done_to_undone, false);
        firstChange=false;
    }
    if(counterLeft==counterRight) {
        morphAnim.animFab(R.drawable.ic_undone_to_done, true);
        firstChange=true;
    }
}

Jak widać po każdej zmianie sprawdzamy co było kliknięte, odświeżamy odpowiedni widok i odświeżamy fab.

public void animFab(int resId, boolean success) {
    final Animatable icon = (Animatable) ResourcesCompat.getDrawable(context, resId);
    floatingActionButton.setImageDrawable((Drawable) icon);
    icon.start();
    if(success)
        floatingActionButton.setBackgroundTintList(context.getResources()
            .getColorStateList(R.color.colorSuccessGreen));
    else
        floatingActionButton.setBackgroundTintList(context.getResources()
     .getColorStateList(R.color.colorFailureRed));
}
Sama animacja Fab to również tylko kilka linijek kodu, ponieważ lwią pracę ostatnio odwaliliśmy po stronie xmla.
Następnym krokiem będzie stworzenie aktywności, która będzie sprawdzała po kliknięciu, czy stosy są w równowadze i wyświetlała tą informację.
Pozdrawiam!

#6 Morphing – animujemy floating action button cz.2 ścieżki

W poprzedniej części opisałem jak stworzyć animację morphingu bez jednego aspektu, mianowicie ścieżek, czyli rzeczy zgoła najpotrzebniejszej. Dlatego dzisiaj skupimy się na ścieżkach.

Przykładowa ścieżka wygląda tak:

M9,16.2 L4.8,12 L3.4,13.4 L9,19 L21,7 L19.6,5.6 L9,16.2 Z

W języku svg tak:

<svg fill="#FFFFFF" height="48" 
        viewBox="0 0 24 24" width="48" 
  xmlns="http://www.w3.org/2000/svg">
    <path d="M0 0h24v24H0z" fill="none"/>
    <path d="M9 16.2L4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4L9 
     16.2z"/>
</svg>

Z kolei jako png tak (kliknij aby zobaczyć):

Główna zasada tworzenia ścieżek do morphingu jest taka, że muszą być kompatybilne, tzn muszą być stworzone z takiej samej ilości elementów, czyli liter i cyfr przy nich, poukładanych w takiej samej kolejności, różniących się oczywiście zawartością, np:
<string name="path_undone">M 19.0,6.41 L 17.59,5.0 L 12.0,10.59 L 6.41,5.0 L 5.0,6.41 L 10.59,12.0 L 5.0,17.59 L 6.41,19.0 L 12.0,13.41 v 0.0 l 0.0,0.0 l 0.0,0.0 v 0.0 c 0.0,0.0,0.0,0.0,0.0,0.0 c 0.0,0.0,0.0,0.0,0.0,0.0 L 17.59,19.0 c 0.0,0.0,0.0,0.0,0.0,0.0 c 0.0,0.0,0.0,0.0,0.0,0.0 L 19.0,17.59 m 0.0,0.0 L 13.41,12.0 c 0.0,0.0,0.0,0.0,0.0,0.0 c 0.0,0.0,0.0,0.0,0.0,0.0 v 0.0 l 0.0,0.0 l 0.0,0.0 v 0.0 c 0.0,0.0,0.0,0.0,0.0,0.0 c 0.0,0.0,0.0,0.0,0.0,0.0 L 19.0,6.41 Z</string>
<string name="path_repeat">M 12.0,6.0 L 12.0,6.0 L 12.0,6.0 L 12.0,6.0 L 12.0,6.0 L 12.0,6.0 L 12.0,6.0 L 12.0,6.0 L 12.0,6.0 v 3.0 l 4.0,-4.0 l -4.0,-4.0 v 3.0 c -4.42,0.0,-8.0,3.58,-8.0,8.0 c 0.0,1.57,0.46,3.03,1.24,4.26 L 6.7,14.8 c -0.45,-0.83,-0.7,-1.79,-0.7,-2.8 c 0.0,-3.31,2.69,-6.0,6.0,-6.0 L 12.0,6.0 m 6.76,1.74 L 17.3,9.2 c 0.44,0.84,0.7,1.79,0.7,2.8 c 0.0,3.31,-2.69,6.0,-6.0,6.0 v -3.0 l -4.0,4.0 l 4.0,4.0 v -3.0 c 4.42,0.0,8.0,-3.58,8.0,-8.0 c 0.0,-1.57,-0.46,-3.03,-1.24,-4.26 L 18.76,7.74 Z</string>

Widzimy tutaj sporo 0, ale dzięki temu uzyskujemy kompatybilność, a efekt który dają nam te ścieżki w zwolnionym tempie wygląda tak:

Noo dobra, wytłumaczyłem jak to musi wyglądać, teraz jak transformować pliki svg na ścieżki? Na początku trafiłem na stronę svg2android. Jeśli wrzucimy tam plik svg, i zaznaczymy opcję:
„Bake transforms into path (experimental)”
to otrzymamy poprawną ścieżkę. To samo robimy z drugim plikiem do którego chcemy morphować i voilla. Chociaż nie do końca, bo jak pisałem powyżej w zależności od złożoności ikony możemy otrzymać różne długości ścieżek i trzeba to wyrównać, można to zrobić oczywiście ręcznie jeśli ścieżka jest krótka jak tutaj:
 
<string name="path_line">M22,12 L18,8 L18,11 L3,11 L3,13 L18,13 L18,16 Z</string>
<string name="path_done">M9,16.2 L4.8,12 L3.4,13.4 L9,19 L21,7 L19.6,5.6 L9,16.2 Z</string>

Które to ścieżki dają nam taki efekt:

Jest jednak szybszy sposób 😉
Biblioteka vectalign, pobierany sobie stamtąd plik .jar, uruchamiamy go i podajemy paramtery –start nazwa pierwszego svg, –end nazwa drugiego svg tak wygląda efekt:
Kopiujemy sobie ścieżki z pliku wynikowego i uzyskujemy bardzo ładną animację, np taką:
Dla porządku dodam jeszcze ścieżki dla tej konkretnej animacji:
 
<string name="path_line">M22,12   L18,8  L18,8  L18,11  L18,11  L3,11 L3,11  L3,13  L3,13 L18,13  L18,13  L18,16 Z</string>
<string name="path_undone">M19,6.41 L17.59,5 L12,10.59 L6.41,5 L5,6.41 L10.59,12 L5,17.59  L6.41,19  L12,13.41 L17.59,19 L19,17.59 L13.41,12 Z</string>
I to już wszystko co udało mi się odkryć w temacie morphingu, tak naprawdę dowolną ikonę możemy przerobić na svg, a następnie na ścieżkę, dlatego mam wrażenie że w projekcie jeszcze pojawi się tego typu animacja nie raz i to niekoniecznie na tak małych obiektach jak floating action button 😉
Pozdrawiam!

#5 Morphing – animujemy floating action button cz.1

Razem z pojawieniem się Material Design, Androida Lollipop wprowadzono nowy sposób przechowywania ikon. Zamiast plików graficznych jak np png postawiono na zgodny z ideą flat design plik typu svg. Nietrudno zrozumieć taką decyzję:

xxxhdpi to rozmiar dla fullHd, ileż jeszcze można tych x dodać, żeby obsługiwać 4k, albo w przyszłości 16k? 😉 Svg ma ten plus, że skaluje się bez utraty jakości, tzn jest jeden plik, który obsłuży wszystkie rozdzielczości. Dla bardziej zainteresowanych standardem, który opracował W3C zresztą link.

Aplikacji które korzystały by jednak z tego typu rozwiązań jakoś błyskawicznie nie przybywa (png znajdujący się w folderze xxxhdpi przeskaluje się na ekranie 4k, a że smartfony mają rozmiar jakieś 6-7 cali te większe, tablety jakieś 10 cali, to i tak tego gołym okiem nie widać. Może na telewizorze 4k to widać, jak się patrzy z bliska, ale nie po to są telewizory, żeby patrzeć z bliska ;). Dlatego też pliki png mają się dobrze. Zaletą stosowania svg jest możliwość korzystania z morphingu, który na png musielibyśmy wywołać jakimś zewnętrznym programem, przerabiając go zresztą na gifa. No i tak ten gif by się potem skalował na większy ekran.. Ok, wiemy już, że powinniśmy korzystać z svg. Samo korzystanie jest takie samo jak z png w Androidzie, wrzucamy plik tylko do jednego folderu: drawable, a widać go wszędzie. A teraz zabierzmy się za morphing, ufff trochę czasu mi zajęło rozgryzienie tego.

Aby móc użyć animacji morphingu na androidzie poniżej wersji 5.0 skorzystałem z biblioteki vector-compat, która dostarczyła kilka gotowych animacji:

Nie pasowały one jednak do tego co chciałem uzyskać, dlatego też zrobiłem kilka swoich. Oto jak się to robi w androidzie.
Zacznę może od kodu w javie, musimy odnieść się do pliku xml typu animated vector:
final Animatable icon = (Animatable) ResourcesCompat.getDrawable
      (getApplicationContext(), R.drawable.ic_line_to_done);
fab.setImageDrawable((Drawable)icon);
icon.start();
Zawartość tego pliku (ic_line_to_done.xml) to:
<?xml version="1.0" encoding="utf-8"?>
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/ic_line_vector">
    <target
        android:name="rotationGroup"
        android:animation="@anim/line_to_done_rotation" />
    <target
        android:name="v"
        android:animation="@anim/line_to_done_path" />
</animated-vector>
Gdzie widzimy 3 istotne rzeczy:
– android:drawable, czyli lokalizację opisu naszej początkowej ikony, tej od której będzie zaczynała się animacja
– target totationGroup, czyli odnośnik do aimacji rotacji, przed zmianą ikony następuje obrócenie aktualnej, taki efekt dodający fantazji 😉
-target v, czyli właściwy odnośnik do naszej animacji morphingu
Plik line_to_done_rotation, czyli nasz obrót:
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="@integer/anim_duration"
    android:propertyName="rotation"
    android:valueFrom="0"
    android:valueTo="360"/>
Nic trudnego, po prostu zwykły obrót ikony, trwający 200ms. Plik line_to_done_path, czyli zmiana naszych ścieżek:
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"

    android:duration="@integer/anim_duration"
    android:propertyName="pathData"
    android:valueFrom="@string/path_line"
    android:valueTo="@string/path_done"
    android:valueType="pathType"
    app:vc_valueType="pathType"/>
Tutaj również jest łatwo, zwracam tylko uwagę na app:vc_valueType którego potrzebuje vector_comapt, żeby działać na starszych urządzeniach.
No i plik drawable, jest typu vector, oto jak wygląda:
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:width="48dp"
    android:height="48dp"
    android:viewportHeight="24"
    android:viewportWidth="24"

    app:vc_viewportHeight="24"
    app:vc_viewportWidth="24">
    <group
        android:name="rotationGroup"
        android:pivotX="12.0"
        android:pivotY="12.0"
        android:rotation="360.0">

        <path
            android:name="v"
            android:fillColor="#FFFFFF"
            android:pathData="@string/path_line"

            app:vc_fillColor="#FFFFFF"
            app:vc_pathData="@string/path_line" />
    </group>
</vector>
Mamy tutaj grupę w której znajduje się plik path, czyli tak jak pisałem powyżej ścieżka opisująca wygląd naszej ikony. I przechodzimy do rzeczy najtrudniejszej, czyli właśnie ścieżek, oto jak przykładowo wyglądają:
M 48.0,54.0 L 31.0,42.0 L 15.0,54.0 L 21.0,35.0 L 6.0,23.0 L 25.0,23.0 L 25.0,23.0 L 25.0,23.0 L 25.0,23.0 L 32.0,4.0 L 40.0,23.0 L 58.0,23.0 L 42.0,35.0 L 48.0,54.0 
 
M 48.0,54.0 L 48.0,54.0 L 48.0,54.0 L 48.0,54.0 L 31.0,54.0 L 15.0,54.0 L 10.0,35.0 L 6.0,23.0 L 25.0,10.0 L 32.0,4.0 L 40.0,10.0 L 58.0,23.0 L 54.0,35.0 L 48.0,54.0
Mam nadzieję, że zaciekawieni, w następnej części opiszę jak uzyskać prawidłowe ścieżki z ikon znajdujących się tutaj. Bez tłumaczenia co oznaczają te liczby i litery, skupię się po prostu na tym w jaki sposób te ścieżki uzyskać i móc morfować dowolne ikony 😉

Finalnie uzyskałem takie efekty.

Pozdrawiam!

Floating Action Button dzięki Android Design Support Library

Będzie dzisiaj o wyglądzie aplikacji na Android, a konkretnie bibliotece:
Android Design Support Library
Chciało by się powiedzieć: wreszcie. Google chciało promować Material Design, a na urządzeniach starszych niż Lollipop nie dało się go tak łatwo zaimplementować. Z sytuacją walczyli niezależni developerzy, tworząc biblioteki pozwalające na prostszą implementację niektórych elementów, ale co biblioteka od Google, to jednak od Google. Dzisiaj właśnie korzystałem z niej pierwszy raz do utworzenia czegoś, na co w skrócie mówi się FAB, czyli Floating Action Button. Chodzi konkretnie o ten button:

Mała przydatna rzecz, najczęściej po prawej stronie na dole. Rzuca ładny cień, jak widać. Animuje się zapełniając, nazywa się to ripple effect. Ale do kodu, aby zacząć korzystać z biblioteki musimy dodać ją do pliku build.gradle
compile 'com.android.support:design:22.2.0′

Mamy pierwszą niezaprzeczalną zaletę, nie wszystkie niezależne biblioteki dały się dodać do projektu w ten sposób, czasem trzeba było się nakombinować…..
Pokazuję teraz w jaki sposób utworzyć ten przycisk:

<android.support.design.widget.FloatingActionButton
        android:id=”@+id/fab”
        android:layout_width=”56dp”
        android:layout_height=”56dp”
        android:layout_gravity=”bottom|end”
        android:layout_margin=”32dp”
        android:src=”@drawable/ic_add”
        android:onClick=”plusClick”
        app:elevation=”10dp”
        app:borderWidth=”0dp” />

A do nagłówka z plikiem zawierającym wygląd naszego ekranu, który zawiera nasz przycisk, dodajemy:

xmlns:app=”http://schemas.android.com/apk/res-auto”

I już, gotowe, nasz przycisk wygląda jak by pięknie unosił się nad powierzchnią. Prawda, że proste i przyjemne? Myślę, że elementy w designie opisują same siebie swoimi nazwami, jeśli coś jest nie jasne, to zachęcam do zabawy, czyli zmieniania wartości i patrzenia na wyniki, chyba w ten sposób tworzy się najdoskonalszy design. A kto nie lubi, zapraszam do zapoznania się z dokumentacją. Mogę jeszcze pokazać dwa ciekawe parametry:

app:fabSize=”normal”
app:rippleColor=””

FabSize może przyjąć jeszcze parametr mini, z kolei rippleColor to kolor efektu zapełniania przycisku. Aby najlepiej go dojrzeć można przytrzymać placem przycisk, wtedy ten powoli się zapełni. Jeśli skopiowaliście kod, zaczniecie się zastanawiać skąd wziąć ten parametr src, czyli element znajdujący się w środku (na rysunku jest to gwiazdka), najczęściej jednak potrzebujemy +. Już podaję link:
Znajdujemy tam to co nam aktualnie potrzebne i pobieramy. Teraz mamy już wszystko, aby tworzyć zgodne z wytycznymi Google przyciski typu fab w naszej aplikacji.
Pozdrawiam!