Оформлення елементів GridView квадратними


78

Я хотів би, щоб мої предмети GridViewбули квадратними. Є 2 стовпці, а ширина елементів - fill_parent(наприклад, вони займають якомога більше горизонтального простору. Елементи - це власні види.

Як зробити так, щоб висота елементів дорівнювала їхній змінній ширині?

Відповіді:


106

Існує більш просте рішення, коли стовпці GridView розтягуються. Просто перевизначте onMeasure макета елемента GridView за допомогою ...

@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, widthMeasureSpec);
}

Чудово працює. У відповіді я пропустив лише кілька речей: 1. Висота ігнорується, а ширина передається як висота. 2. Метод слід замінити в елементі та самій сітці.
AlikElzin-kilaka

12
Близько 1: саме це робить його квадратним - "
mDroidd

2
@KarthikPalanivelu Це буде використано у макеті елементів вашої сітки, а не самого GridView. Можливо, ви можете розширити RelativeLayout до SquareRelativeLayout за допомогою цього фрагмента.
jdamcd

1
якщо я роблю це у своєму gridview, я роблю квадрат GridView, а не його дітей.
Даніе Бо

4
Повна відповідь була б непоганою. Ви хочете розширити gridview?
StarWind0

56

Або якщо ви хочете розширити представлення, просто зробіть щось дуже просте, наприклад:

public class SquareImageView extends ImageView
{

    public SquareImageView(final Context context)
    {
        super(context);
    }

    public SquareImageView(final Context context, final AttributeSet attrs)
    {
        super(context, attrs);
    }

    public SquareImageView(final Context context, final AttributeSet attrs, final int defStyle)
    {
        super(context, attrs, defStyle);
    }


    @Override
    protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec)
    {
        final int width = getDefaultSize(getSuggestedMinimumWidth(),widthMeasureSpec);
        setMeasuredDimension(width, width);
    }

    @Override
    protected void onSizeChanged(final int w, final int h, final int oldw, final int oldh)
    {
        super.onSizeChanged(w, w, oldw, oldh);
    }
}

Варто зазначити, що super.onMeasure()це не потрібно. onMeasuredВимога полягає в тому, що ви повинні телефонувати setMeasuredDimension.


2
Працює як шарм. Дякую Кріс :)
Картік Андгаміл

2
@ Chris.Jenkins Я не згоден з вашим останнім коментарем: якщо я не зателефоную super.onMeasure(), розміщений усередині нього ImageView не буде намальований. Тому, здається, це потрібно як перший рядок onMeasureметоду.
cyrilchampier

@nerith, це на конкретному пристрої, оскільки я використовую цей код дуже довго і ніколи не впадаю в проблеми. Цікаво побачити, як відтворити побачене.
Кріс Дженкінс

@ Chris.Jenkins не на певному пристрої. Мій SquareFrameLayout завантажується з xml. Ви додаєте своїх дітей програмно?
cyrilchampier

О так, це не буде працювати з переглядами груп перегляду. Можливо, мені слід про це згадати.
Кріс Дженкінс,

16

Я не впевнений, що це можливо за допомогою поточних віджетів. Найкращою ставкою може бути розміщення власного подання у власному "SquareView". Цей вигляд міг містити лише 1 дочірній вигляд і примусити висоту дорівнювати ширині, коли викликається метод onLayout.

Я ніколи не намагався зробити щось подібне, але думаю, це не повинно бути надто складно. Альтернативним (і, можливо, дещо простішим) рішенням може бути підклас кореневого макета власного подання (наприклад, якщо це LinearLayout, зробити SquareLinearLayout) і використовувати його як контейнер.

редагувати: Ось основна реалізація, яка, здається, працює для мене:

package com.mantano.widget;

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;

public class SquareView extends ViewGroup {

    public SquareView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onLayout(boolean changed, int l, int u, int r, int d) {
        getChildAt(0).layout(0, 0, r-l, d-u); // Layout with max size
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        View child = getChildAt(0);
        child.measure(widthMeasureSpec, widthMeasureSpec);
        int width = resolveSize(child.getMeasuredWidth(), widthMeasureSpec);
        child.measure(width, width); // 2nd pass with the correct size
        setMeasuredDimension(width, width);
    }
}

Він розроблений для того, щоб мати унікальну дитину, але я проігнорував усі перевірки заради простоти. Основна ідея полягає в тому, щоб виміряти дитину з параметрами ширини / висоти, встановленими GridView (у моєму випадку він використовує numColumns = 4 для обчислення ширини), а потім зробити другий прохід з кінцевими розмірами, з висотою = ширина. .. Макет - це просто макет, який розміщує унікальну дочірню сторінку на (0, 0) з бажаними розмірами (праворуч-ліворуч, вниз-вгору).

І ось XML, який використовується для елементів GridView:

<?xml version="1.0" encoding="utf-8"?>
<com.mantano.widget.SquareView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent" android:layout_height="wrap_content">

    <LinearLayout android:id="@+id/item" android:layout_width="fill_parent"
        android:layout_height="fill_parent" android:orientation="horizontal"
        android:gravity="center">

        <TextView android:id="@+id/text" android:layout_width="fill_parent"
            android:layout_height="wrap_content" android:text="Hello world" />
    </LinearLayout>
</com.mantano.widget.SquareView>

Я використовував LinearLayout всередині SquareView, щоб він керував усіма гравітаційними можливостями, полями тощо.

Я не впевнений, наскільки добре (або погано) цей віджет реагуватиме на зміни орієнтації та розмірів, але, схоже, він працює коректно.


Це все добре звучить, єдина проблема - правильно писати onLayout (або onMeasure). В даний час я встановлюю висоту / ширину в ItemAdapter.getView (), але мені це рішення не подобається.
anagaf

@anagaf Я відредагував свою відповідь кодом, який я щойно перевірив і який, здається, працює. Це досить легко зрозуміти, тому це має бути легко виправити на той випадок, якщо ви знайдете якісь збої ^^ (не впевнений, чи повинен був я відредагувати чи опублікувати другу відповідь, вибачте, якщо я зробив це неправильно!)
Григорій

1
Вищевказаний макет не працює --- я не знаю чому, але з дітьми існують тонкі проблеми з макетом, які означають, що, наприклад, TextViews не обгортається, а RelativeLayouts жахливо плутають. Однак тут я знайшов еквівалент: stackoverflow.com/questions/2948212/ ... ... хоча мені все-таки потрібно було трохи його відрегулювати (розміри засновані на найбільшому розмірі, а не просто на ширині).
Девід Дано

12

В кінцевому підсумку отримати квадрат елемента сітки досить просто.

У вашому методі "GetView" вашого мережевого адаптера просто виконайте:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    GridView grid = (GridView)parent;
    int size = grid.getRequestedColumnWidth();

    TextView text = new TextView(getContext());
    text.setLayoutParams(new GridView.LayoutParams(size, size));

    // Whatever else you need to set on your view

    return text;
}

Це єдине рішення, яке спрацювало для мене ... Щиро дякую !!
Зеба,

4
довелося замінити "getRequestColumnWidth" на "getColumnWidth", і це у мене спрацювало .. дякую!
Ayad Kara Kâhya

1
тут же: мені довелося замінити getRequestedColumnWidthз getColumnWidthі працював для мене ... дякую!
Yahya

6

Я не знаю, чи це найкращий спосіб, але я досягаю цього, роблячи так, щоб мій власний вигляд перевизначав onSizeChanged таким чином:

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);

    if (getLayoutParams() != null && w != h) {
        getLayoutParams().height = w;
        setLayoutParams(getLayoutParams());
    }
}

Я використовую цей власний вигляд всередині LinearLayout та GridView, і в обох він відображає квадрат!


О, людино, ти рятувальник життя, я цілими днями борюся з цим. Відповідь Григорія чудово працює, якщо у вас багато дітей; тоді, як зазначає коментар, TextViews не обертаються, і більшість подань не коригують свої межі. Але це виправляє!
Макаріо

6

Це спрацювало для мене!

Якщо ви схожі на мене, і ви не можете використовувати getRequestColumnWidth (), оскільки ваш minSdk нижчий за 16, я пропоную цей варіант.

  1. у вашому фрагменті:

    DisplayMetrics dm = new DisplayMetrics(); getActivity().getWindowManager().getDefaultDisplay().getMetrics(dm); int size = dm.widthPixels / nbColumns; CustomAdapter adapter = new CustomAdapter(list, size, getActivity());

  2. у вашому адаптері (у getView (int позиція, View convertView, ViewGroup батьківський))

    v.setLayoutParams(new GridView.LayoutParams(GridView.AUTO_FIT, size));

  3. fragment.xml:

    <GridView android:id="@+id/gridView" android:layout_width="match_parent" android:layout_height="match_parent" android:horizontalSpacing="3dp" android:verticalSpacing="3dp" android:numColumns="4" android:stretchMode="columnWidth" />

  4. custom_item.xml: (наприклад)

    <ImageView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/picture" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="centerCrop" />

Сподіваюся, це комусь допоможе!


5

якщо ви встановите статичну кількість стовпців у xml, тоді ви можете взяти ширину подання та розділити її на кількість стовпців.

якщо ви використовуєте, auto_fitтоді буде трохи складно отримати підрахунок стовпців (немає методу getColumnCount ()), крім цього, це питання має вам якось допомогти.

це код, який я використовую в getView(...)методі адаптера з фіксованою кількістю стовпців:

    item_side = mFragment.holder.grid.getWidth() / N_COL;
    v.getLayoutParams().height = item_side;
    v.getLayoutParams().width = item_side;

5

Спробуйте

<GridView
...
android:stretchMode="columnWidth" />

Ви також можете грати з іншими режимами


4

Це те, що я роблю, щоб показати квадратні комірки в GridView. Я не впевнений, що вам потрібні квадратні клітинки чи щось інше.

GridView grid = new GridView( this );
grid.setColumnWidth( UIScheme.cellSize );
grid.setVerticalSpacing( UIScheme.gap );
grid.setStretchMode( GridView.STRETCH_COLUMN_WIDTH );
grid.setNumColumns( GridView.AUTO_FIT );

І тоді подання, яке я створюю для кожної комірки, я повинен зробити з ним наступне:

cell.setLayoutParams( new GridView.LayoutParams(iconSize, iconSize) );

3

На основі відповіді Стіва Боркмана , який є API 16+:

@Override
public View getView(int position, View convertView, ViewGroup parent) {

    GridView grid = (GridView)parent;
    int size = grid.getColumnWidth();

    if (convertView == null){
        convertView = LayoutInflater.from(context).inflate(R.layout.your_item, null);
        convertView.setLayoutParams(new GridView.LayoutParams(size, size));
    }

     //Modify your convertView here

     return convertView;
}

1

У відповідь на відповідь @ Gregory, мені довелося обернути своє зображення у LinearLayout, щоб GridView не маніпулював його розмірами з квадрата. Зверніть увагу, що для зовнішнього LinearLayout слід встановити розмір зображення, а ширина стовпця GridView повинна бути шириною зображення PLUS будь-якого поля. Наприклад:

    <!-- LinearLayout wrapper necessary to wrap image button in order to keep square;
    otherwise, the grid view distorts it into rectangle.

    also, margin top and right allows the indicator overlay to extend top and right.

    NB: grid width is set in filter_icon_page.xml, and must correspond to size + margin
    -->
<LinearLayout
        android:id="@+id/sport_icon_lay"
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:orientation="vertical"

        android:layout_marginRight="6dp"
        android:layout_marginTop="6dp"
        >

    <ImageButton
            android:id="@+id/sport_icon"
            android:layout_width="60dp"
            android:layout_height="60dp"
            android:maxHeight="60dp"
            android:maxWidth="60dp"
            android:scaleType="fitCenter"
            />
</LinearLayout>

та GridView, як:

   <GridView
        android:id="@+id/grid"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:fillViewport="true"

        android:columnWidth="66dp"

        android:numColumns="auto_fit"
        android:verticalSpacing="25dp"
        android:horizontalSpacing="24dp"
        android:stretchMode="spacingWidth"

        />

-1

У вашій діяльності

 DisplayMetrics displaymetrics = new DisplayMetrics();
 getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
 valX = displaymetrics.widthPixels/columns_number;

у CustomAdapter GridView

 v.setLayoutParams(new GridView.LayoutParams(GridView.AUTO_FIT, YourActivity.valX));
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.