Wie kann ich eine Ansicht basierend auf der Größe des übergeordneten Layouts skalieren? Zum Beispiel habe ich ein RelativeLayout
, das den gesamten Bildschirm ausfüllt, und ich möchte, dass eine untergeordnete Ansicht, z. B. ein ImageView
, die gesamte Höhe und die Hälfte der Breite einnimmt.
Ich habe versucht, alle auf onMeasure
, onLayout
, onSizeChanged
usw. zu überschreiben, und ich konnte es nicht zum Laufen bringen ....
Ich weiß nicht, ob noch jemand diesen Thread liest oder nicht, aber Jeffs Lösung wird Sie nur auf halbem Weg dorthin bringen (ein bisschen wörtlich). Was sein onMeasure tun wird, ist das halbe Bild im halben übergeordneten Element anzuzeigen. Das Problem besteht darin, dass beim Aufrufen von super.onMeasure vor dem setMeasuredDimension
alle untergeordneten Elemente in der Ansicht anhand der Originalgröße gemessen werden. Anschließend wird die Ansicht nur halbiert, wenn die Größe des setMeasuredDimension
geändert wird.
Stattdessen müssen Sie setMeasuredDimension
aufrufen (wie für eine OnMeasure-Überschreibung erforderlich) nd Ihrer Ansicht nach ein neues LayoutParams
bereitstellen, dann aufrufen super.onMeasure
. Denken Sie daran, dass Ihr LayoutParams
vom übergeordneten Typ Ihrer Ansicht und nicht vom Typ Ihrer Ansicht abgeleitet wird.
@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);
}
Ich glaube, das einzige Mal, dass Sie Probleme mit dem übergeordneten LayoutParams
haben, ist, wenn das übergeordnete AbsoluteLayout
ist (was veraltet, aber manchmal immer noch nützlich ist).
Sie können dieses Problem beheben, indem Sie eine benutzerdefinierte Ansicht erstellen und die Methode onMeasure () überschreiben. Wenn Sie immer "fill_parent" für die layout_width in Ihrer XML-Datei verwenden, sollte der widthMeasureSpec-Parameter, der an die onMeasusre () -Methode übergeben wird, die Breite des übergeordneten Elements enthalten.
public class MyCustomView extends TextView {
public MyCustomView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
this.setMeasuredDimension(parentWidth / 2, parentHeight);
}
}
Ihr XML würde ungefähr so aussehen:
<LinearLayout
Android:layout_width="match_parent"
Android:layout_height="match_parent">
<view
class="com.company.MyCustomView"
Android:layout_width="match_parent"
Android:layout_height="match_parent" />
</LinearLayout>
Ich habe festgestellt, dass es am besten ist, die gemessenen Abmessungen nicht selbst einzustellen. Tatsächlich wird zwischen der übergeordneten und der untergeordneten Ansicht ein bisschen verhandelt, und Sie möchten nicht alles neu schreiben Code .
Sie können jedoch die measureSpecs ändern und dann super mit ihnen aufrufen. Ihre Ansicht wird nie erfahren, dass sie eine geänderte Nachricht von ihrem übergeordneten Element erhält, und sich um alles für Sie kümmern:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
int myWidth = (int) (parentHeight * 0.5);
super.onMeasure(MeasureSpec.makeMeasureSpec(myWidth, MeasureSpec.EXACTLY), heightMeasureSpec);
}
Wenn Sie ein Layout und eine Ansicht in XML definieren, können Sie die Layoutbreite und -höhe einer Ansicht so festlegen, dass der Inhalt umbrochen oder die übergeordnete Ansicht ausgefüllt wird. Die Hälfte der Fläche einzunehmen ist etwas schwieriger, aber wenn Sie etwas hatten, das Sie auf der anderen Hälfte wollten, könnten Sie etwas wie das Folgende tun.
<LinearLayout Android:layout_width="fill_parent"
Android:layout_height="fill_parent">
<ImageView Android:layout_height="fill_parent"
Android:layout_width="0dp"
Android:layout_weight="1"/>
<ImageView Android:layout_height="fill_parent"
Android:layout_width="0dp"
Android:layout_weight="1"/>
</LinearLayout>
Wenn Sie zwei Dingen das gleiche Gewicht geben, bedeutet dies, dass sie sich dehnen, um den gleichen Anteil des Bildschirms einzunehmen. Weitere Informationen zu Layouts finden Sie unter die Entwicklerdokumente
Ich glaube, dass Mayras XML-Ansatz in ordentlich kommen kann. Es ist jedoch möglich, die Genauigkeit mit nur einer Ansicht zu verbessern, indem Sie die Gewichtssumme einstellen. Ich würde das nicht mehr als Hack bezeichnen, aber meiner Meinung nach ist es der einfachste Ansatz:
<LinearLayout Android:layout_width="fill_parent"
Android:layout_height="fill_parent"
Android:weightSum="1">
<ImageView Android:layout_height="fill_parent"
Android:layout_width="0dp"
Android:layout_weight="0.5"/>
</LinearLayout>
Auf diese Weise können Sie ein beliebiges Gewicht verwenden, z. B. 0,6 (und Zentrierung) ist das Gewicht, das ich für Schaltflächen gerne verwende.
Versuche dies
int parentWidth = ((parentViewType)childView.getParent()).getWidth();
int parentHeight = ((parentViewType)childView.getParent()).getHeight();
dann können Sie LinearLayout.LayoutParams zum Einstellen der Parameter von chileView verwenden
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(childWidth,childLength);
childView.setLayoutParams(params);
Sie können jetzt PercentRelativeLayout verwenden. Boom! Problem gelöst.
Wenn die andere Seite leer ist. Ich denke, der einfachste Weg wäre, eine leere Ansicht (z. B. ein lineares Layout) hinzuzufügen und dann die Breite beider Ansichten auf fill_parent und ihre Gewichtung auf 1 zu setzen.
Dies funktioniert in einem LinearLayout ...
Roman, wenn Sie Ihr Layout in Java Code (ViewGroup-Nachkomme) erstellen möchten, ist dies möglich. Der Trick besteht darin, dass Sie sowohl die onMeasure-Methode als auch die onLayout-Methode implementieren müssen. Die onMeasure-Methode wird zuerst und dann aufgerufen Sie müssen die Unteransicht dort "messen" (effektiv auf den gewünschten Wert skalieren). Sie müssen sie im OnLayout-Aufruf erneut skalieren. Wenn Sie diese Sequenz nicht ausführen oder setMeasuredDimension () am Ende Ihres OnMeasure nicht aufrufen Warum das so kompliziert und fragil gestaltet ist, ist mir ein Rätsel.
Es ist ungefähr so:
<RelativeLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:tools="http://schemas.Android.com/tools"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
tools:context="com.company.myapp.ActivityOrFragment"
Android:id="@+id/activity_or_fragment">
<LinearLayout
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:id="@+id/linearLayoutFirst"
Android:weightSum="100"> <!-- Overall weights sum of children elements -->
<Spinner
Android:layout_width="0dp" <!-- It's 0dp because is determined by Android:layout_weight -->
Android:layout_weight="50"
Android:layout_height="wrap_content"
Android:id="@+id/spinner" />
</LinearLayout>
<LinearLayout
Android:layout_height="wrap_content"
Android:layout_width="match_parent"
Android:layout_below="@+id/linearLayoutFirst"
Android:layout_alignParentLeft="true"
Android:layout_alignParentStart="true"
Android:id="@+id/linearLayoutSecond">
<EditText
Android:layout_height="wrap_content"
Android:layout_width="0dp"
Android:layout_weight="75"
Android:inputType="numberDecimal"
Android:id="@+id/input" />
<TextView
Android:layout_height="wrap_content"
Android:layout_width="0dp"
Android:layout_weight="25"
Android:id="@+id/result"/>
</LinearLayout>
</RelativeLayout>