GridLayout (а не GridView), как равномерно распределить всех детей

Я хочу иметь сетку 2×2 с кнопками внутри. Это только ICS, поэтому я пытаюсь использовать новый GridLayout.

Вот XML моего макета:

<?xml version="1.0" encoding="utf-8"?> <GridLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/favorites_grid" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#00ff00" android:rowCount="2" android:columnCount="2"> <Button android:text="Cell 0" android:layout_row="0" android:layout_column="0" android:textSize="14dip" /> <Button android:text="Cell 1" android:layout_row="0" android:layout_column="1" android:textSize="14dip" /> <Button android:text="Cell 2" android:layout_row="1" android:layout_column="0" android:textSize="14dip" /> <Button android:text="Cell 3" android:layout_row="1" android:layout_column="1" android:textSize="14dip" /> </GridLayout> 

Проблема в том, что мои взгляды не растягиваются равномерно для каждой строки. Это вызывает много лишнего пространства справа от моего GridLayout.

Я попытался установить layout_gravity="fill_horizontal" но это применимо только к последнему виду в строке. Это означает, что Cell 1 растягивается полностью, чтобы дать достаточно места для Cell 0.

Мысли о том, как справиться с этим?

UPDATE : весы поддерживаются по API 21. См. Ответ PaulT для получения более подробной информации. END UPDATE Существуют ограничения при использовании GridLayout, следующая цитата взята из документации .

«GridLayout не поддерживает принцип веса, определенный по весу. В общем случае невозможно настроить GridLayout для распределения избыточного пространства в нетривиальных пропорциях между несколькими строками или столбцами … Для полного контроля над Избыточное распределение пространства в строке или столбце, используйте подкласс LinearLayout для хранения компонентов в связанной группе ячеек. "

Вот небольшой пример, который использует подходы LinearLayout. (Я использовал Space Views, который занимает неиспользованную область и нажимает кнопки в нужную позицию.)

 <GridLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:columnCount="1" > <TextView android:text="2x2 button grid" android:textSize="32dip" android:layout_gravity="center_horizontal" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <Space android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_weight="1" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button 1" /> <Space android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_weight="1" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="start" android:text="Button 2" /> <Space android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_weight="1" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" > <Space android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_weight="1" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button 3" /> <Space android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_weight="1" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="start" android:text="Button 4" /> <Space android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_weight="1" /> </LinearLayout> </GridLayout> 

Начиная с API 21 понятие веса было добавлено в GridLayout. Для поддержки старых устройств Android вы можете использовать GridLayout из библиотеки поддержки v7.

Следующий XML дает пример того, как вы можете использовать весы для заполнения ширины экрана.

 <?xml version="1.0" encoding="utf-8"?> <android.support.v7.widget.GridLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:grid="http://schemas.android.com/apk/res-auto" android:id="@+id/choice_grid" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:padding="4dp" grid:alignmentMode="alignBounds" grid:columnCount="2" grid:rowOrderPreserved="false" grid:useDefaultMargins="true"> <TextView android:layout_width="0dp" android:layout_height="100dp" grid:layout_columnWeight="1" grid:layout_gravity="fill_horizontal" android:gravity="center" android:background="#FF33B5E5" android:text="Tile1" /> <TextView android:layout_width="0dp" android:layout_height="100dp" grid:layout_columnWeight="1" grid:layout_gravity="fill_horizontal" android:gravity="center" android:background="#FF33B5E5" android:text="Tile2" /> <TextView android:layout_width="0dp" android:layout_height="100dp" grid:layout_columnWeight="1" grid:layout_gravity="fill_horizontal" android:gravity="center" android:background="#FF33B5E5" android:text="Tile3" /> <TextView android:layout_width="0dp" android:layout_height="100dp" grid:layout_columnWeight="1" grid:layout_gravity="fill_horizontal" android:gravity="center" android:background="#FF33B5E5" android:text="Tile4" /> </android.support.v7.widget.GridLayout> 

Введите описание изображения здесь

Appcompat21 GridLayout имеет весы столбцов и строк, которые можно использовать, как показано ниже, для равномерного создания каждого элемента сетки в gridlayout, как показано выше.

 <android.support.v7.widget.GridLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:grid="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_centerHorizontal="true" grid:alignmentMode="alignBounds" grid:columnCount="4"> <Button android:layout_width="0dp" style="?buttonStyle" android:layout_height="0dp" android:text="-1" grid:layout_columnWeight="1" grid:layout_rowWeight="1" grid:layout_gravity="fill"/> ... ... ... 

Вы можете установить ширину каждого ребенка динамически:

 GridLayout.LayoutParams params = (GridLayout.LayoutParams) child.getLayoutParams(); params.width = (parent.getWidth()/parent.getColumnCount()) -params.rightMargin - params.leftMargin; child.setLayoutParams(params); 

Начиная с API 21 без библиотеки поддержки v7 с помощью ScrollView:

Введите описание изображения здесь

XML:

 <?xml version="1.0" encoding="utf-8"?> <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" > <GridLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:columnCount="2" > <TextView android:layout_width="0dp" android:layout_height="100dp" android:layout_columnWeight="1" android:gravity="center" android:layout_gravity="fill_horizontal" android:background="@color/colorAccent" android:text="Tile1" /> <TextView android:layout_width="0dp" android:layout_height="100dp" android:layout_columnWeight="1" android:gravity="center" android:layout_gravity="fill_horizontal" android:background="@color/colorPrimaryDark" android:text="Tile2" /> <TextView android:layout_width="0dp" android:layout_height="100dp" android:layout_columnWeight="1" android:gravity="center" android:layout_gravity="fill_horizontal" android:background="@color/colorPrimary" android:text="Tile3" /> <TextView android:layout_width="0dp" android:layout_height="100dp" android:layout_columnWeight="1" android:gravity="center" android:layout_gravity="fill_horizontal" android:background="@color/colorAccent" android:text="Tile4" /> </GridLayout> </ScrollView> 

Попробуйте добавить в спецификацию GridLayout следующее. Это должно сработать.

андроид: useDefaultMargins = "истина"

Наконец я нашел решение. Как сказал Ротеммиз, вы должны сделать это динамично после этого. Этот код растягивает кнопки, чтобы заполнить представление по горизонтали, но то же самое можно сделать и по вертикали.

 public void fillview(android.support.v7.widget.GridLayout gl) { Button buttontemp; //Stretch buttons int idealChildWidth = (int) ((gl.getWidth()-20*gl.getColumnCount())/gl.getColumnCount()); for( int i=0; i< gl.getChildCount();i++) { buttontemp = (Button) gl.getChildAt(i); buttontemp.setWidth(idealChildWidth); } } 

(20 для внутренних и внешних отступов и полей. Это можно сделать более универсально, но это намного чище)

Тогда его можно вызвать так:

  android.support.v7.widget.GridLayout gl = (android.support.v7.widget.GridLayout)findViewById(R.id.buttongrid); ViewTreeObserver vto = gl.getViewTreeObserver(); vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {@Override public void onGlobalLayout() { android.support.v7.widget.GridLayout gl = (android.support.v7.widget.GridLayout) findViewById(R.id.buttongrid); fillview(gl); ViewTreeObserver obs = gl.getViewTreeObserver(); obs.removeGlobalOnLayoutListener(this); }}); 

Это должно быть сделано с наблюдателем, потому что нам нужно дождаться, пока изображение будет нарисовано, прежде чем мы будем называть представления.

В моем случае я динамически добавлял кнопки, поэтому для моего решения требовалась часть XML и часть Java. Мне приходилось находить и смешивать решения из нескольких разных мест и думать, что я поделюсь им здесь, чтобы кто-то другой, ищущий подобное решение, мог бы найти его полезным.

Первая часть моего файла макета XML …

 <android.support.v7.widget.GridLayout xmlns:grid="http://schemas.android.com/apk/res-auto" android:id="@+id/gl_Options" android:layout_width="match_parent" android:layout_height="wrap_content" grid:useDefaultMargins="true"> </android.support.v7.widget.GridLayout> 

grid:useDefaultMargins="true" не требуется, но я добавил, потому что это выглядело лучше для меня, вы можете применять другие визуальные эффекты (например, отступы), как упомянуто в некоторых ответах здесь. Теперь для кнопок, поскольку я должен добавить их динамически. Вот часть Java моего кода для создания этих кнопок, я включаю только те строки, которые связаны с этим контекстом. Предположим, что мне нужно сделать кнопки из числа myOptions , доступных для моего кода, и я также не копирую код OnClickListener.

 import android.support.v7.widget.GridLayout; //Reference to Library public class myFragment extends Fragment{ GridLayout gl_Options; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { gl_AmountOptions = (GridLayout)view.findViewById( R.id.gl_AmountOptions ); ... gl_Options.removeAllViews(); // Remove all existing views gl_AmountOptions.setColumnCount( myOptions.length <= 9 ? 3: 4 ); // Set appropriate number of columns for( String opt : myOptions ) { GridLayout.LayoutParams lParams = new GridLayout.LayoutParams( GridLayout.spec( GridLayout.UNDEFINED, 1f), GridLayout.spec( GridLayout.UNDEFINED, 1f)); // The above defines LayoutParameters as not specified Column and Row with grid:layout_columnWeight="1" and grid:layout_rowWeight="1" lParams.width = 0; // Setting width to "0dp" so weight is applied instead Button b = new Button(this.getContext()); b.setText( opt ); b.setLayoutParams(lParams); b.setOnClickListener( myClickListener ); gl_Options.addView( b ); } } } 

Поскольку мы используем GridLayout из библиотеки поддержки, а не стандартный GridLayout, мы должны рассказать о том, что в файле YourProject.grade .

 dependencies { compile 'com.android.support:appcompat-v7:23.4.0' ... compile 'com.android.support:gridlayout-v7:23.4.0' } 

Вы можете сделать это быстрее, переопределив метод ViewGroup onLayout. Это мое универсальное решение:

 package your.app.package; import android.content.Context; import android.view.ViewGroup; public class GridLayout extends ViewGroup { public GridLayout(Context context) { super(context); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { final int columns = 2;//edit this if you need different grid final int rows = 2; int children = getChildCount(); if (children != columns * rows) throw new IllegalStateException("GridLayout must have " + columns * rows + " children"); int width = getWidth(); int height = getHeight(); int viewWidth = width / columns; int viewHeight = height / rows; int rowIndex = 0; int columnIndex = 0; for (int i = 0; i < children; i++) { getChildAt(i).layout(viewWidth * columnIndex, viewHeight * rowIndex, viewWidth * columnIndex + viewWidth, viewHeight * rowIndex + viewHeight); columnIndex++; if (columnIndex == columns) { columnIndex = 0; rowIndex++; } } } } 

EDIT: не забывайте match_parent для детей!

 android:layout_width="match_parent" android:layout_height="match_parent" 

Лучшее решение, которое я смог найти, – использовать линейную компоновку (горизонтальную) для каждой строки, в которой вы хотите, и внутри нее назначить ширину кнопки (ячейки) до 0dp, а вес – 1. Для каждого из линейных макетов (строк) назначить высоту До 0dp и весом до 1. Найдите код ниже – также android: layout_gravity = "center_vertical" используется для выравнивания кнопок в строке, если они содержат текст переменной длины. Использование 0dp и вес это довольно аккуратный, но не очень известный трюк.

 <LinearLayout android:id="@+id/parent_layout" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@drawable/button_bue_3d" android:orientation="vertical" > <LinearLayout android:id="@+id/layout_row1" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:orientation="horizontal" > <Button android:id="@+id/button1" style="?android:attr/buttonStyleSmall" android:layout_height="wrap_content" android:layout_width="0dp" android:layout_weight="1" android:clickable="false" android:layout_gravity="center_vertical" android:text="ssssssssssssssssssssssssss" /> <Button android:id="@+id/button2" style="?android:attr/buttonStyleSmall" android:clickable="false" android:layout_height="wrap_content" android:layout_width="0dp" android:layout_weight="1" android:layout_gravity="center_vertical" android:text="sggggggg" /> </LinearLayout> <LinearLayout android:id="@+id/layout_row2" android:layout_weight="1" android:layout_width="match_parent" android:layout_height="0dp" android:orientation="horizontal" > <Button android:id="@+id/button3" style="?android:attr/buttonStyleSmall" android:layout_height="wrap_content" android:layout_width="0dp" android:layout_weight="1" android:layout_gravity="center_vertical" android:text="s" /> <Button android:id="@+id/button4" style="?android:attr/buttonStyleSmall" android:layout_height="wrap_content" android:layout_width="0dp" android:layout_weight="1" android:clickable="false" android:layout_gravity="center_vertical" android:text="s" /> </LinearLayout> </LinearLayout> 

Это правильный ответ

 <?xml version="1.0" encoding="utf-8"?> <GridLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/favorites_grid" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#00ff00" android:rowCount="2" android:columnCount="2"> <Button android:text="Cell 0" android:layout_row="0" android:layout_column="0" android:layout_columnWeight="1" android:layout_rowWeight="1" android:textSize="14dip" /> <Button android:text="Cell 1" android:layout_row="0" android:layout_column="1" android:textSize="14dip" android:layout_columnWeight="1" android:layout_rowWeight="1"/> <Button android:text="Cell 2" android:layout_row="1" android:layout_column="0" android:textSize="14dip" android:layout_columnWeight="1" android:layout_rowWeight="1"/> <Button android:text="Cell 3" android:layout_row="1" android:layout_column="1" android:textSize="14dip" android:layout_columnWeight="1" android:layout_rowWeight="1"/> </GridLayout> 

Я хотел бы иметь центрированную таблицу с выравниваемыми метками и выравниванием значений. Дополнительное пространство должно быть вокруг стола. После много экспериментов и не следуя тому, что документация сказала, что я должен делать, я придумал что-то, что работает. Вот что я сделал:

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:orientation="vertical" > <GridLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:columnCount="2" android:orientation="horizontal" android:useDefaultMargins="true" > <TextView android:layout_gravity="right" android:text="Short label:" /> <TextView android:id="@+id/start_time" android:layout_gravity="left" android:text="Long extended value" /> <TextView android:layout_gravity="right" android:text="A very long extended label:" /> <TextView android:id="@+id/elapsed_time" android:layout_gravity="left" android:text="Short value" /> </GridLayout> 

Это похоже на работу, но GridLayout показывает сообщение:

«Этот макет GridLayout или его родитель LinearLayout бесполезен»

Не уверен, почему это «бесполезно», когда оно работает для меня.

Я не уверен, почему это работает, или если это хорошая идея, но если вы попробуете его и можете предложить лучшую идею, небольшое улучшение или объяснить, почему он работает (или не будет работать), я буду благодарен за отзывы.

Благодарю.

Старый вопрос, но хотел добавить мое решение. Я создал «линейную схему сетки», которая имитирует сетку, но использует вложенные линейные макеты. Это позволяет растягиваться, чтобы заполнить пространство.

http://zerocredibility.wordpress.com/2014/12/18/linear-grid-layout/

Вот что я сделал, и я рад сказать, что это сработало для меня. Мне тоже нужна сетка из 2×2, 3×3 и т. Д., Чтобы покрыть весь экран. Gridlayouts не придерживаются ширины экрана. LinearLayouts – вид работы, но вы не можете использовать вложенные веса.

Лучшим вариантом для меня было использование Фрагментов. Я использовал этот учебник, чтобы начать с того, что я хотел сделать.

Вот какой код:

Основная деятельность:

 public class GridHolderActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main_6); } } 

Activity_main_6 XML (раздувает 3 фрагмента)

 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <fragment android:id="@+id/frag1" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:name=".TwoHorizontalGridFragment" tools:layout="@layout/two_horiz" /> <fragment android:id="@+id/frag2" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:name=".TwoHorizontalGridFragment" tools:layout="@layout/two_horiz" /> <fragment android:id="@+id/frag3" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:name=".Grid.TwoHorizontalGridFragment" tools:layout="@layout/two_horiz" /> 

Макет базового фрагмента

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="wrap_content" android:layout_gravity="center" android:layout_height="match_parent"> <ImageQueue android:layout_width="0dp" android:layout_height="wrap_content" android:id="@+id/img1" android:layout_weight="1"/> <ImageQueue android:layout_width="0dp" android:layout_height="wrap_content" android:id="@+id/img2" android:layout_weight="1"/> </LinearLayout> 

Класс фрагмента (обрабатывает только инициализацию пользовательского представления) раздувает 2 фрагмента на фрагмент

 public class TwoHorizontalGridFragment extends Fragment { private View rootView; private ImageQueue imageQueue1; private ImageQueue imageQueue2; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { /** * Inflate the layout for this fragment */ rootView = inflater.inflate( R.layout.two_horiz, container, false); return rootView; } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); imageQueue1 = (ImageQueue)rootView.findViewById(R.id.img1); imageQueue2 = (ImageQueue)rootView.findViewById(R.id.img2); imageQueue1.updateFiles(); imageQueue2.updateFiles(); } 

}

Это оно!

Это странная работа по использованию вложенных весов. Это дает мне идеальную сетку 2×3, которая заполняет весь экран как моего 10-дюймового планшета, так и моей ДНК-дроида-HTC. Дайте мне знать, как это происходит для вас!

Intereting Posts
Увеличенная реальность – отображение GPS в OpenGL Как программно написать ярлык на конкретную страницу на главном экране панели запуска Android? Создайте android framework.jar только GridView scrollBar: неустойчивое поведение при динамическом добавлении изображений Как получить версию Android sdk? Проверка статуса сообщения GCM Приложение перезапускает, а не возобновляет FirebaseMessagingService не может переопределить zzae (Intent) в zzb. Более слабая опорная ошибка Выпадающий список в гибридном приложении имеет черный текст на сером фоне на некоторых устройствах Android Переопределить цвет темы для выделения касания, прокручивать намеки Почему softkeyboard не отображается во Фрагменте с помощью WebView Шифрование AES j2me Не удается получить контакты с синхронизированными учетными записями gmail. Android Canvas. Перемещение и поворот растрового изображения по круговому пути на основе касания? Проблема с веб-хостом, файлы .apk для загрузки из браузера android