web-dev-qa-db-ja.com

ScrollView内の画像のグリッド

テキストと画像の両方を含む画面を作成しようとしています。以下に示すように、画像をグリッドのようにレイアウトする必要がありますが、周囲のScrollViewによって提供されるもの以外のスクロール機能を持​​たないようにします。

画像は私の質問を最もよく示しています:

alt text

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

グリッドにスクロール機能がない、さまざまな数の画像のグリッドを表示する最良の方法は何ですか?

GridViewのスクロール機能を無効にしても機能しないことに注意してください。これはスクロールバーを無効にするだけですが、すべてのアイテムを表示するわけではありません。

更新:下の画像は、GridViewでスクロールバーが無効になっている状態を示しています。

alt text

63
hanspeide

ああ、そうだ、これで問題が発生するだろう。スクロールと子供のリサイクルに加えて、より有益な機能があることは誰もが知っているので、ListViewとGridViewを展開して子供をラップすることはできません。

それにもかかわらず、これを回避したり、必要に応じて独自のレイアウトを作成したりできます。私の頭の上では、2つの可能性が考えられます。

私自身のアプリでは、ScrollView内にListViewを埋め込みました。これを行うには、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_MOSTonMeasureメソッド内で、すべての子を作成して測定します(ソースコードを参照することでこれを発見しました)。 GridViewが同じように動作することを願っていますが、動作しない場合でも、GridViewのすべてのコンテンツを自分で測定できます。ただし、GridViewをだまして実行できるようにすると簡単です。

ここで、このソリューションはGridViewを非常に効率的にするビューリサイクルを完全に無効にし、それらのImageViewはすべて表示されていなくてもメモリ内にあることに留意する必要があります。私の次のソリューションでも同じことが言えます。

他の可能性は、GridViewを捨てて独自のレイアウトを作成することです。 AbsoluteLayoutまたはRelativeLayoutのいずれかを拡張できます。たとえば、RelativeLayoutを拡張する場合、各画像を配置できますLEFT_OF前の行。各行のスペースがなくなるまで各画像の幅を追跡し、新しい行の最初の画像を配置して次の行を開始しますBELOW最後の行。画像を水平方向に中央揃えするか、等間隔の列に配置するには、さらに苦労する必要があります。たぶんAbsoluteLayoutの方が良いでしょう。いずれにせよ、痛みのようなもの。

がんばろう。

186
Neil Traft

ScrollViewにGridViewを埋め込む代わりに、ヘッダーとフッターを含むGridViewを使用できます。ヘッダーとフッターは何でも構いません-テキスト、画像、リストなど。ヘッダーとフッターを含むGridViewの例があります。 https://github.com/SergeyBurish/HFGridView

4
Sergey Burish

これには2つのソリューションがあります。

  1. 独自のカスタムレイアウトを作成します。これはより困難なソリューションになります(ただし、正しいソリューションと見なされる場合があります)。

  2. コードでGridViewの実際の高さを設定します。例えば:

 RelativeLayout.LayoutParams lp =(RelativeLayout.LayoutParams)myGridView.getLayoutParams(); 
 // lp.setMargins(0、0、10、10); //レイアウトマージンがある場合は、それらも設定する必要があります
 lp.height = measureRealHeight(...); 
 myGridView.setLayoutParams(lp); 

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+。

3
Edi

このような非スクロール可能なリストビューを作成します。

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"/>

これは動作するはずです。

2
user3282666

ScrollView内でGridViewのサイズを固定し、スクロールを有効にする方法を見つけました。

そのためには、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"}));

私はそれが役立つことを願っています=)

1
Lionel T.

これを試して

 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();
    }
0
Roman Mosiienko

保存ScrollView内に他のビューがあるGridViewですべてスクロールするには、次のリンクにアクセスしてください: 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);_
0
Sarith NOB