Android - View.requestLayout在OnLayoutChangeListener中不起作用

Bar*_*ock 7 java layout android viewgroup

我必须使用GridLayout我的应用程序.问题GridLayout是体重的限制因此我必须在运行时缩放其子项大小.我是在一个人的帮助下做到的OnGlobalLayoutListener.

我的孩子GridLayout是两个孩子Button,有父母的宽度和父母身高的一半.一个Button在上面,一个Button在下面.如果Button单击鞋面,我想将GridLayout宽度和高度的大小切换为500,宽度和高度的大小为700.点击在上部后ButtonButtonS的关系具有正确的尺度,但他们没有这样做.

public class HauptAktivitaet extends Activity implements OnLayoutChangeListener, OnClickListener{

  /** ContentView its sizes I will change on a click later */

  private GridLayout mGridLayout;

  /** LayoutParams of the above child */

  private GridLayout.LayoutParams mGridLayout_LayoutParams_Above;

  /** LayoutParams of the below child */

  private GridLayout.LayoutParams mGridLayout_LayoutParams_Below;

  /** Children of the ContentView */

  private Button mButtonAbove;
  private Button mButtonBelow;


  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    inline();

    setContentView(mGridLayout);

  }

  private void inline(){

    /* instantiation of ContentView which is named mGridLayout */

    mGridLayout = new GridLayout(this);

    /* set the count of rows and columns of ContentView */

    mGridLayout.setRowCount(2);
    mGridLayout.setColumnCount(1);

      /* set OnGlobalLayoutListener for observe a change of its layout */

    mGridLayout.addOnLayoutChangeListener(this);

    /* instantiation of the LayoutParams for the children */

    mGridLayout_LayoutParams_Above = new GridLayout.LayoutParams(GridLayout.spec(0), GridLayout.spec(0));
    mGridLayout_LayoutParams_Below = new GridLayout.LayoutParams(GridLayout.spec(1), GridLayout.spec(0));

    /* instantiation of the children and setting of their LayoutParams */

    mButtonAbove = new Button(this);
    mButtonAbove.setLayoutParams(mGridLayout_LayoutParams_Above);
    mButtonAbove.setOnClickListener(this); // A click on this Button changes the Size of its parent ViewGroup.

    /* instantiation of ContentView */

    mButtonBelow = new Button(this);
    mButtonBelow.setLayoutParams(mGridLayout_LayoutParams_Below);

    /* add children to the ContentView */

    mGridLayout.addView(mButtonAbove);
    mGridLayout.addView(mButtonBelow);

  }

  @Override
  public void onLayoutChange(View v, int left, int top, int right, int bottom,
      int oldLeft, int oldTop, int oldRight, int oldBottom) {

    /* Width and height on this time are known */

    int width = mGridLayout.getWidth();
    int height = mGridLayout.getHeight();

    /* Changes the LayoutParams of ContentViews children dynamicly*/

    mGridLayout_LayoutParams_Above.width = width;
    mGridLayout_LayoutParams_Above.height = height / 2;

    mGridLayout_LayoutParams_Below.width = width;
    mGridLayout_LayoutParams_Below.height = height / 2;

    /* ISSUE:
     * should update the rendering of the buttons but it doesn't work correctly */

    mButtonAbove.requestLayout();
    mButtonBelow.requestLayout();

    /* A little debug info for knowing of the ContentViews size */

    mButtonBelow.setText("Own Width = " + mButtonBelow.getWidth() + "\n" + 
                         "Own Height = " + mButtonBelow.getHeight() + "\n" +
                         "Perents Width = " + width + "\n" +
                         "Perents Height = " + height);


  }

  private boolean switcher = true;

  /** 
   * Works correctly
   * */

  @Override
  public void onClick(View v) {

    int width = 0;
    int height = 0;

    if(switcher){
      width = 500;
      height = 500;
      switcher = false;
    }else{
      width = 700;
      height = 700;
      switcher = true;
    }

    mGridLayout.getLayoutParams().width = width;
    mGridLayout.getLayoutParams().height = height;

    mGridLayout.requestLayout();

  }

}
Run Code Online (Sandbox Code Playgroud)

谁能告诉我该怎么办?

我该如何告诉ContentView刷新自己及其子女?我正在寻找一个优雅的解决方案.

非常感谢您的回答!

问候!:-)

小智 7

我遇到了同样的问题.我猜Android在onLayoutChanges()调用时还没有完成计算新布局,并且无法从方法中触发重新计算.解决方案是使用Handler将布局更改发布到UI线程的末尾.

我不太确定requestLayout(),也许用另一个电话替换它setLayoutParams().它可能具有相同的效果.

因此,在实现Runnable,实例化Handlerin onCreate()onLayoutChanges()实例化Runnable类的类中实现重新布局,并将其发布到Handler:

public class HauptAktivitaet extends Activity implements OnLayoutChangeListener, OnClickListener{

  // this class updates the layout
  private class LayoutUpdater implements Runnable {
    private final int width;
    private final int height;

    private LayoutUpdater(int width, int height) {
      this.width = width;
      this.height = height;
    }

    public void run() {
      mGridLayout_LayoutParams_Above.width = width;
      mGridLayout_LayoutParams_Above.height = height;

      mGridLayout_LayoutParams_Below.width = width;
      mGridLayout_LayoutParams_Below.height = height;

      // might be necessary or not: set layout parameters to trigger update
      mButtonAbove.setLayoutParams(mGridLayout_LayoutParams_Above);   
      mButtonBelow.setLayoutParams(mGridLayout_LayoutParams_Below);
    }
  }

  /* snip */

  // add handler running in UI thread
  private Handler uiHandler;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // instantiate handler
    uiHandler = new Handler();

    inline();

    setContentView(mGridLayout);

  }

  /* snip */

  @Override
  public void onLayoutChange(View v, int left, int top, int right, int bottom,
      int oldLeft, int oldTop, int oldRight, int oldBottom) {

    /* Width and height on this time are known */

    int width = mGridLayout.getWidth();
    int height = mGridLayout.getHeight();

    // post layout update to the end of queue
    uiHandler.post(new LayoutUpdater(width, height / 2);
  }
}
Run Code Online (Sandbox Code Playgroud)


Bar*_*ock 7

@ user3492470非常
感谢您的回答.我以为没有人有想法.

你的"解决方案"很有意思,但遗憾的是有点不对劲.光学上它的效果很好但是在后台你有一个无限循环...
如果你在其中一个的文本上设置一个计数器,你会看到它Button.柜台不断增加.
设置Buttons'新的布局大小Handler后面跟着一个新的调用,OnLayoutChangeListener然后再次Listener启动Handler等等......
如果你使用的是a OnGlobalLayoutListener而不是OnLayoutChangeListenera,你会遇到同样的问题Handler.
原因如下.该方法中的view.requestLayout()view.setLayoutParams(…)不起作用onLayoutChange,但它适用于onGlobalLayout方法或Handler创建新线程的方法.
现在这部分我真的不明白:
成功调用对child.requestLayout()onLayoutChange方法进行新调用.这很奇怪,因为父母的布局不应该再次改变.
然而,有一点if/else逻辑解决了无休止的调用.

  private int counter = 0;
  @Override
  public void onGlobalLayout() {
    // TODO Auto-generated method stub

    /* Width and height on this time are known */

    int width  = mGridLayout.getWidth();
    int height = mGridLayout.getHeight();

    /* Buttons width and height are supposed to be */

    int mButtons_width  = width;
    int mButtons_height = height / 2;

    if(!(mButtonAbove.getWidth()  == mButtons_width  &&
         mButtonAbove.getHeight() == mButtons_height &&
         mButtonBelow.getWidth()  == mButtons_width  &&
         mButtonBelow.getHeight() == mButtons_height)
      ){

      /* Changes the LayoutParams of ContentViews children dynamicly */

      mGridLayout_LayoutParams_Above.width = mButtons_width;
      mGridLayout_LayoutParams_Above.height = mButtons_height;

      mGridLayout_LayoutParams_Below.width = mButtons_width;
      mGridLayout_LayoutParams_Below.height = mButtons_height;

      /* NO ISSUE ANYMORE:
       * updates the rendering of the buttons */

      mButtonAbove.requestLayout();
      mButtonBelow.requestLayout();

    }

    /* A little debug info for knowing the ContentView's and Children's size */

    mButtonBelow.setText("Own Width = " + mButtonBelow.getWidth() + "\n" + 
                         "Own Height = " + mButtonBelow.getHeight() + "\n" +
                         "Perents Width = " + width + "\n" +
                         "Perents Height = " + height + "\n" +
                         "Calls = " + counter++);

  }
Run Code Online (Sandbox Code Playgroud)

在这种情况下,我使用OnGlobalLayoutListener而不是OnLayoutChangeListener/ uiHandler组合.;-) if/else逻辑是相同的.

我原来的问题,为什么requestLayout不起作用onLayoutChange,仍然是开放的,但这里提出了令人满意的解决方案,所以我很高兴.

再次感谢您的关注!