How to work with weights in onMeasue for custom views?

I have a custom view that I create that will scale the font size of its child TextViews so that they fit the entire width, so each one is on a separate line. Obviously, it will take a width to figure this out.

I redefined onMeasure() like this:

 @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() calculates the width of the largest line of text, and everything works with that. This code works fine for FILL_PARENT and WRAP_CONTENT , but WRAP_CONTENT up when I try to assign a component weight and let it automatically set its weight in this way.

MeasureSpec.getSize(widthMeasureSpec) returns 0 , like getMinimumSuggestedWidth() . This gives a wonderful non-responsive activity, as LineWidth will always be less than calculateTextWidth() will ever return, so the while loop will be executed forever. The XML code I used was like this:

 <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> 

I understand why it returns 0 - obviously it is set to 0 - but how do I get it to use layout_weight ? I feel this should have a simple answer, but I don’t know what it is.

+6
source share
1 answer

I ended up figuring this out through some significant Googling. On this page, I found out that onMeasure is actually called twice when android:layout_weight . I found out later that he mentioned in How Android draws the view that measure() can be called as many times as you like, it just didn’t immediately sit in my brain. The first pass, obviously, cannot give value for the size of each child, since he does not know what the weights of all brothers and sisters are. It goes through it once and gives a width of 0 with the MeasureSpec.UNSPECIFIED parameter to find out if the child has any specific restrictions, and then goes again to assign the actual weights using MeasureSpec.EXACTLY. My activity was gaining momentum in the first pass, so he did not reach the layout. Corrections to my onMeasure () for the following code fixed the problem.

 @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); } 
+10
source

Source: https://habr.com/ru/post/906902/


All Articles