Getting height of text view before rendering to layout
2 solutions
Used solution 1 at first and found solution 2 later on. Both work, it's really what you prefer.
Important is to make sure you got all the dimensions right since mixing font sizes in sp or px will give quite a difference depending on what screen you test on.
A very basic example project is available at https://github.com/hanscappelle/SO-3654321
Solution 1 using TextView and MeasureSpec
Main issue with original question is TextView in below method should be configured as our TextView which should be rendered to layout. I think this solution is valuable for many people who faced this problem.
public static int getHeight(Context context, CharSequence text, int textSize, int deviceWidth, Typeface typeface,int padding) {
TextView textView = new TextView(context);
textView.setPadding(padding,0,padding,padding);
textView.setTypeface(typeface);
textView.setText(text, TextView.BufferType.SPANNABLE);
textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, textSize);
int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(deviceWidth, View.MeasureSpec.AT_MOST);
int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
textView.measure(widthMeasureSpec, heightMeasureSpec);
return textView.getMeasuredHeight();
}
And an example of how to use this:
// retrieve deviceWidth
int deviceWidth;
WindowManager wm = (WindowManager) textView.getContext().getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
if(android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2){
Point size = new Point();
display.getSize(size);
deviceWidth = size.x;
} else {
deviceWidth = display.getWidth();
}
// the text to check for
String exampleTextToMeasure = "some example text that will be long enough to make this example split over multiple lines so we can't easily predict the final height";
// some dimensions from dimes resources to take into account
int textSize = getContext().getResources().getDimensionPixelSize(R.dimen.text_size);
int padding = getContext().getResources().getDimensionPixelSize(R.dimen.text_padding);
// final calculation of textView height
int measuredTextHeight = getHeight(getContext(), exampleTextToMeasure, textSize, deviceWidth, TypeFace.DEFAULT, padding);
Solution 2 using TextPaint and StaticLayout
This method relies on a TextPaint and StaticLayout which also gives reliable results on all API levels I've tested so far. Pay good attention to units of dimensions; all should be in pixels!
Source: Measuring text height to be drawn on Canvas ( Android )
public static int method1UsingTextPaintAndStaticLayout(
final CharSequence text,
final int textSize, // in pixels
final int deviceWidth, // in pixels
final int padding // in pixels
) {
TextPaint myTextPaint = new TextPaint();
myTextPaint.setAntiAlias(true);
// this is how you would convert sp to pixels based on screen density
//myTextPaint.setTextSize(16 * context.getResources().getDisplayMetrics().density);
myTextPaint.setTextSize(textSize);
Layout.Alignment alignment = Layout.Alignment.ALIGN_NORMAL;
float spacingMultiplier = 1;
float spacingAddition = padding; // optionally apply padding here
boolean includePadding = padding != 0;
StaticLayout myStaticLayout = new StaticLayout(text, myTextPaint, deviceWidth, alignment, spacingMultiplier, spacingAddition, includePadding);
return myStaticLayout.getHeight();
}
Accurate way to determine the measured height of a view, even before it changed from GONE to VISIBLE
Your 2nd code snippet is almost correct, but you need to specify pixel sizes - not FILL_PARENT/MATCH_PARENT
. This should work:
v.measure(MeasureSpec.makeMeasureSpec(parentView.getWidth(), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(MAX_HEIGHT, MeasureSpec.AT_MOST));
final int targetHeight = v.getMeasuredHeight();
You'll need to have a reference to the ViewGroup that v
is a child of to get its width, and define MAX_HEIGHT
(or perhaps use the parent View's height?).
Also, you should change the height parameters of the two TextViews that are within the horizontal LinearLayout to wrap_content
, as using match_parent
here may cause problems. The LinearLayout is set to wrap_content, but the two children don't specify a height.
How to correctly measure the height of a view before it is drawn
Try the following observer
{
ViewTreeObserver treeObserver=measuringView.getViewTreeObserver();
treeObserver.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
int height=measuringView.getHeight();
}
}
}
View's getWidth() and getHeight() returns 0
You are calling getWidth()
too early. The UI has not been sized and laid out on the screen yet.
I doubt you want to be doing what you are doing, anyway -- widgets being animated do not change their clickable areas, and so the button will still respond to clicks in the original orientation regardless of how it has rotated.
That being said, you can use a dimension resource to define the button size, then reference that dimension resource from your layout file and your source code, to avoid this problem.
Related Topics
How to Detect When the User Has Changed the Clock Time on Their Device
Which Android Ide Is Better - Android Studio or Eclipse
Android Cannot Pass Intent Extras Though Alarmmanager
Get Listview Item Position on Button Click
How to Send JSON Object to Server Using Volley in Android
How to Get Release Build APK File Using Proguard
Add Views Below Toolbar in Coordinatorlayout
Action_View Intent for a File with Unknown Mimetype
Android Studio/Emulator on MACos with Arm CPU M1
Intent - If Activity Is Running, Bring It to Front, Else Start a New One (From Notification)
Apply Custom Filters to Camera Output
Adding Local .Aar Files to My Gradle Build
Using Listview:How to Add a Header View
Why Does Alertdialog.Builder(Context Context) Only Accepts Activity as a Parameter
Drawing Multiple Lines in Edittext E.G. Notepad
Adb Connection by Wifi Getting Killed When a New Usb Attached/Detached
Recyclerview Gridlayoutmanager: How to Auto-Detect Span Count
Android Contacts Display Name and Phone Number(S) in Single Database Query