Jaki jest prawidłowy sposób przesłaniania onMeasure ()? Widziałem różne podejścia. Na przykład Professional Android Development używa MeasureSpec do obliczenia wymiarów, a następnie kończy się wywołaniem metody setMeasuredDimension (). Na przykład:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
this.setMeasuredDimension(parentWidth/2, parentHeight);
}
Z drugiej strony, zgodnie z tym postem , „poprawnym” sposobem jest użycie MeasureSpec, wywołanie setMeasuredDimensions (), a następnie wywołanie setLayoutParams () i zakończenie wywołaniem super.onMeasure (). Na przykład:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
this.setMeasuredDimension(parentWidth/2, parentHeight);
this.setLayoutParams(new *ParentLayoutType*.LayoutParams(parentWidth/2,parentHeight));
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
Więc jaka jest właściwa droga? Żadne z tych podejść nie zadziałało dla mnie w 100%.
Myślę, że naprawdę pytam, czy ktoś zna samouczek, który wyjaśnia onMeasure (), układ, wymiary widoków potomnych itp.?
android
android-layout
U Avalos
źródło
źródło
Odpowiedzi:
Pozostałe rozwiązania nie są kompleksowe. W niektórych przypadkach mogą działać i są dobrym miejscem do rozpoczęcia, ale nie ma gwarancji, że będą działać.
Kiedy zadzwoni onMeasure, możesz mieć prawo do zmiany rozmiaru lub nie. Wartości, które są przekazywane do twojego onMeasure (
widthMeasureSpec
,heightMeasureSpec
) zawierają informacje o tym, co twój widok podrzędny może robić. Obecnie istnieją trzy wartości:MeasureSpec.UNSPECIFIED
- Możesz być tak duży, jak chceszMeasureSpec.AT_MOST
- Tak duży, jak chcesz (do rozmiaru specyfikacji), to jestparentWidth
w twoim przykładzie.MeasureSpec.EXACTLY
- Bez wyboru. Rodzic wybrał.Dzieje się tak, aby system Android mógł wykonać wiele przejść, aby znaleźć odpowiedni rozmiar dla każdego elementu. Więcej informacji można znaleźć tutaj .
Jeśli nie będziesz przestrzegać tych zasad, Twoje podejście nie będzie gwarantowane.
Na przykład, jeśli chcesz sprawdzić, czy w ogóle możesz zmienić rozmiar, możesz wykonać następujące czynności:
final int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec); final int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec); boolean resizeWidth = widthSpecMode != MeasureSpec.EXACTLY; boolean resizeHeight = heightSpecMode != MeasureSpec.EXACTLY;
Korzystając z tych informacji, będziesz wiedział, czy możesz modyfikować wartości w swoim kodzie. Lub jeśli musisz zrobić coś innego. Szybkim i łatwym sposobem ustalenia żądanego rozmiaru jest użycie jednej z następujących metod:
int solutionSizeAndState (int size, int measureSpec, int childMeasuredState)
intolveSize (int size, int measureSpec)
Podczas gdy pierwsza jest dostępna tylko w Honeycomb, druga jest dostępna we wszystkich wersjach.
Uwaga: może się okazać, że to
resizeWidth
lubresizeHeight
zawsze jest fałszywe. Okazało się, że tak jest, gdy o to prosiłemMATCH_PARENT
. Udało mi się to naprawić, żądającWRAP_CONTENT
w moim układzie nadrzędnym, a następnie podczas fazy NIEOKREŚLONEJ, żądając rozmiaruInteger.MAX_VALUE
. Dzięki temu uzyskasz maksymalny rozmiar, na jaki zezwala twój rodzic podczas następnego przejścia przez onMeasure.źródło
Dokumentacja jest autorytetem w tej sprawie: http://developer.android.com/guide/topics/ui/how-android-draws.html i http://developer.android.com/guide/topics/ui/custom -components.html
Podsumowując: na końcu swojej nadpisanej
onMeasure
metody powinieneś wywołaćsetMeasuredDimension
.Nie powinieneś dzwonić
super.onMeasure
po wywołaniusetMeasuredDimension
, to po prostu wykasuje wszystko, co ustawisz. W niektórych sytuacjach możesz chcieć wywołaćsuper.onMeasure
pierwszy, a następnie zmodyfikować wyniki, wywołującsetMeasuredDimension
.Nie nazywaj
setLayoutParams
sięonMeasure
. Układ następuje w drugim przejściu po pomiarze.źródło
Myślę, że to zależy od rodzica, nad którym masz pierwszeństwo.
Na przykład, jeśli rozszerzasz ViewGroup (jak FrameLayout), po zmierzeniu rozmiaru powinieneś wywołać jak poniżej
super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
ponieważ możesz chcieć ViewGroup zrobić resztę pracy (zrobić kilka rzeczy w widoku dziecka)
Jeśli rozszerzasz View (jak ImageView), możesz po prostu zadzwonić
this.setMeasuredDimension(width, height);
, ponieważ klasa nadrzędna po prostu zrobi coś, co zwykle robiłeś.super.onMeasure()
Jednym słowem, jeśli chcesz, aby niektóre funkcje oferowane przez twoją klasę nadrzędną były darmowe, powinieneś zadzwonić (zwykle w trybie MeasureSpec.EXACTLY), w przeciwnym raziethis.setMeasuredDimension(width, height);
wystarczy wywołanie .źródło
oto jak rozwiązałem problem:
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { .... setMeasuredDimension( measuredWidth, measuredHeight ); widthMeasureSpec = MeasureSpec.makeMeasureSpec( measuredWidth, MeasureSpec.EXACTLY ); heightMeasureSpec = MeasureSpec.makeMeasureSpec( measuredHeight, MeasureSpec.EXACTLY); super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
Ponadto było to konieczne dla komponentu ViewPager
źródło
super.onMeasure
czyści wymiary ustawione za pomocąsetMeasuredDimension
.W przypadku zmiany rozmiaru widoków w środku
onMeasure
wszystko czego potrzebujesz tosetMeasuredDimension
zadzwoń. Jeśli zmieniasz rozmiar pozaonMeasure
sobą, musisz zadzwonićsetLayoutParams
. Na przykład zmiana rozmiaru widoku tekstu po zmianie tekstu.źródło
Zależy od używanego sterowania. Instrukcje zawarte w dokumentacji działają dla niektórych kontrolek (TextView, Button, ...), ale nie dla innych (LinearLayout, ...). Sposobem, który działał dla mnie bardzo dobrze, było zadzwonienie do super, kiedy skończę. Na podstawie artykułu w poniższym linku.
http://humptydevelopers.blogspot.in/2013/05/android-view-overriding-onmeasure.html
źródło
Wydaje mi się, że setLayoutParams i ponowne obliczenie pomiarów jest obejściem umożliwiającym poprawną zmianę rozmiaru widoków podrzędnych, tak jak zwykle jest to wykonywane w onMeasure klasy pochodnej.
Jednak rzadko to działa poprawnie (z jakiegokolwiek powodu ...), lepiej wywołaj MeasureChildren (podczas tworzenia ViewGroup) lub spróbuj czegoś podobnego, gdy jest to konieczne.
źródło
możesz wziąć ten fragment kodu jako przykład onMeasure () ::
public class MyLayerLayout extends RelativeLayout { public MyLayerLayout(Context context) { super(context); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int parentWidth = MeasureSpec.getSize(widthMeasureSpec); int parentHeight = MeasureSpec.getSize(heightMeasureSpec); int currentChildCount = getChildCount(); for (int i = 0; i < currentChildCount; i++) { View currentChild = getChildAt(i); //code to find information int widthPercent = currentChildInfo.getWidth(); int heightPercent = currentChildInfo.getHeight(); //considering we will pass height & width as percentage int myWidth = (int) Math.round(parentWidth * (widthPercent / 100.0)); int myHeight = (int) Math.round(parentHeight * (heightPercent / 100.0)); //Considering we need to set horizontal & vertical position of the view in parent AlignmentTraitValue vAlign = currentChildInfo.getVerticalLocation() != null ? currentChildlayerInfo.getVerticalLocation() : currentChildAlignmentTraitValue.TOP; AlignmentTraitValue hAlign = currentChildInfo.getHorizontalLocation() != null ? currentChildlayerInfo.getHorizontalLocation() : currentChildAlignmentTraitValue.LEFT; int topPadding = 0; int leftPadding = 0; if (vAlign.equals(currentChildAlignmentTraitValue.CENTER)) { topPadding = (parentHeight - myHeight) / 2; } else if (vAlign.equals(currentChildAlignmentTraitValue.BOTTOM)) { topPadding = parentHeight - myHeight; } if (hAlign.equals(currentChildAlignmentTraitValue.CENTER)) { leftPadding = (parentWidth - myWidth) / 2; } else if (hAlign.equals(currentChildAlignmentTraitValue.RIGHT)) { leftPadding = parentWidth - myWidth; } LayoutParams myLayoutParams = new LayoutParams(myWidth, myHeight); currentChildLayoutParams.setMargins(leftPadding, topPadding, 0, 0); currentChild.setLayoutParams(myLayoutParams); } super.onMeasure(widthMeasureSpec, heightMeasureSpec); } }
źródło