Сетки изображений внутри представление ScrollView


Я пытаюсь создать экран с текстом и изображениями. Я хочу, чтобы изображения были выложены как сетка, как показано ниже, но я хочу, чтобы у них не было других функций прокрутки, которые предоставляются окружающим ScrollView.

изображение лучше всего иллюстрирует мой вопрос:

<ScrollView>
    <LinearLayout>
        <ImageView />
        <TextView />
        <GridView />
        <TextView />
    </LinearLayout>
</ScrollView>

каков наилучший способ показать сетку из различного количества изображений, где сетка не имеет функции прокрутки?

Пожалуйста, обратите внимание это отключение функции прокрутки для GridView не работает, так как это просто отключает полосы прокрутки, но не показывает все элементы.

обновление: На рисунке ниже показано, как это выглядит с отключенными полосами прокрутки в GridView.

7 63

7 ответов:

О боже, да, у тебя будут проблемы с этим. Это сводит меня с ума, что ListViews и GridViews не могут быть расширены, чтобы обернуть своих детей, потому что мы все знаем, что у них есть более полезные функции в дополнение к их прокрутке и переработке их детей.

тем не менее, вы можете взломать вокруг этого или создать свой собственный макет под свои нужды без особых трудностей. С моей головы, я могу думать о двух возможностях:

в моем собственное приложение у меня встроенный элемент управления ListView внутри представление ScrollView. Я сделал это, явно сказав, что ListView должен быть точно таким же высоким, как и его содержимое. Я делаю это, изменяя параметры макета прямо внутри ListView.onMeasure() метод вот так:

public class ExpandableListView extends ListView {

    boolean expanded = false;

    public ExpandableListView(Context context, AttributeSet attrs, int defaultStyle) {
        super(context, attrs, defaultStyle);
    }

    public boolean isExpanded() {
        return expanded;
    }

    public void setExpanded(boolean expanded) {
        this.expanded = expanded;
    }

    @Override
    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // HACK!  TAKE THAT ANDROID!
        if (isExpanded()) {         
            // Calculate entire height by providing a very large height hint.
            // View.MEASURED_SIZE_MASK represents the largest height possible.
            int expandSpec = MeasureSpec.makeMeasureSpec(MEASURED_SIZE_MASK,
                        MeasureSpec.AT_MOST);
            super.onMeasure(widthMeasureSpec, expandSpec);

            LayoutParams params = getLayoutParams();
            params.height = getMeasuredHeight();
        } else {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    }
}

это работает, потому что когда вы даете ListView в режиме AT_MOST, Он создает и измеряет все свои дети для вас, прямо внутри onMeasure способ (я обнаружил это, просматривая исходный код). Надеюсь, GridView ведет себя то же самое, но если это не так, вы все равно можете измерить все содержимое GridView самостоятельно. Но было бы проще, если бы вы могли обмануть GridView, чтобы сделать это за вас.

теперь вы должны иметь в виду, что это решение полностью отключит переработку представления, которая делает GridView настолько эффективным, и все эти изображения будут находиться в памяти, даже если они не видны. То же самое касается и моего следующего решения.

другая возможность состоит в том, чтобы бросить GridView и создать ваш собственный макет. Вы можете расширить либо AbsoluteLayout или RelativeLayout. Например, если вы расширяете RelativeLayout, вы можете разместить каждое изображение LEFT_OF предыдущий, отслеживая ширину каждого изображения, пока вы не закончите комнату в этой строке, а затем запустите следующую строку, поместив первое изображение новой строки BELOW самое высокое изображение последней строки. Чтобы получить изображения по горизонтали или в равномерно расположенных столбцах, вам придется пройти еще больше боли. Может быть, абсолютный выход лучше. В любом случае, немного больно.

удачи.

GridView с верхним и нижним колонтитулами можно использовать вместо того, чтобы пытаться встроить GridView в ScrollView. Header и footer может быть что угодно - текст, картинки, списки и т. д. Есть пример GridView с верхним и нижним колонтитулами:https://github.com/SergeyBurish/HFGridView

у вас есть 2 решения для этого:

  1. напишите свой собственный макет. Это было бы более трудным решением (но может считаться правильным).

  2. установите реальную высоту вашего GridView в коде. Например:

  RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) myGridView.getLayoutParams();
  // lp.setMargins(0, 0, 10, 10); // if you have layout margins, you have to set them too
  lp.height = measureRealHeight(...);
  myGridView.setLayoutParams(lp);

The measureRealHeight() метод должен выглядеть примерно так (Надеюсь я правильно понял):

private int measureRealHeight(...)
{
  final int screenWidth = getWindowManager().getDefaultDisplay().getWidth();
  final double screenDensity = getResources().getDisplayMetrics().density;
  final int paddingLeft = (int) (X * screenDensity + 0.5f); // where X is your desired padding
  final int paddingRight = ...;
  final int horizontalSpacing = (int) (X * screenDensity + 0.5f); // the spacing between your columns
  final int verticalSpacing = ...; // the spacing between your rows
  final int columnWidth = (int) (X * screenDensity + 0.5f);             
  final int columnsCount = (screenWidth - paddingLeft - paddingRight + horizontalSpacing - myGridView.getVerticalScrollbarWidth()) / (columnWidth + horizontalSpacing);
  final int rowsCount = picsCount / columnsCount + (picsCount % columnsCount == 0 ? 0 : 1);

  return columnWidth * rowsCount + verticalSpacing * (rowsCount - 1);
}

приведенный выше код должен работать в Android 1.5+.

создать не прокручиваемый вид списка, как это:

public class ExpandableListView extends ListView{

public ExpandableListView(Context context) {
    super(context);
}

public ExpandableListView(Context context, AttributeSet attrs, int defaultStyle) {
    super(context, attrs, defaultStyle);
}

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

@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    int heightMeasureSpec_custom = MeasureSpec.makeMeasureSpec(
            Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
    super.onMeasure(widthMeasureSpec, heightMeasureSpec_custom);
    ViewGroup.LayoutParams params = getLayoutParams();
    params.height = getMeasuredHeight();
  }
}

в файле макета создайте такой элемент:

<com.example.ExpandableListView
           android:layout_width="match_parent"
           android:layout_height="wrap_content"/>

Это должно работать.

Я нашел способ дать GridView фиксированный размер внутри ScrollView и включить прокрутку.

для этого вам нужно будет реализовать новый класс, расширяющий GridView и переопределить onTouchEvent() для вызова requestDisallowInterceptTouchEvent(true). Таким образом, Родительский вид оставит сетку перехватывать события касания.

GridViewScrollable.java:

package com.example;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.GridView;

public class GridViewScrollable extends GridView {

    public GridViewAdjuntos(Context context) {
        super(context);
    }

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

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

    @Override
    public boolean onTouchEvent(MotionEvent ev){
        // Called when a child does not want this parent and its ancestors to intercept touch events.
        requestDisallowInterceptTouchEvent(true);
        return super.onTouchEvent(ev);
    }
}

добавьте его в свой макет с характеристиками, которые вы хотите:

<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="match_parent"
android:isScrollContainer="true" >

    <com.example.GridViewScrollable
    android:id="@+id/myGVS"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:clickable="true"
    android:numColumns="auto_fit"
    android:columnWidth="100dp"
    android:stretchMode="columnWidth" />

</ScrollView>

и просто сделать это в вашей деятельности и установите адаптер, например ArrayAdapter:

GridViewScrollable mGridView = (GridViewScrollable) findViewById(R.id.myGVS);
mGridView.setAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, new String[]{"one", "two", "three", "four", "five"}));

надеюсь, это поможет =)

попробуй такое

 public static void setGridViewHeightBasedOnChildren(GridView gridView, int columns) {
        ListAdapter listAdapter = gridView.getAdapter();
        if (listAdapter == null)
            return;
        int desiredWidth = View.MeasureSpec.makeMeasureSpec(gridView.getWidth(), View.MeasureSpec.UNSPECIFIED);
        int totalHeight = 0;
        View view = null;
        int rows = listAdapter.getCount() / columns;
        if(listAdapter.getCount() % columns> 0){
            rows++;
        }
        for (int i = 0; i < rows; i++) {
            view = listAdapter.getView(i, view, gridView);
            if (i == 0)
                view.setLayoutParams(new ViewGroup.LayoutParams(desiredWidth, LinearLayout.LayoutParams.WRAP_CONTENT));

            view.measure(desiredWidth, View.MeasureSpec.UNSPECIFIED);
            totalHeight += view.getMeasuredHeight();
        }
        ViewGroup.LayoutParams params = gridView.getLayoutParams();
        params.height = totalHeight + (gridView.getHorizontalSpacing() * rows);
        gridView.setLayoutParams(params);
        gridView.requestLayout();
    }

для GridView с другим видом внутри сохранить ScrollView, чтобы сделать все это прокрутки, перейдите по этой ссылке: http://www.londatiga.net/it/programming/android/make-android-listview-gridview-expandable-inside-scrollview/#comment-3967742. это полезно и сэкономило мое время, которое я просто провожу 5 минут с этим, когда я никогда не знал об этом.

обновление:

из ссылки у меня есть настроить ExpandedGridView:

public class ExpandedGridView extends GridView {
    boolean expanded = false;

    public ExpandedGridView(Context context) {
        super(context);
    }

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

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

    public boolean isExpanded() {
        return expanded;
    }

    @Override
    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // HACK! TAKE THAT ANDROID!
        if (isExpanded()) {
            // Calculate entire height by providing a very large height hint.
            // But do not use the highest 2 bits of this integer; those are
            // reserved for the MeasureSpec mode.
            int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
            super.onMeasure(widthMeasureSpec, expandSpec);
            ViewGroup.LayoutParams params = getLayoutParams();
            params.height = getMeasuredHeight();
        } else {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    }

    public void setExpanded(boolean expanded) {
        this.expanded = expanded;
    }
}

для вашего изменения xml из GridView в ExpandedGridView, которые были настроены.

<com.your.package.ExpandedGridView
    android:id="@+id/home_screen_list_goals"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:numColumns="2" />

использование:

назовите это в своей деятельности. Если во фрагменте использовать contentView.findViewById(...). Какой contentView-это весь ваш макет, определенный.

ExpandedGridView gridView = (ExpandedGridView) findViewById(R.id.home_screen_list_goals);
//set data into grid view
gridView.setAdapter(YOUR_ADAPTER_OBJECT);
gridView.setExpanded(true);