Co oznacza parametr attachToRoot w LayoutInflater?


201

LayoutInflater.inflateDokumentacja nie jest dokładnie wyczyścić mi o celów attachToRootparametru.

attachToRoot : czy zawyżona hierarchia powinna być dołączona do parametru root? Jeśli false, root jest używany tylko do utworzenia poprawnej podklasy LayoutParams dla widoku root w XML.

Czy ktoś mógłby wyjaśnić bardziej szczegółowo, w szczególności, czym jest widok główny, a może pokazać przykład zmiany w zachowaniu między truei falsewartościami?



Odpowiedzi:


157

TERAZ LUB NIE TERAZ

Główną różnicą między „trzecim” parametrem attachToRoot, który ma wartość true lub false, jest to.

Po wstawieniu attachToRoot

true: dodaj widok potomka do rodzica PRAWO TERAZ
false: dodaj widok potomka do rodzica NIE TERAZ .
Dodaj to później. `

Kiedy to jest później ?

Później używasz np parent.addView(childView)

Częstym nieporozumieniem jest to, że jeśli parametr attachToRoot ma wartość false, widok potomny nie zostanie dodany do elementu nadrzędnego. ŹLE
W obu przypadkach widok potomny zostanie dodany do ParentView. To tylko kwestia czasu .

inflater.inflate(child,parent,false);
parent.addView(child);   

jest równa

inflater.inflate(child,parent,true);

WIELKIE NIE NIE
Nigdy nie należy przekazywać attachToRoot jako wartości true, jeśli nie jesteś odpowiedzialny za dodanie widoku potomka do rodzica.
Np. Podczas dodawania fragmentu

public View onCreateView(LayoutInflater inflater,ViewGroup parent,Bundle bundle)
  {
        super.onCreateView(inflater,parent,bundle);
        View view = inflater.inflate(R.layout.image_fragment,parent,false);
        .....
        return view;
  }

jeśli podasz trzeci parametr jako true, otrzymasz IllegalStateException z powodu tego faceta.

getSupportFragmentManager()
      .beginTransaction()
      .add(parent, childFragment)
      .commit();

Ponieważ już przez pomyłkę dodałeś fragment potomny w onCreateView (). Wywołanie add powie ci, że widok potomny jest już dodany do nadrzędnego Stąd IllegalStateException .
W tym przypadku nie jesteś odpowiedzialny za dodanie childView, FragmentManager jest odpowiedzialny. Więc zawsze podawaj false w tym przypadku.

UWAGA: Przeczytałem również, że ParentView nie dostanie childView touchEvents, jeśli attachToRoot ma wartość false. Ale nie przetestowałem tego.


6
Bardzo pomocne, szczególnie część dotycząca FragmentManager, dziękuję!
CybeX,

94

Jeśli ustawione na true, to kiedy twój układ zostanie zawyżony, zostanie automatycznie dodany do hierarchii widoków grupy ViewGroup określonej w drugim parametrze jako dziecko. Na przykład, jeśli parametr root był a, LinearLayoutwówczas nadmuchany widok zostanie automatycznie dodany jako element potomny tego widoku.

Jeśli jest ustawiony na false, układ zostanie zawyżony, ale nie zostanie dołączony do żadnego innego układu (więc nie będzie rysowany, odbiera zdarzeń dotykowych itp.).


17
Jestem zmieszany. Ja dostaję „Określone dziecko ma już błędu dominująca”, dopóki nie przeczytałem tej odpowiedzi , które skierowałam do wykorzystania falsena attachToRootczasie moja Fragment użytkownika onCreateView. To rozwiązało problem i jeszcze układ fragment jest widoczny i aktywny, mimo swojej odpowiedzi. Co się dzieje? tutaj?
Jeff Axelrod

67
Ponieważ fragment automatycznie dołącza układ zwrócony z onCreateView. Więc jeśli załączysz go ręcznie w onCreateView, wtedy twój widok zostanie dołączony do 2 rodziców (co powoduje błąd, o którym wspomniałeś).
Joseph Earl

11
Jestem tu trochę zdezorientowany, @JosephEarl powiedziałeś, że jeśli ustawione na true, widok jest dołączony do drugiego parametru, który jest container, ale potem mówisz, że fragment jest automatycznie dołączany onCreateView(), więc o ile rozumiem, trzeci parametr jest bezużyteczny i powinien zostać ustawiony falsezawsze?
unmultimedio

5
Widok jest zwracany w widoku oncreateview, a następnie jest automatycznie dołączany. Jeśli ustawisz attach na true, generowany jest błąd. Jednak po nadmuchaniu widoku w samodzielnej sytuacji można automatycznie dołączyć widok do jego kontenera, ustawiając wartość true. Prawie nigdy nie ustawiałem się w prawdę, ponieważ zawsze dodaję pogląd.
frostymarvelous

7
@unmultimedio jest to bezużyteczne tylko dla widoku głównego zwróconego przez onCreateView. Jeśli napompujesz kolejne układy do tego widoku głównego lub napompujesz w innym kontekście (np. W działaniu), wtedy jest to przydatne.
Joseph Earl

36

Wygląda na to, że w odpowiedziach jest dużo tekstu, ale brak kodu, dlatego postanowiłem ożywić to stare pytanie za pomocą przykładu kodu, w kilku odpowiedziach wspomnianych przez ludzi:

Jeśli ustawione na true, to kiedy twój układ zostanie zawyżony, zostanie automatycznie dodany do hierarchii widoków grupy ViewGroup określonej w drugim parametrze jako dziecko.

Co to właściwie oznacza w kodzie (co rozumie większość programistów):

public class MyCustomLayout extends LinearLayout {
    public MyCustomLayout(Context context) {
        super(context);
        // Inflate the view from the layout resource and pass it as child of mine (Notice I'm a LinearLayout class).

        LayoutInflater.from(context).inflate(R.layout.child_view, this, true);
    }
}

Zauważ, że poprzedni kod dodaje układ R.layout.child_viewjako element potomny z MyCustomLayoutpowodu attachToRootparametrów truei przypisuje parametry układu elementu nadrzędnego dokładnie w taki sam sposób, jakbym używał addViewprogramowo lub tak, jakbym to zrobił w xml:

<LinearLayout>
   <View.../>
   ...
</LinearLayout>

Poniższy kod wyjaśnia scenariusz przy przekazywaniu attachRootjako false:

LinearLayout linearLayout = new LinearLayout(context);
linearLayout.setLayoutParams(new LayoutParams(
    LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
linearLayout.setOrientation(LinearLayout.VERTICAL);
    // Create a stand-alone view
View myView = LayoutInflater.from(context)
    .inflate(R.layout.ownRootView, null, false);
linearLayout.addView(myView);

W poprzednim kodzie określasz, że chcesz myViewbyć jego własnym obiektem głównym i nie dołączasz go do żadnego elementu nadrzędnego, później dodaliśmy go jako część, LinearLayoutale przez chwilę był to widok autonomiczny (bez elementu nadrzędnego).

To samo dzieje się z Fragmentami, możesz dodać je do już istniejącej grupy i być jej częścią lub po prostu przekazać parametry:

inflater.inflate (R.layout.fragment, null, false);

Aby określić, że będzie to jego własny root.


1
To było najbardziej pomocne.
Wahib Ul Haq,

26

Dokumentacja i dwie poprzednie odpowiedzi powinny wystarczyć, tylko kilka myśli ode mnie.

Ta inflatemetoda służy do nadmuchiwania plików układu. Z tymi zawyżonymi układami musisz mieć możliwość dołączenia ich bezpośrednio do elementu nadrzędnego ViewGrouplub po prostu nadmuchania hierarchii widoków z tego pliku układu i pracy z nią poza normalną hierarchią widoków.

W pierwszym przypadku attachToRootparametr będzie musiał być ustawiony na true(lub o wiele prostsze użycie inflatemetody, która pobiera plik układu i nadrzędny katalog główny ViewGroup(inny niż null)). W tym przypadku Viewzwracana jest po prostu ViewGroupmetoda przekazana w metodzie, ViewGroupdo której zostanie dodana zawyżona hierarchia widoków.

W przypadku drugiej opcji zwracany Viewjest katalog główny ViewGroupz pliku układu. Jeśli pamiętasz naszą ostatnią dyskusję z include-mergepytania o parę, jest to jeden z powodów mergeograniczenia (gdy plik układu z mergerootem jest zawyżony, musisz podać element nadrzędny i attachedToRootustawić na true). Jeśli miałeś plik układu z mergetagiem głównym i attachedToRootustawiono go na, falsewówczas inflatemetoda nie będzie miała nic do zwrócenia, ponieważ mergenie ma odpowiednika. Ponadto, jak napisano w dokumentacji, ważna jest inflatewersja z attachToRootustawionym na, falseponieważ można utworzyć prawidłową hierarchię widokówLayoutParamsod rodzica. Jest to ważne w niektórych przypadkach, szczególnie w przypadku dzieci AdapterView, podklasaViewGroup , dla którychaddView()zestaw metod nie jest obsługiwany. Jestem pewien, że pamiętasz, używając tej linii w getView()metodzie:

convertView = inflater.inflate(R.layout.row_layout, parent, false);

Ta linia zapewnia, że ​​zawyżony R.layout.row_layoutplik ma poprawną wartość LayoutParamsz AdapterViewpodklasy ustawionej w katalogu głównym ViewGroup. Jeśli nie zrobiłbyś tego, możesz mieć problemy z plikiem układu, jeśli root byłby RelativeLayout. Te TableLayout/TableRowmają również specjalne i ważne LayoutParamsi powinieneś upewnić się, że widoki w nich mają poprawne LayoutParams.


18

Ja również mylić o tym, co było prawdziwym celem attachToRootw inflatemetodzie. Po nieco przestudiowaniu interfejsu użytkownika w końcu uzyskałem odpowiedź:

rodzic:

w tym przypadku jest widżet / układ otaczający obiekty widoku, które chcesz nadmuchać za pomocą findViewById ().

attachToRoot:

dołącza widoki do ich elementów nadrzędnych (obejmuje je w hierarchii elementów nadrzędnych), więc każde zdarzenie dotykowe, które otrzymają widoki, zostanie również przeniesione do widoku elementu nadrzędnego. Teraz od rodzica zależy, czy chce bawić się tymi wydarzeniami, czy je zignorować. jeśli ustawione na false, nie są dodawane jako bezpośrednie dzieci rodzica, a rodzic nie odbiera żadnych zdarzeń dotykowych z widoków.

Mam nadzieję, że to rozwiąże zamieszanie


Twoja odpowiedź jest już dostępna tutaj: stackoverflow.com/questions/22326314/...
Neon Warge

11

Napisałem tę odpowiedź, ponieważ nawet po przejrzeniu kilku stron StackOverflow nie byłem w stanie jasno zrozumieć, co znaczy attachToRoot. Poniżej znajduje się metoda inflate () w klasie LayoutInflater.

View inflate (int resource, ViewGroup root, boolean attachToRoot)

Spójrz na plik activity_main.xml , układ button.xml i utworzony przez mnie plik MainActivity.java .

Activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/root"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

</LinearLayout>

button.xml

<Button xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />

MainActivity.java

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

    LayoutInflater inflater = getLayoutInflater();
    LinearLayout root = (LinearLayout) findViewById(R.id.root);
    View view = inflater.inflate(R.layout.button, root, false);
}

Kiedy uruchomimy kod, nie zobaczymy przycisku w układzie. Wynika to z faktu, że nasz układ przycisków nie jest dodawany do głównego układu działania, ponieważ attachToRoot ma wartość false.

LinearLayout ma metodę addView (widok widoku) , której można użyć do dodania widoków do LinearLayout. Spowoduje to dodanie układu przycisku do głównego układu działania i sprawi, że przycisk będzie widoczny po uruchomieniu kodu.

root.addView(view);

Usuńmy poprzedni wiersz i zobaczmy, co się stanie, gdy ustawimy attachToRoot na true.

View view = inflater.inflate(R.layout.button, root, true);

Ponownie widzimy, że układ przycisku jest widoczny. Wynika to z tego, że attachToRoot bezpośrednio dołącza zawyżony układ do określonego elementu nadrzędnego. Który w tym przypadku jest root LinearLayout. Tutaj nie musimy dodawać widoków ręcznie, jak to zrobiliśmy w poprzednim przypadku z metodą addView (widok widoku).

Dlaczego ludzie otrzymują wyjątek IllegalStateException, gdy parametr attachToRoot ma wartość true dla fragmentu?

Jest tak, ponieważ dla fragmentu, który już określiłeś, gdzie chcesz umieścić układ fragmentu w pliku aktywności.

FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
    .add(R.id.root, fragment)
    .commit();

Add (int rodzic, fragment Fragment) dodaje się fragment, który ma swój układ do układu nadrzędnego. Jeśli ustawimy attachToRoot jako true, otrzymasz IllegalStateException: Określone dziecko ma już rodzica. Ponieważ układ fragmentów jest już dodany do układu nadrzędnego w metodzie add ().

Zawsze powinieneś podawać wartość false dla attachToRoot, gdy nadmuchujesz Fragmenty. Zadaniem FragmentManager jest dodawanie, usuwanie i zastępowanie Fragmentów.

Wróć do mojego przykładu. Co jeśli zrobimy jedno i drugie.

View view = inflater.inflate(R.layout.button, root, true);
root.addView(view);

W pierwszym wierszu LayoutInflater dołącza układ przycisków do układu głównego i zwraca obiekt View zawierający ten sam układ przycisków. W drugim wierszu dodajemy ten sam obiekt View do nadrzędnego układu głównego. Powoduje to ten sam wyjątek IllegalStateException, który widzieliśmy w przypadku fragmentów (określone dziecko ma już element nadrzędny).

Należy pamiętać, że istnieje inna metoda przeciążenia inflate (), która domyślnie ustawia attachToRoot na true.

View inflate (int resource, ViewGroup root)

Proste i jasne wyjaśnienie, właśnie tego szukałem!
flyingAssistant

10

Istnieje wiele nieporozumień na ten temat z powodu dokumentacji dla metody inflate ().

Ogólnie, jeśli attachToRoot ma wartość true, plik układu określony w pierwszym parametrze jest nadmuchiwany i dołączany do grupy ViewGroup określonej w drugim parametrze w tym momencie. Gdy właściwość attachToRoot ma wartość false, plik układu z pierwszego parametru jest zawyżany i zwracany jako widok, a dowolny załącznik widoku ma miejsce w innym czasie.

To chyba nie znaczy wiele, chyba że zobaczysz wiele przykładów. Podczas wywoływania LayoutInflater.inflate () w metodzie onCreateView fragmentu, będziesz chciał przekazać wartość false dla attachToRoot, ponieważ działanie powiązane z tym fragmentem jest w rzeczywistości odpowiedzialne za dodanie widoku tego fragmentu. Jeśli ręcznie pompujesz i dodajesz widok do innego widoku w późniejszym czasie, na przykład przy użyciu metody addView (), będziesz chciał przekazać wartość false dla attachToRoot, ponieważ załącznik przychodzi w późniejszym czasie.

O kilku innych unikalnych przykładach dotyczących okien dialogowych i niestandardowych widoków możesz przeczytać w poście na blogu, który napisałem na ten temat.

https://www.bignerdranch.com/blog/understanding-androids-layoutinflater-inflate/


4

attachToRootwartość true oznacza, że inflatedViewzostanie dodany do hierarchii widoku rodzica. W ten sposób użytkownicy mogą „widzieć” i wyczuwać zdarzenia dotykowe (lub dowolne inne operacje interfejsu użytkownika). W przeciwnym razie został on właśnie utworzony, nie został dodany do żadnej hierarchii widoku, a zatem nie można go zobaczyć ani obsługiwać zdarzeń dotykowych.

W przypadku programistów iOS nowszych w systemie Android attachToRootwartość true oznacza, że ​​wywołujesz tę metodę:

[parent addSubview:inflatedView];

Jeśli pójdziesz dalej, możesz zapytać: Dlaczego powinienem przekazać widok rodzica, jeśli mam taką attachToRootopcję false? Jest tak, ponieważ element główny w drzewie XML potrzebuje widoku rodzica, aby obliczyć niektóre LayoutParams (np. Dopasowanie rodzica).


0

Po zdefiniowaniu elementu nadrzędnego attachToRoot określa, czy inflator ma faktycznie dołączyć go do elementu nadrzędnego, czy nie. W niektórych przypadkach powoduje to problemy, na przykład w ListAdapter spowoduje wyjątek, ponieważ lista próbuje dodać widok do listy, ale mówi, że jest już dołączona. W innym przypadku, gdy sam nadmuchujesz widok, aby dodać do działania, może być przydatny i oszczędzić Ci linię kodu.


1
nie daje wyraźnego obrazu, który powinna dać dobra odpowiedź.
Prakhar1001

0

Na przykład mamy an ImageView, a LinearLayouti a RelativeLayout. LinearLayout jest dzieckiem RelativeLayout. będzie Hierarchia widoków.

RelativeLayout
           ------->LinearLayout

i mamy osobny plik układu dla ImageView

image_view_layout.xml

Dołącz do katalogu głównego:

//here container is the LinearLayout

    View v = Inflater.Inflate(R.layout.image_view_layout,container,true);
  1. Tutaj v zawiera odniesienie do układu kontenera, tj. LinearLayout. I jeśli chcesz ustawić parametry takie jak setImageResource(R.drawable.np);ImageView, musisz je znaleźć przez odniesienie do rodzica, tj.view.findById()
  2. Rodzicem v będzie FrameLayout.
  3. LayoutParams będzie FrameLayout.

Nie dołączaj do katalogu głównego:

//here container is the LinearLayout
    View v = Inflater.Inflate(R.layout.image_view_layout,container,false);
  1. Tutaj v zawiera układ kontenera bez odniesienia, ale bezpośrednie odniesienie do ImageView, które jest zawyżone, dzięki czemu można ustawić jego parametry jak view.setImageResource(R.drawable.np); bez odwoływania się do tego findViewById. Ale kontener jest określony, aby ImageView pobierał LayoutParams kontenera, dzięki czemu można powiedzieć, że odwołanie do kontenera jest tylko dla LayoutParams.
  2. więc w szczególnym przypadku Rodzic będzie zerowy.
  3. LayoutParams będzie LinearLayout.

0

attachToRoot Ustaw na true:

Jeśli właściwość attachToRoot ma wartość true, plik układu określony w pierwszym parametrze jest nadmuchiwany i dołączany do grupy ViewGroup określonej w drugim parametrze.

Wyobraź sobie, że podaliśmy przycisk w pliku układu XML z szerokością i wysokością układu ustawioną na match_parent.

<Button xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/custom_button">
</Button>

Chcemy teraz programowo dodać ten przycisk do liniowego układu wewnątrz fragmentu lub działania. Jeśli nasz LinearLayout jest już zmienną składową mLinearLayout, możemy po prostu dodać przycisk w następujący sposób:

inflater.inflate(R.layout.custom_button, mLinearLayout, true);

Określiliśmy, że chcemy nadmuchać Button z jego pliku zasobów układu; następnie mówimy LayoutInflater, że chcemy dołączyć go do mLinearLayout. Nasze parametry układu są honorowane, ponieważ wiemy, że przycisk zostanie dodany do LinearLayout. Typem parametrów układu przycisku powinien być LinearLayout.LayoutParams.

attachToRoot Ustaw na wartość false (nie jest wymagane, aby użyć wartości false)

Jeśli właściwość attachToRoot ma wartość false, plik układu określony w pierwszym parametrze jest zawyżany i nie jest dołączany do grupy ViewGroup określonej w drugim parametrze, ale ten zawyżony widok uzyskuje LayoutParams rodzica, co umożliwia prawidłowe dopasowanie tego widoku do rodzica.


Przyjrzyjmy się, kiedy chcesz ustawić attachToRoot na false. W tym scenariuszu widok określony w pierwszym parametrze inflate () nie jest w tym momencie dołączany do grupy ViewGroup w drugim parametrze.

Przypomnijmy nasz przykład z wcześniejszego przycisku, w którym chcemy dołączyć niestandardowy przycisk z pliku układu do mLinearLayout. Nadal możemy dołączyć nasz przycisk do mLinearLayout, przekazując wartość false dla attachToRoot - po prostu dodajemy go samodzielnie.

Button button = (Button) inflater.inflate(R.layout.custom_button,    mLinearLayout, false);
mLinearLayout.addView(button);

Te dwa wiersze kodu są równoważne temu, co napisaliśmy wcześniej w jednym wierszu kodu, gdy przekazaliśmy true dla attachToRoot. Przekazując fałsz, mówimy, że nie chcemy jeszcze dołączać naszego widoku do głównej grupy ViewGroup. Mówimy, że stanie się to w innym momencie. W tym przykładzie innym momentem jest po prostu metoda addView () zastosowana bezpośrednio poniżej inflacji.

Fałszywy przykład attachToRoot wymaga nieco więcej pracy, gdy ręcznie dodamy widok do grupy ViewGroup.

attachToRoot Ustaw na wartość false (wymagana jest wartość false)

Podczas nadmuchiwania i zwracania widoku fragmentu w funkcji onCreateView (), należy podać wartość false dla parametru attachToRoot. Jeśli podasz true, otrzymasz IllegalStateException, ponieważ określone dziecko ma już rodzica. Powinieneś określić, gdzie widok Twojego Fragmentu zostanie umieszczony z powrotem w Twojej Aktywności. Zadaniem FragmentManager jest dodawanie, usuwanie i zastępowanie Fragmentów.

FragmentManager fragmentManager = getSupportFragmentManager();
Fragment fragment =  fragmentManager.findFragmentById(R.id.root_viewGroup);

if (fragment == null) {
fragment = new MainFragment();
fragmentManager.beginTransaction()
    .add(R.id.root_viewGroup, fragment)
    .commit();
}

Kontener root_viewGroup, który przechowa Twój Fragment w Twojej Aktywności, jest parametrem ViewGroup podanym w funkcji onCreateView () w Twoim Fragmentie. Jest to także grupa ViewGroup, którą przekazujesz do LayoutInflater.inflate (). FragmentManager poradzi sobie jednak z dołączaniem Widoku Fragmentu do tej grupy ViewGroup. Nie chcesz dołączać go dwa razy. Ustaw attachToRoot na false.

public View onCreateView(LayoutInflater inflater, ViewGroup  parentViewGroup, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_layout,     parentViewGroup, false);

return view;
}

Dlaczego otrzymujemy nadrzędną grupę ViewGroup naszego Fragmentu, jeśli nie chcemy dołączać jej do funkcji onCreateView ()? Dlaczego metoda inflate () żąda głównej grupy ViewGroup?

Okazuje się, że nawet jeśli nie dodajemy od razu naszego świeżo napompowanego Widoku do jego nadrzędnej grupy ViewGroup, powinniśmy nadal używać LayoutParams rodzica, aby nowy widok mógł określić jego rozmiar i pozycję, gdy tylko zostanie ostatecznie dołączony.

Link: https://youtu.be/1Y0LlmTCOkM?t=409


0

Po prostu dzieląc się niektórymi punktami, które napotkałem podczas pracy na ten temat,

Oprócz zaakceptowanej odpowiedzi chciałbym przedstawić kilka punktów, które mogą być pomocne.

Tak więc, kiedy użyłem attachToRoot jako true, zwracany widok był typu ViewGroup, tj. Główny root nadrzędnej grupy ViewGroup, która została przekazana jako parametr dla metody inflate (layoutResource, ViewGroup, attachToRoot) , nie typu układu, który został przekazany, ale w przypadku attachToRoot jako fałsz otrzymujemy typ zwracanej funkcji tego głównego układu ViewGroup źródła .

Pozwól mi wyjaśnić na przykładzie:

Jeśli mamy układ liniowy jako układ główny, a następnie chcemy dodać do niego TextView poprzez nadmuchanie funkcję .

następnie przy użyciu attachToRoot jako funkcji true inflate zwraca widok typu LinearLayout

podczas korzystania z attachToRoot jako funkcji fałszywego nadmuchu zwraca widok typu TextView

Mam nadzieję, że to odkrycie okaże się pomocne ...

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.