When Can I First Measure a View?
I didn't know about ViewTreeObserver.addOnPreDrawListener()
, and I tried it in a test project.
With your code it would look like this:
public void onCreate() {
setContentView(R.layout.main);
final TextView tv = (TextView)findViewById(R.id.image_test);
final LayerDrawable ld = (LayerDrawable)tv.getBackground();
final ViewTreeObserver obs = tv.getViewTreeObserver();
obs.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw () {
Log.d(TAG, "onPreDraw tv height is " + tv.getHeight()); // bad for performance, remove on production
int height = tv.getHeight();
int topInset = height / 2;
ld.setLayerInset(1, 0, topInset, 0, 0);
tv.setBackgroundDrawable(ld);
return true;
}
});
}
In my test project onPreDraw()
has been called twice, and I think in your case it may cause an infinite loop.
You could try to call the setBackgroundDrawable()
only when the height of the TextView
changes :
private int mLastTvHeight = 0;
public void onCreate() {
setContentView(R.layout.main);
final TextView tv = (TextView)findViewById(R.id.image_test);
final LayerDrawable ld = (LayerDrawable)tv.getBackground();
final ViewTreeObserver obs = mTv.getViewTreeObserver();
obs.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw () {
Log.d(TAG, "onPreDraw tv height is " + tv.getHeight()); // bad for performance, remove on production
int height = tv.getHeight();
if (height != mLastTvHeight) {
mLastTvHeight = height;
int topInset = height / 2;
ld.setLayerInset(1, 0, topInset, 0, 0);
tv.setBackgroundDrawable(ld);
}
return true;
}
});
}
But that sounds a bit complicated for what you are trying to achieve and not really good for performance.
EDIT by kcoppock
Here's what I ended up doing from this code. Gautier's answer got me to this point, so I'd rather accept this answer with modification than answer it myself. I ended up using the ViewTreeObserver's addOnGlobalLayoutListener() method instead, like so (this is in onCreate()):
final TextView tv = (TextView)findViewById(R.id.image_test);
ViewTreeObserver vto = tv.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
LayerDrawable ld = (LayerDrawable)tv.getBackground();
ld.setLayerInset(1, 0, tv.getHeight() / 2, 0, 0);
}
});
Seems to work perfectly; I checked LogCat and didn't see any unusual activity. Hopefully this is it! Thanks!
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.
Get view width/height or font width/height/other sizes before first display
The size of view cannot be calculated until its parent is calculated, but you can always force this calculation by calling measure(allowedWidth, allowedHeight)
on it. Then getMeasuredWidth()
will works.
see http://developer.android.com/reference/android/view/View.html#measure(int, int)
Calculate view measure before display it
Edit your code as below :
Display display = getWindowManager().getDefaultDisplay();
int maxWidth = display.getWidth();
int widthSoFar=0;
int allItems = 50;
int currentItem = 0;
while(currentItem < allItems) {
FrameLayout view = (FrameLayout) inflater.inflate(R.layout.fl, null);
linearLayout.addView(view);
view .measure(0, 0);
widthSoFar = widthSoFar + view.getMeasuredWidth();
if (widthSoFar >= maxWidth) {
linearLayout.removeView(view);
break;
}
}
Hope this helps you
In which state activity measure it's view
This answer probably gives you what you need: https://stackoverflow.com/a/1016941/213528
You would maybe use it like this:
private int WIDTH;
private int HEIGHT;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
WIDTH = size.x;
HEIGHT = size.y;
pager = (ReadPage)findViewById(R.id.readpage);
pager.addArticle("...");
}
// ...
public void addArticle(String s){
articles.add(new Article(s, WIDTH, HEIGHT));
}
React-Native : measure a View
During the night some guys talked about a (hacky) solution but it solved my problem, found it here: https://github.com/facebook/react-native/issues/953
Basically the solution is to use setTimeout
and everything just works magically:
componentDidMount: function() {
setTimeout(this.measureProgressBar);
},
measureProgressBar: function() {
this.refs.progressBar.measure((a, b, width, height, px, py) =>
this.setState({ progressMaxSize: width })
);
}
Measure all view hierarchy before drawing in Android
I have find out way to get view width. I can get it after android measuret it but before drawing using OnPreDrawListener in ViewTreeObserver:
view.getViewTreeObserver().addOnPreDrawListener(new OnPreDrawListener()
{
@Override
public boolean onPreDraw()
{
int avaliableWidth = view.getWidth() - view.getPaddingLeft() - view.getPaddingRight();
Log.d("width", String.valueOf(avaliableWidth));
return true;
}
});
From Android documentation:
Callback method to be invoked when the view tree is about to be drawn.
At this point, all views in the tree have been measured and given a
frame. Clients can use this to adjust their scroll bounds or even to
request a new layout before drawing occurs.
When can one obtain view dimensions in an activity?
Declare onGlobalLayoutListener in onCreate method:
View firstView = (View) findViewById(R.id.firstView);
View secondView = (View) findViewById(R.id.secondView);
firstView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
// Ensure you call it only once :
firstView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
int width = firstView.getWidth();
int height = firstView.getHeight();
// set dimensions of another view with that dimensions
secondView.setWidth(width);
secondView.setHeight(height);
}
});
Related Topics
An Established Connection Was Aborted by the Software in Your Host MAChine
How to Create Jar for Android Library Project
How to Center Text Horizontally and Vertically in a Textview
How to Import Existing Android Project into Eclipse
Pass Data from Activity to Service Using an Intent
Problems with Android Fragment Back Stack
Getting the Physical Screen Dimensions/Dpi/Pixel Density in Chrome on Android
How to Send Data from One Fragment to Another Fragment
Setting Global Styles for Views in Android
How to Save Sms to Inbox in Android
How to Kill an Application with All Its Activities
Android Studio Does Not Show Layout Preview
Web Colors in an Android Color Xml Resource File
Spinner: Get State or Get Notified When Opens
How to Remove Application from App Listings on Android Developer Console
Programmatically Select Item Listview in Android
Android Alarmmanager Not Working on Some Devices When the App Is Closed