Wyjaśnienie widoku niestandardowego onMeasure

Próbowałem zrobić niestandardowy komponent. Rozszerzyłem klasę View i wykonałem rysowanie w onDraw overrided method. Dlaczego muszę nadpisać onMeasure? Jeśli nie, wszystko będzie dobrze. Czy ktoś może to wyjaśnić? Jak napisać moją metodę onMeasure? Widziałem kilka samouczków, ale każdy z nich jest trochę inny niż drugi. Czasami dzwonią super.onMeasure na końcu, czasami używają setMeasuredDimension i nie dzwonią. Gdzie jest różnica?

W końcu chcę użyć kilku dokładnie tych samych komponenty. Dodałem te komponenty do pliku XML, ale nie wiem, jak duże powinny być. Chcę ustawić jego pozycję i rozmiar później (dlaczego muszę ustawić rozmiar w onMeasure jeśli w {[1] } Kiedy rysuję, działa również) w niestandardowej klasie komponentów. Kiedy dokładnie mam to zrobić?

 282
Author: Tiago, 2012-09-04

2 answers

onMeasure() jest to Twoja okazja, aby powiedzieć Androidowi, jak duży chcesz, aby Twój niestandardowy widok był zależny od ograniczeń układu dostarczonych przez rodzica; jest to również okazja Twojego niestandardowego widoku, aby dowiedzieć się, jakie są te ograniczenia układu (w przypadku, gdy chcesz zachowywać się inaczej w sytuacji match_parent niż w sytuacji wrap_content). Ograniczenia te są pakowane do wartości MeasureSpec, które są przekazywane do metody. Oto przybliżona korelacja wartości trybu:

  • dokładnie oznacza, że wartość layout_width lub layout_height została ustawiona na określoną wartość. Powinieneś zrobić swój widok w takim rozmiarze. Może to być również wywołane, gdy match_parent jest używany, aby ustawić rozmiar dokładnie do widoku nadrzędnego (jest to zależne od układu w frameworku).
  • AT_MOST zazwyczaj oznacza, że wartość layout_width lub layout_height została ustawiona na match_parent lub wrap_content, gdzie wymagany jest maksymalny rozmiar (jest to zależne od układu w strukturze), a rozmiar nadrzędnego wymiaru jest wartością. Nie powinieneś być żadnym większy niż ten rozmiar.
  • nieokreślona zazwyczaj oznacza, że wartość layout_width lub layout_height została ustawiona na wrap_content bez ograniczeń. Możesz mieć dowolny rozmiar. Niektóre układy używają również tego połączenia zwrotnego, aby dowiedzieć się pożądanego rozmiaru, zanim określisz, jakie specyfikacje faktycznie przekażą cię ponownie w drugim żądaniu pomiaru.

Umowa, która istnieje z onMeasure() jest taka, że setMeasuredDimension() musi być wywołane na końcu z rozmiarem, jaki chcesz mieć widok. To metoda jest wywoływana przez wszystkie implementacje frameworka, w tym domyślną implementację znajdującą się w View, dlatego bezpieczne jest wywołanie super, jeśli pasuje to do twojego przypadku użycia.

Przyznane, ponieważ framework stosuje domyślną implementację, może nie być konieczne zastąpienie tej metody, ale możesz zobaczyć obcinanie w przypadkach, gdy przestrzeń widoku jest mniejsza niż zawartość, jeśli tego nie zrobisz, i jeśli ułożysz swój niestandardowy widok za pomocą wrap_content w obu kierunkach, twój widok będzie wyświetlany może się w ogóle nie pojawić, ponieważ framework nie wie, jak duży jest!

Ogólnie rzecz biorąc, jeśli nadpisujesz View, a nie inny istniejący widżet, prawdopodobnie dobrym pomysłem jest dostarczenie implementacji, nawet jeśli jest to tak proste, jak coś takiego:

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

    int desiredWidth = 100;
    int desiredHeight = 100;

    int widthMode = MeasureSpec.getMode(widthMeasureSpec);
    int widthSize = MeasureSpec.getSize(widthMeasureSpec);
    int heightMode = MeasureSpec.getMode(heightMeasureSpec);
    int heightSize = MeasureSpec.getSize(heightMeasureSpec);

    int width;
    int height;

    //Measure Width
    if (widthMode == MeasureSpec.EXACTLY) {
        //Must be this size
        width = widthSize;
    } else if (widthMode == MeasureSpec.AT_MOST) {
        //Can't be bigger than...
        width = Math.min(desiredWidth, widthSize);
    } else {
        //Be whatever you want
        width = desiredWidth;
    }

    //Measure Height
    if (heightMode == MeasureSpec.EXACTLY) {
        //Must be this size
        height = heightSize;
    } else if (heightMode == MeasureSpec.AT_MOST) {
        //Can't be bigger than...
        height = Math.min(desiredHeight, heightSize);
    } else {
        //Be whatever you want
        height = desiredHeight;
    }

    //MUST CALL THIS
    setMeasuredDimension(width, height);
}
Mam nadzieję, że to pomoże.
 681
Author: Devunwired,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-17 14:46:51

W rzeczywistości odpowiedź nie jest kompletna, ponieważ wartości zależą również od kontenera. W przypadku układów względnych lub liniowych wartości zachowują się następująco:

  • Dokładnie match_parent jest dokładnie + rozmiar rodzica
  • AT_MOST wrap_content daje wynik At_most MeasureSpec
  • nieokreślone nigdy nie wyzwalane

W przypadku poziomego przewijania kod będzie działał.

 4
Author: Florian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-30 07:42:28