Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Layout a view after resizing

I'm creating a grid that displays values that change very often. Because of this, I'm using a TextView that autoresizes when its content changes (Auto Scale TextView Text to Fit within Bounds). The resize takes place, but the view doesn't layout properly

layout after resize

The thing is, when I examine the activity with HierarchyViewer the layout displays as I want.

layout after hierarchyviewer

My guess is that HierarchyViewer invokes requestLayout() or invalidate() on the view, but I've tried that with no success. This code is invoked in the main activity with no effect.

new Handler().postDelayed(new Runnable() {            
            @Override
            public void run() {
              getWindow().getDecorView().requestLayout();
              getWindow().getDecorView().invalidate();
            }
          }, 5000);

I've also tried invalidating the view after resizing.

The TextView has gravity set to Center, and if no resize takes place, it looks ok.

Any hint will be welcome, thanks in advance!

like image 483
Maragues Avatar asked Oct 13 '12 12:10

Maragues


2 Answers

I solved it by overriding onLayout in one of the TextView's parent and using a Handler created in the constructor

public class CellView extends LinearLayout{
   public CellView(Context context) {
     super(context);

     mHandler = new Handler();

     View.inflate(context, R.layout.cellview, this);
  }

 @Override
  protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
    if(changed){
      mHandler.post(new Runnable() {          
        @Override
        public void run() {
          requestLayout();
        }
      });
    }

   super.onLayout(changed, left, top, right, bottom);
  }

I had tried calling requestLayout inside TextView's onLayout, tho it didn't work, I'm not sure why. It might be because the value was updated through an Observer, but the onTextChanged listener should happen in the UI Thread. I hope it serves someone else

like image 78
Maragues Avatar answered Sep 27 '22 23:09

Maragues


The way requestLayout() works is that when called on a view, it will schedule a layout pass on itself and all of it's children. This is desirable whenever a view has shifted or resized do to margin, padding, or content changes.

The documentation on the method getDecorView() isn't very clear on what exactly it gives you. However, per the documentation on the website:

Note that calling this function for the first time "locks in" various window characteristics as described in setContentView(View, android.view.ViewGroup.LayoutParams).

This leaves me to believe that there's something special about the view that getDecorView() retrieves. What you are probably doing is making the layout of the view permanent thus never changing when you make a requestLayout() pass.

This is apparently the proper way to get the root view of your entire activity.

However, for efficiency reasons, I recommend calling requestLayout() on the lowest child you possibly can. Like I said before, it schedules a layout pass on a view and it's children. If you do a layout pass on the top-most view, you're essientially rebuilding everything which includes the views that stay in place.

like image 25
DeeV Avatar answered Sep 28 '22 01:09

DeeV