I have to use the GridLayout
for my application. The problem of GridLayout
is the limitation of weight so I must scale its children size at runtime. I do this by the help of an OnGlobalLayoutListener
.
The children of my GridLayout
are two Button
s which have got the width of the parent and the half of parents height. One Button
above and one Button
below.
If the upper Button
is clicked I want to switch the size of the GridLayout
to 500 in width and height and 700 in width and height.
After the click at the upper Button
the Button
s should scale correctly but they don't do that.
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();
}
}
Can anybody tell me what to do?
How can I tell the ContentView
to refresh itself and its children? I am searching for an elegant solution.
Thank you very much for answers!
Regards! :-)
Now when calling requestLayout () on a descendent of that view, Android will recursively call requestLayout () on that descendent's ancestors. The problem is that it will stop the recursion at the view on which you've called forceLayout (). So the requestLayout () call will never reach the view root and thus never schedule a layout pass.
So the requestLayout () call will never reach the view root and thus never schedule a layout pass. An entire subtree of the view hierarchy is waiting for a layout and calling requestLayout () on any view of that subtree will not cause a layout.
An example of when a custom view would call it is when a text or background color property has changed. The view will be redrawn but the size will not change. If something about your view changes that will affect the size, then you should call requestLayout ().
There is also a much bigger issue when using forceLayout () and requestLayout (): Let's say you've called forceLayout () on a view. Now when calling requestLayout () on a descendent of that view, Android will recursively call requestLayout () on that descendent's ancestors.
I ran into the same problem. I guess Android has not finished calculating the new layout when onLayoutChanges()
is called, and a recalculation cannot be triggered from within the method.
The solution is to use a Handler to post layout changes to the end of the UI thread.
I am not really sure about requestLayout()
, maybe replace it with another call of setLayoutParams()
. It probably has the same effect.
So implement your re-layout in a class implementing Runnable
, instantiate a Handler
in onCreate()
and in onLayoutChanges()
instantiate the Runnable class and post it to the 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);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With