Wie gehe ich mit Gewichten in onMeasue für benutzerdefinierte Ansichten um?
-
14-11-2019 - |
Frage
Ich habe eine benutzerdefinierte Ansicht, die ich erstelle, um die Schriftgröße des untergeordneten Elements zu skalieren TextViews
um alle in eine festgelegte Breite zu passen, befindet sich jede auf einer eigenen Linie.Offensichtlich wird es die Breite brauchen, um das herauszufinden.
Ich hatte überschrieben onMeasure()
wie so:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int lineWidth = widthSize - getPaddingLeft() - getPaddingRight();
// Change the text size until the largest line of text fits.
while (lineWidth < calculateTextWidth()) {
for (TextView textView : this.childViews) {
float newSize = textView.getTextSize() - 1;
textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, newSize);
}
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
calculateTextWidth()
berechnet die Breite der größten Textzeile und damit funktioniert alles.Dieser Code funktioniert gut für FILL_PARENT
und WRAP_CONTENT
breiten, aber vermasselt, wenn ich versuche, der Komponente ein Gewicht zu geben und sie ihr Gewicht automatisch so einstellen zu lassen.
MeasureSpec.getSize(widthMeasureSpec)
zurückgeben 0
, als getMinimumSuggestedWidth()
tut es auch.Dies ergibt einen wunderbaren Aktivitätsfehler, der nicht reagiert, da die Linienbreite immer kleiner ist als calculateTextWidth()
würde jemals wiederkommen, also die while
schleife läuft für immer.Der XML-Code, den ich verwendet habe, war im Wesentlichen folgender:
<com.my.widgets.ScalingTextViewGroup
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
android:gravity="center_horizontal"
>
<TextView
android:id="@+id/text_1"
android:text="Text 1"
android:textSize="20sp" />
<TextView
android:id="@+id/text_2"
android:text="Text 2"
android:textSize="18sp" />
<TextView
android:id="@+id/text_3"
android:text="Text 3"
android:textSize="18sp" />
<TextView
android:id="@+id/text_4"
android:text="Text 4"
android:textSize="18sp" />
</com.my.widgets.ScalingTextViewGroup>
Ich verstehe, warum es 0 zurückgibt - offensichtlich wird es auf 0 gesetzt - aber wie bringe ich es dazu, das zu verwenden layout_weight
?Ich habe das Gefühl, dass es etwas ist, das eine einfache Antwort haben sollte, aber ich weiß nicht, was es ist.
Lösung
Am Ende habe ich es durch ein bedeutendes Googeln herausgefunden.Auf diese Seite Das habe ich herausgefunden onMeasure wird tatsächlich zweimal aufgerufen wenn android:layout_weight
eingestellt ist.Ich habe später herausgefunden, dass es in erwähnt wird Wie Android Ansichten zeichnet dass measure()
kann beliebig oft aufgerufen werden, es saß einfach nicht sofort in meinem Gehirn.Der erste Durchgang kann offensichtlich keinen Wert für die Größe jedes Kindes angeben, da er nicht weiß, wie hoch die Gewichte aller Geschwister der Ansicht sind.Es geht es einmal durch und gibt mit einer MeasureSpec eine Breite von 0 an.NICHT SPEZIFIZIERT, um zu sehen, ob das Kind bestimmte Einschränkungen hat, dann geht es durch wieder um die tatsächlichen Gewichte einer MeasureSpec zuzuordnen.GENAU.Meine Aktivität wurde beim ersten Durchgang durcheinander gebracht, so dass es nie zum Layoutschritt kam.Das Ändern von onMeasure () in den folgenden Code hat das Problem behoben.
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
if (widthMode != MeasureSpec.UNSPECIFIED) {
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int lineWidth = widthSize - getPaddingLeft() - getPaddingRight();
// Change the text size until the largest line of text fits.
while (lineWidth < calculateTextWidth()) {
for (TextView textView : this.childViews) {
float newSize = textView.getTextSize() - 1;
textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, newSize);
}
}
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}