Project

General

Profile

« Previous | Next » 

Revision 97a4ae23

Added by Leszek Koltunski almost 3 years ago

Progress with ConfigScreen.

View differences:

src/main/java/org/distorted/config/ConfigActivity.java
22 22
import android.os.Build;
23 23
import android.os.Bundle;
24 24
import android.util.DisplayMetrics;
25
import android.view.DisplayCutout;
26 25
import android.view.View;
27 26
import android.view.ViewGroup;
28 27
import android.view.WindowManager;
......
39 38
import org.distorted.main.R;
40 39
import org.distorted.objectlib.main.ObjectControl;
41 40
import org.distorted.objectlib.main.ObjectType;
42
import org.distorted.tutorials.TutorialScreen;
43 41

  
44 42
import java.io.InputStream;
45 43

  
......
48 46
public class ConfigActivity extends AppCompatActivity
49 47
{
50 48
    private static final int ACTIVITY_NUMBER = 2;
51
    private static final float RATIO_INSET= 0.08f;
52
    public static final float BAR_RATIO = 0.17f;
49
    private static final float RATIO_BAR  = 0.10f;
53 50

  
54 51
    public static final float DIALOG_BUTTON_SIZE  = 0.06f;
55 52
    public static final float MENU_BIG_TEXT_SIZE  = 0.05f;
......
65 62
    private int mCurrentApiVersion;
66 63
    private ConfigScreen mScreen;
67 64
    private int mObjectOrdinal;
68
    private int mHeightUpperBar;
65
    private int mHeightBar;
69 66

  
70 67
///////////////////////////////////////////////////////////////////////////////////////////////////
71 68

  
......
87 84
      getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
88 85
      mScreenWidth =displaymetrics.widthPixels;
89 86
      mScreenHeight=displaymetrics.heightPixels;
90

  
87
      mScreenHeight = (int)(1.07f*mScreenHeight); // add 7% for the upper bar
88
                                                  // which is not yet hidden.
89
                                                  // TODO: figure this out exactly.
91 90
      hideNavigationBar();
92 91
      cutoutHack();
92
      computeBarHeights();
93
      }
94

  
95
///////////////////////////////////////////////////////////////////////////////////////////////////
96
// this does not include possible insets
97

  
98
    private void computeBarHeights()
99
      {
100
      int barHeight = (int)(mScreenHeight*RATIO_BAR);
101
      mHeightBar = barHeight;
102

  
103
      LinearLayout layout = findViewById(R.id.lowerBar);
104
      ViewGroup.LayoutParams params = layout.getLayoutParams();
105
      params.height = barHeight;
106
      layout.setLayoutParams(params);
93 107
      }
94 108

  
95 109
///////////////////////////////////////////////////////////////////////////////////////////////////
......
125 139
      {
126 140
      super.onAttachedToWindow();
127 141

  
128
      int insetHeight = 0;
129

  
130
      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P)
131
        {
132
        DisplayCutout cutout = getWindow().getDecorView().getRootWindowInsets().getDisplayCutout();
133
        insetHeight = cutout!=null ? cutout.getSafeInsetTop() : 0;
134
        }
135

  
136
      LinearLayout layoutHid = findViewById(R.id.hiddenBar);
137
      ViewGroup.LayoutParams paramsHid = layoutHid.getLayoutParams();
138
      paramsHid.height = (int)(insetHeight*RATIO_INSET);
139
      layoutHid.setLayoutParams(paramsHid);
140
      mHeightUpperBar += paramsHid.height;
141

  
142 142
      if( mScreen==null ) mScreen = new ConfigScreen();
143
      mScreen.createScreen(this);
143
      mScreen.enterScreen(this,mObjectOrdinal);
144 144
      }
145 145

  
146 146
///////////////////////////////////////////////////////////////////////////////////////////////////
......
221 221
      control.changeIfDifferent(type.ordinal(),jsonStream,meshStream);
222 222
      }
223 223

  
224
///////////////////////////////////////////////////////////////////////////////////////////////////
225

  
226
    ConfigScreen getState()
227
      {
228
      return mScreen;
229
      }
230

  
231 224
///////////////////////////////////////////////////////////////////////////////////////////////////
232 225
// PUBLIC API
233 226
///////////////////////////////////////////////////////////////////////////////////////////////////
......
239 232

  
240 233
///////////////////////////////////////////////////////////////////////////////////////////////////
241 234

  
242
    public int getHeightUpperBar()
235
    public int getHeightBar()
243 236
      {
244
      return mHeightUpperBar;
237
      return mHeightBar;
245 238
      }
246 239

  
247 240
///////////////////////////////////////////////////////////////////////////////////////////////////
......
251 244
      return mScreenWidth;
252 245
      }
253 246

  
247
///////////////////////////////////////////////////////////////////////////////////////////////////
248

  
249
    public int getScreenHeightInPixels()
250
      {
251
      return mScreenHeight;
252
      }
253

  
254 254
///////////////////////////////////////////////////////////////////////////////////////////////////
255 255

  
256 256
    public ObjectControl getControl()
......
301 301
      ConfigSurfaceView view = findViewById(R.id.configSurfaceView);
302 302
      return view.isVertical();
303 303
      }
304

  
305
///////////////////////////////////////////////////////////////////////////////////////////////////
306

  
307
    public void changeObject(ObjectType newObject)
308
      {
309
      ConfigSurfaceView view = findViewById(R.id.configSurfaceView);
310
      ObjectControl control = view.getObjectControl();
311
      changeIfDifferent(newObject,control);
312
      }
304 313
}
src/main/java/org/distorted/config/ConfigRenderer.java
42 42

  
43 43
   ConfigRenderer(ConfigSurfaceView v)
44 44
     {
45
     final float BRIGHTNESS = 0.30f;
45
     final float BRIGHTNESS = 0.333f;
46 46

  
47 47
     mView = v;
48 48
     mScreen = new DistortedScreen();
src/main/java/org/distorted/config/ConfigScreen.java
19 19

  
20 20
package org.distorted.config;
21 21

  
22
import android.content.res.Resources;
23
import android.graphics.drawable.BitmapDrawable;
24
import android.os.Build;
25
import android.util.TypedValue;
26
import android.view.Gravity;
22 27
import android.view.View;
28
import android.widget.GridLayout;
29
import android.widget.ImageButton;
23 30
import android.widget.LinearLayout;
31
import android.widget.PopupWindow;
32
import android.widget.ScrollView;
33
import android.widget.TextView;
34

  
35
import org.distorted.objectlib.main.ObjectControl;
36
import org.distorted.objectlib.main.ObjectType;
24 37

  
25 38
import org.distorted.helpers.TransparentImageButton;
26 39
import org.distorted.main.R;
27 40
import org.distorted.main.RubikActivity;
28
import org.distorted.objectlib.main.ObjectControl;
41

  
42
import static android.view.View.inflate;
43
import static org.distorted.objectlib.main.ObjectType.NUM_OBJECTS;
29 44

  
30 45
///////////////////////////////////////////////////////////////////////////////////////////////////
31 46

  
32 47
public class ConfigScreen
33 48
{
34
  private TransparentImageButton mBackButton;
49
  private static final int NUM_COLUMNS = 4;
50
  private static final int[] mLocation = new int[2];
51

  
52
  private TransparentImageButton mBackButton, mObjectButton, mPrevButton, mNextButton;
53
  private TextView mMovesText;
54
  private PopupWindow mObjectPopup;
55
  private int mObjectOrdinal;
56
  private int mColCount, mRowCount, mMaxRowCount;
57
  private int mObjectSize;
58
  private int mBarHeight;
59
  private float mButtonSize;
60

  
61
///////////////////////////////////////////////////////////////////////////////////////////////////
62

  
63
  private void setupObjectWindow(final ConfigActivity act, final float width, final float height)
64
    {
65
    int icon = RubikActivity.getDrawable(R.drawable.cube_2s,R.drawable.cube_2m, R.drawable.cube_2b, R.drawable.cube_2h);
66

  
67
    Resources res = act.getResources();
68
    BitmapDrawable bd = (BitmapDrawable)res.getDrawable(icon);
69
    int cubeWidth = bd.getIntrinsicWidth();
70
    int margin = (int)(width*RubikActivity.LARGE_MARGIN);
71
    mObjectSize = (int)(cubeWidth + 2*margin + 0.5f);
72
    mMaxRowCount = (int)((height-mBarHeight)/mObjectSize);
73

  
74
    ScrollView view = (ScrollView)inflate( act, R.layout.popup_object_simple, null);
75
    GridLayout objectGrid = view.findViewById(R.id.objectGrid);
76

  
77
    GridLayout.Spec[] rowSpecs = new GridLayout.Spec[mRowCount];
78
    GridLayout.Spec[] colSpecs = new GridLayout.Spec[mColCount];
79

  
80
    objectGrid.setColumnCount(mColCount);
81
    objectGrid.setRowCount(mRowCount);
82

  
83
    mObjectPopup = new PopupWindow(act);
84
    mObjectPopup.setFocusable(true);
85
    mObjectPopup.setContentView(view);
86

  
87
    int[] nextInRow = new int[mRowCount];
88

  
89
    for(int row=0; row<mRowCount; row++)
90
      {
91
      rowSpecs[row] = GridLayout.spec(row);
92
      nextInRow[row]= 0;
93
      }
94
    for(int col=0; col<mColCount; col++)
95
      {
96
      colSpecs[col] = GridLayout.spec(col);
97
      }
98

  
99
    for(int object = 0; object< NUM_OBJECTS; object++)
100
      {
101
      final int ordinal = object;
102
      ObjectType type = ObjectType.getObject(ordinal);
103
      int iconSize = RubikActivity.getDrawableSize();
104
      int icons = type.getIconID(iconSize);
105
      int row = object/NUM_COLUMNS;
106

  
107
      ImageButton button = new ImageButton(act);
108
      button.setBackgroundResource(icons);
109
      button.setOnClickListener( new View.OnClickListener()
110
        {
111
        @Override
112
        public void onClick(View v)
113
          {
114
          if( act.getControl().isUINotBlocked() && mObjectOrdinal!=ordinal )
115
            {
116
            mObjectOrdinal = ordinal;
117
            act.changeObject(type);
118
            mMovesText.setText(act.getString(R.string.mo_placeholder,mObjectOrdinal+1,NUM_OBJECTS));
119
            setupInfo(act);
120
            }
121

  
122
          mObjectPopup.dismiss();
123
          }
124
        });
125

  
126
      GridLayout.LayoutParams params = new GridLayout.LayoutParams(rowSpecs[row],colSpecs[nextInRow[row]]);
127
      params.bottomMargin = margin;
128
      params.topMargin    = margin;
129
      params.leftMargin   = margin;
130
      params.rightMargin  = margin;
131

  
132
      nextInRow[row]++;
133

  
134
      objectGrid.addView(button, params);
135
      }
136
    }
35 137

  
36 138
///////////////////////////////////////////////////////////////////////////////////////////////////
37 139

  
38 140
  private void setupBackButton(final ConfigActivity act)
39 141
    {
40 142
    int icon = RubikActivity.getDrawable(R.drawable.ui_small_smallback,R.drawable.ui_medium_smallback, R.drawable.ui_big_smallback, R.drawable.ui_huge_smallback);
41
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT,1.0f);
143
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT);
42 144
    mBackButton = new TransparentImageButton(act, icon, TransparentImageButton.GRAVITY_MIDDLE, params);
43 145

  
44 146
    mBackButton.setOnClickListener( new View.OnClickListener()
......
55 157

  
56 158
///////////////////////////////////////////////////////////////////////////////////////////////////
57 159

  
58
  void createScreen(final ConfigActivity act)
160
  private void setupObjectButton(final ConfigActivity act, final int width)
59 161
    {
60
    LinearLayout layout = act.findViewById(R.id.lowerBar);
61
    layout.removeAllViews();
62
    setupBackButton(act);
63
    layout.addView(mBackButton);
162
    final int margin= (int)(width*RubikActivity.MARGIN);
163
    final int icon = RubikActivity.getDrawable(R.drawable.ui_small_cube_menu,R.drawable.ui_medium_cube_menu, R.drawable.ui_big_cube_menu, R.drawable.ui_huge_cube_menu);
164
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT);
165
    mObjectButton = new TransparentImageButton(act, icon, TransparentImageButton.GRAVITY_MIDDLE, params);
166

  
167
    mObjectButton.setOnClickListener( new View.OnClickListener()
168
      {
169
      @Override
170
      public void onClick(View view)
171
        {
172
        if( mObjectPopup==null )
173
          {
174
          float height= act.getScreenHeightInPixels();
175
          setupObjectWindow(act,width,height);
176
          }
177

  
178
        if( act.getControl().isUINotBlocked())
179
          {
180
          int rowCount = Math.min(mMaxRowCount,mRowCount);
181
          View popupView = mObjectPopup.getContentView();
182
          popupView.setSystemUiVisibility(RubikActivity.FLAGS);
183
          displayPopup(act,view,mObjectPopup,mObjectSize*mColCount,mObjectSize*rowCount,margin,margin);
184
          }
185
        }
186
      });
187
    }
188

  
189
///////////////////////////////////////////////////////////////////////////////////////////////////
190
// work around lame bugs in Android's version <= 10 pop-up and split-screen modes
191

  
192
  private void displayPopup(ConfigActivity act, View view, PopupWindow window, int w, int h, int xoff, int yoff)
193
    {
194
    View topLayout = act.findViewById(R.id.mainLayout);
195
    boolean isFullScreen;
196

  
197
    if( topLayout!=null )
198
      {
199
      topLayout.getLocationOnScreen(mLocation);
200
      isFullScreen = (mLocation[1]==0);
201
      }
202
    else
203
      {
204
      isFullScreen = true;
205
      }
206

  
207
    try
208
      {
209
      // if on Android 11 or we are fullscreen
210
      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R || isFullScreen )
211
        {
212
        window.showAsDropDown(view, xoff, yoff, Gravity.CENTER);
213
        window.update(view, w, h);
214
        }
215
      else  // Android 10 or below in pop-up mode or split-screen mode
216
        {
217
        view.getLocationOnScreen(mLocation);
218
        int width  = view.getWidth();
219
        int height = view.getHeight();
220
        int x = mLocation[0]+(width-w)/2;
221
        int y = mLocation[1]+height+yoff;
222

  
223
        window.showAsDropDown(view);
224
        window.update(x,y,w,h);
225
        }
226
      }
227
    catch( IllegalArgumentException iae )
228
      {
229
      // ignore, this means window is 'not attached to window manager' -
230
      // which most probably is because we are already exiting the app.
231
      }
64 232
    }
65 233

  
66 234
///////////////////////////////////////////////////////////////////////////////////////////////////
67
// PUBLIC API
68 235

  
69
  public ConfigScreen()
236
  private void prevObject(ConfigActivity act)
70 237
    {
238
    mObjectOrdinal--;
239
    if( mObjectOrdinal<0 ) mObjectOrdinal=NUM_OBJECTS-1;
240

  
241
    ObjectType type = ObjectType.getObject(mObjectOrdinal);
242
    act.changeObject(type);
243

  
244
    setupInfo(act);
245
    }
246

  
247
///////////////////////////////////////////////////////////////////////////////////////////////////
248

  
249
  private void nextObject(ConfigActivity act)
250
    {
251
    mObjectOrdinal++;
252
    if( mObjectOrdinal>=NUM_OBJECTS ) mObjectOrdinal=0;
253

  
254
    ObjectType type = ObjectType.getObject(mObjectOrdinal);
255
    act.changeObject(type);
256

  
257
    setupInfo(act);
258
    }
259

  
260
///////////////////////////////////////////////////////////////////////////////////////////////////
261

  
262
  private void setupPrevButton(final ConfigActivity act)
263
    {
264
    int icon = RubikActivity.getDrawable(R.drawable.ui_small_left,R.drawable.ui_medium_left, R.drawable.ui_big_left, R.drawable.ui_huge_left);
265
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0,LinearLayout.LayoutParams.MATCH_PARENT,1.0f);
266
    mPrevButton = new TransparentImageButton(act,icon,TransparentImageButton.GRAVITY_MIDDLE,params);
267

  
268
    mPrevButton.setOnClickListener( new View.OnClickListener()
269
      {
270
      @Override
271
      public void onClick(View v)
272
        {
273
        prevObject(act);
274
        mMovesText.setText(act.getString(R.string.mo_placeholder,mObjectOrdinal+1,NUM_OBJECTS));
275
        }
276
      });
277
    }
278

  
279
///////////////////////////////////////////////////////////////////////////////////////////////////
280

  
281
  private void setupNextButton(final ConfigActivity act)
282
    {
283
    int icon = RubikActivity.getDrawable(R.drawable.ui_small_right,R.drawable.ui_medium_right, R.drawable.ui_big_right, R.drawable.ui_huge_right);
284
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0,LinearLayout.LayoutParams.MATCH_PARENT,1.0f);
285
    mNextButton = new TransparentImageButton(act,icon,TransparentImageButton.GRAVITY_MIDDLE,params);
286

  
287
    mNextButton.setOnClickListener( new View.OnClickListener()
288
      {
289
      @Override
290
      public void onClick(View v)
291
        {
292
        nextObject(act);
293
        mMovesText.setText(act.getString(R.string.mo_placeholder,mObjectOrdinal+1,NUM_OBJECTS));
294
        }
295
      });
296
    }
297

  
298
///////////////////////////////////////////////////////////////////////////////////////////////////
299

  
300
  private void setupTextView(final ConfigActivity act, final float width)
301
    {
302
    int padding = (int)(width*RubikActivity.PADDING);
303
    int margin  = (int)(width*RubikActivity.MARGIN);
304
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0,LinearLayout.LayoutParams.MATCH_PARENT,2.0f);
305
    params.topMargin    = margin;
306
    params.bottomMargin = margin;
307
    params.leftMargin   = margin;
308
    params.rightMargin  = margin;
309

  
310
    mMovesText = new TextView(act);
311
    mMovesText.setTextSize(20);
312
    mMovesText.setLayoutParams(params);
313
    mMovesText.setPadding(padding,0,padding,0);
314
    mMovesText.setGravity(Gravity.CENTER);
315
    mMovesText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mButtonSize);
316
    mMovesText.setText(act.getString(R.string.mo_placeholder,mObjectOrdinal+1,NUM_OBJECTS));
317
    }
318

  
319
///////////////////////////////////////////////////////////////////////////////////////////////////
320
// TODO: info pane
321

  
322
  private void setupInfo(ConfigActivity act)
323
    {
324

  
325
    }
326

  
327
///////////////////////////////////////////////////////////////////////////////////////////////////
328

  
329
  void enterScreen(final ConfigActivity act, final int objectOrdinal)
330
    {
331
    int width = act.getScreenWidthInPixels();
332
    mBarHeight = act.getHeightBar();
333
    mButtonSize = width*RubikActivity.BUTTON_TEXT_SIZE;
334

  
335
    mRowCount = (NUM_OBJECTS + NUM_COLUMNS-1) / NUM_COLUMNS;
336
    mColCount = NUM_COLUMNS;
337

  
338
    mObjectOrdinal = objectOrdinal;
339

  
340
    LinearLayout.LayoutParams paramsL = new LinearLayout.LayoutParams((int)(width/4),LinearLayout.LayoutParams.MATCH_PARENT);
341
    LinearLayout.LayoutParams paramsM = new LinearLayout.LayoutParams((int)(width/2),LinearLayout.LayoutParams.MATCH_PARENT);
342
    LinearLayout.LayoutParams paramsR = new LinearLayout.LayoutParams((int)(width/4),LinearLayout.LayoutParams.MATCH_PARENT);
343

  
344
    LinearLayout layoutLeft = new LinearLayout(act);
345
    layoutLeft.setLayoutParams(paramsL);
346
    LinearLayout layoutMid  = new LinearLayout(act);
347
    layoutMid.setLayoutParams(paramsM);
348
    LinearLayout layoutRight= new LinearLayout(act);
349
    layoutRight.setLayoutParams(paramsR);
350

  
351
    setupObjectButton(act,width);
352
    setupPrevButton(act);
353
    setupNextButton(act);
354
    setupTextView(act,width);
355
    setupBackButton(act);
356

  
357
    layoutLeft.addView(mObjectButton);
358
    layoutMid.addView(mPrevButton);
359
    layoutMid.addView(mMovesText);
360
    layoutMid.addView(mNextButton);
361
    layoutRight.addView(mBackButton);
362

  
363
    LinearLayout layout = act.findViewById(R.id.lowerBar);
364
    layout.removeAllViews();
365
    layout.addView(layoutLeft);
366
    layout.addView(layoutMid);
367
    layout.addView(layoutRight);
71 368

  
369
    setupInfo(act);
72 370
    }
73 371
}
src/main/java/org/distorted/config/ConfigSurfaceView.java
47 47
      mScreenWidth = width;
48 48
      mScreenHeight= height;
49 49
      mObjectController.setScreenSize(width,height);
50
      mObjectController.setObjectScale(0.80f);
50
      mObjectController.setObjectScale(1.00f);
51 51

  
52 52
      if( !mCreated )
53 53
        {
src/main/java/org/distorted/screens/RubikScreenPlay.java
29 29
import android.view.Gravity;
30 30
import android.view.LayoutInflater;
31 31
import android.view.View;
32
import android.view.ViewGroup;
33 32
import android.widget.Button;
34 33
import android.widget.GridLayout;
35 34
import android.widget.ImageButton;
src/main/res/layout/config.xml
1 1
<?xml version="1.0" encoding="utf-8"?>
2 2
<LinearLayout  xmlns:android="http://schemas.android.com/apk/res/android"
3
    android:id="@+id/mainLayout"
3 4
    android:layout_width="match_parent"
4 5
    android:layout_height="match_parent"
5 6
    android:orientation="vertical">
6 7

  
7
    <LinearLayout
8
        android:id="@+id/hiddenBar"
8
    <org.distorted.config.ConfigSurfaceView
9
        android:id="@+id/configSurfaceView"
9 10
        android:layout_width="match_parent"
10
        android:layout_height="100dp"
11
        android:gravity="center"
12
        android:orientation="horizontal"
13
        android:background="@android:color/transparent">
14
    </LinearLayout>
11
        android:layout_height="0dp"
12
        android:layout_weight="1"/>
15 13

  
16
    <LinearLayout
17
        android:id="@+id/upperBar"
14
    <ScrollView
15
        android:id="@+id/configScroll"
18 16
        android:layout_width="match_parent"
19
        android:layout_height="100dp"
20
        android:gravity="center"
21
        android:orientation="horizontal"
22
        android:background="@android:color/transparent">
23
    </LinearLayout>
24

  
25
    <LinearLayout
26
        android:layout_width="match_parent"
27
        android:layout_height="match_parent"
28
        android:gravity="center"
29
        android:orientation="vertical"
30
        android:background="@android:color/transparent">
31

  
32
        <org.distorted.config.ConfigSurfaceView
33
           android:id="@+id/configSurfaceView"
34
           android:layout_width="match_parent"
35
           android:layout_height="0dp"
36
           android:layout_weight="1"/>
37

  
38
        <ScrollView
39
           android:id="@+id/configScroll"
40
           android:layout_width="match_parent"
41
           android:layout_height="0dp"
42
           android:layout_weight="1"/>
43

  
44
    </LinearLayout>
17
        android:layout_height="0dp"
18
        android:layout_weight="1"/>
45 19

  
46 20
    <LinearLayout
47 21
        android:id="@+id/lowerBar"
48 22
        android:layout_width="match_parent"
49 23
        android:layout_height="100dp"
24
        android:layout_gravity="end"
50 25
        android:orientation="horizontal"
51
        android:background="@android:color/transparent">
26
        android:background="@color/light_grey">
52 27
    </LinearLayout>
53 28

  
54 29
</LinearLayout>
src/main/res/layout/popup_object_simple.xml
1
<?xml version="1.0" encoding="utf-8"?>
2
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
3
    android:id="@+id/objectScroll"
4
    android:layout_width="match_parent"
5
    android:layout_height="0dp"
6
    android:layout_weight="1">
7

  
8
    <GridLayout
9
        android:id="@+id/objectGrid"
10
        android:layout_width="match_parent"
11
        android:layout_height="wrap_content">
12
    </GridLayout>
13

  
14
</ScrollView>

Also available in: Unified diff