When How to First Measure a View

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



Leave a reply



Submit