简体   繁体   English

如何将页脚添加到Gridview?

[英]How do I add a Footer to a Gridview?

I attempted to reverse engineer a gridview from an example found here: https://github.com/liaohuqiu/android-GridViewWithHeaderAndFooter 我试图从此处找到的示例对gridview进行反向工程: https : //github.com/liaohuqiu/android-GridViewWithHeaderAndFooter

using his source code found here: 使用他的源代码在这里找到:

https://github.com/liaohuqiu/android-cube-app/blob/master/src/in/srain/cube/demo/ui/fragment/GridViewWithHeaderAndFooterFragment.java#L89 https://github.com/liaohuqiu/android-cube-app/blob/master/src/in/srain/cube/demo/ui/fragment/GridViewWithHeaderAndFooterFragment.java#L89

but keep getting a casting error when I try to display images within it. 但是当我尝试在其中显示图像时,总是会出现转换错误。 I would like to learn how to do it myself because his code crashes when I try loading images using glide. 我想自己学习如何做,因为当我尝试使用glide加载图像时,他的代码崩溃了。

Here is the gridview code I have: 这是我有的gridview代码:

package customgridapp.customgridview;

import android.annotation.SuppressLint;
import android.content.Context;
import android.database.DataSetObservable;
import android.database.DataSetObserver;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.FrameLayout;
import android.widget.GridView;
import android.widget.ListAdapter;
import android.widget.WrapperListAdapter;

import java.util.ArrayList;

public class TestFooterGridView extends GridView{

private static final String TAG = "TestFooterGridView";

/**
 * A class that represents a fixed view in a list, for example a header at the top
 * or a footer at the bottom.
 */
private static class FixedViewInfo {
    /**
     * The view to add to the grid
     */
    public View view;
    public ViewGroup viewContainer;
    /**
     * The data backing the view. This is returned from {@link ListAdapter#getItem(int)}.
     */
    public Object data;
    /**
     * <code>true</code> if the fixed view should be selectable in the grid
     */
    public boolean isSelectable;
}

private ArrayList<FixedViewInfo> mHeaderViewInfos = new ArrayList<FixedViewInfo>();

private ArrayList<FixedViewInfo> mFooterViewInfos = new ArrayList<FixedViewInfo>();

private int mRequestedNumColumns;

private int mNumColmuns = 1;

private void initHeaderGridView() {
    super.setClipChildren(false);
}

public TestFooterGridView(Context context) {
    super(context);
    initHeaderGridView();
}

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

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

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

    if (mRequestedNumColumns != AUTO_FIT) {
        mNumColmuns = mRequestedNumColumns;
    }
    if (mNumColmuns <= 0) {
        mNumColmuns = 1;
    }

    ListAdapter adapter = getAdapter();
    if (adapter != null && adapter instanceof FooterViewGridAdapter) {
        ((FooterViewGridAdapter) adapter).setNumColumns(getNumColumns());
    }
}

@Override
public void setClipChildren(boolean clipChildren) {
    // Ignore, since the header rows depend on not being clipped
}

/**
 * Add a fixed view to appear at the top of the grid. If addHeaderView is
 * called more than once, the views will appear in the order they were
 * added. Views added using this call can take focus if they want.
 * <p>
 * NOTE: Call this before calling setAdapter. This is so HeaderFooterGridView can wrap
 * the supplied cursor with one that will also account for header views.
 *
 * @param v            The view to add.
 * @param data         Data to associate with this view
 * @param isSelectable whether the item is selectable
 */
public void addHeaderView(View v, Object data, boolean isSelectable) {
    ListAdapter adapter = getAdapter();

    if (adapter != null && !(adapter instanceof FooterViewGridAdapter)) {
        throw new IllegalStateException(
                "Cannot add header view to grid -- setAdapter has already been called.");
    }

    FixedViewInfo info = new FixedViewInfo();
  //  FrameLayout fl = new FullWidthFixedViewLayout(getContext());
  //  fl.addView(v);
    info.view = v;
  //  info.viewContainer = fl;
    info.data = data;
    info.isSelectable = isSelectable;
    mHeaderViewInfos.add(info);

    // in the case of re-adding a header view, or adding one later on,
    // we need to notify the observer
    if (adapter != null) {
        ((FooterViewGridAdapter) adapter).notifyDataSetChanged();
    }
}
/**
 * Add a fixed view to appear at the bottom of the grid. If addFooterView is
 * called more than once, the views will appear in the order they were
 * added. Views added using this call can take focus if they want.
 * <p>
 * NOTE: Call this before calling setAdapter. This is so HeaderFooterGridView can wrap
 * the supplied cursor with one that will also account for header views.
 *
 * @param v            The view to add.
 * @param data         Data to associate with this view
 * @param isSelectable whether the item is selectable
 */
public void addFooterView(View v, Object data, boolean isSelectable) {
    ListAdapter adapter = getAdapter();

    if (adapter != null && !(adapter instanceof FooterViewGridAdapter)) {
        throw new IllegalStateException(
                "Cannot add footer view to grid -- setAdapter has already been called.");
    }

    FixedViewInfo info = new FixedViewInfo();
    FrameLayout fl = new FullWidthFixedViewLayout(getContext());
    fl.addView(v);
    info.view = v;
    info.viewContainer = fl;
    info.data = data;
    info.isSelectable = isSelectable;
    mFooterViewInfos.add(info);

    // in the case of re-adding a header view, or adding one later on,
    // we need to notify the observer
    if (adapter != null) {
        ((FooterViewGridAdapter) adapter).notifyDataSetChanged();

    }
}

/**
 * Add a fixed view to appear at the bottom of the grid. If addFooterView is
 * called more than once, the views will appear in the order they were
 * added. Views added using this call can take focus if they want.
 * <p>
 * NOTE: Call this before calling setAdapter. This is so HeaderFooterGridView can wrap
 * the supplied cursor with one that will also account for header views.
 *
 * @param v The view to add.
 */
public void addFooterView(View v) {
    addFooterView(v, null, false);
}

private void removeFixedViewInfo(View v, ArrayList<FixedViewInfo> where) {
    int len = where.size();
    for (int i = 0; i < len; ++i) {
        FixedViewInfo info = where.get(i);
        if (info.view == v) {
            where.remove(i);
            break;
        }
    }
}

@Override
public void setAdapter(ListAdapter adapter) {
    if (mHeaderViewInfos.size() > 0 || mFooterViewInfos.size() > 0) {
        FooterViewGridAdapter hadapter = new FooterViewGridAdapter(mFooterViewInfos, adapter);
        int numColumns = getNumColumns();
        if (numColumns > 1) {
            hadapter.setNumColumns(numColumns);
        }
        super.setAdapter(hadapter);
    } else {
        super.setAdapter(adapter);
    }
}

private class FullWidthFixedViewLayout extends FrameLayout {
    public FullWidthFixedViewLayout(Context context) {
        super(context);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int targetWidth = TestFooterGridView.this.getMeasuredWidth()
                - TestFooterGridView.this.getPaddingLeft()
                - TestFooterGridView.this.getPaddingRight();
        widthMeasureSpec = MeasureSpec.makeMeasureSpec(targetWidth,
                MeasureSpec.getMode(widthMeasureSpec));
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }
}

@Override
public void setNumColumns(int numColumns) {
    super.setNumColumns(numColumns);
    // Store specified value for less than Honeycomb.
    mRequestedNumColumns = numColumns;
}

@Override
@SuppressLint("NewApi")
public int getNumColumns() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
        return super.getNumColumns();
    }

    // Return value for less than Honeycomb.
    return mNumColmuns;
}

/**
 * ListAdapter used when a HeaderFooterGridView has header views. This ListAdapter
 * wraps another one and also keeps track of the header views and their
 * associated data objects.
 * <p>This is intended as a base class; you will probably not need to
 * use this class directly in your own code.
 */
private static class FooterViewGridAdapter implements WrapperListAdapter, Filterable {

    // This is used to notify the container of updates relating to number of columns
    // or headers changing, which changes the number of placeholders needed
    private final DataSetObservable mDataSetObservable = new DataSetObservable();

    private final ListAdapter mAdapter;
    private int mNumColumns = 1;

    // This ArrayList is assumed to NOT be null.


    ArrayList<FixedViewInfo> mFooterViewInfos;

    boolean mAreAllFixedViewsSelectable;

    private final boolean mIsFilterable;

    public FooterViewGridAdapter(ArrayList<FixedViewInfo> footerViewInfos, ListAdapter adapter) {
        mAdapter = adapter;
        mIsFilterable = adapter instanceof Filterable;

        if (footerViewInfos == null) {
            throw new IllegalArgumentException("footerViewInfos cannot be null");
        }
        mFooterViewInfos = footerViewInfos;

        mAreAllFixedViewsSelectable = areAllListInfosSelectable(mFooterViewInfos);
    }

    public int getHeadersCount() {
        return 0;
    }

    public int getFootersCount() {
        return mFooterViewInfos.size();
    }

    @Override
    public boolean isEmpty() {
        return (mAdapter == null || mAdapter.isEmpty()) && getHeadersCount() == 0 && getFootersCount() == 0;
    }

    public void setNumColumns(int numColumns) {
        if (numColumns < 1) {
            throw new IllegalArgumentException("Number of columns must be 1 or more");
        }
        if (mNumColumns != numColumns) {
            mNumColumns = numColumns;
            notifyDataSetChanged();
        }
    }

    private boolean areAllListInfosSelectable(ArrayList<FixedViewInfo> infos) {
        if (infos != null) {
            for (FixedViewInfo info : infos) {
                if (!info.isSelectable) {
                    return false;
                }
            }
        }
        return true;
    }


    public boolean removeFooter(View v) {
        for (int i = 0; i < mFooterViewInfos.size(); i++) {
            FixedViewInfo info = mFooterViewInfos.get(i);
            if (info.view == v) {
                mFooterViewInfos.remove(i);

                mAreAllFixedViewsSelectable = areAllListInfosSelectable(mFooterViewInfos);

                mDataSetObservable.notifyChanged();
                return true;
            }
        }

        return false;
    }

    @Override
    public int getCount() {
        if (mAdapter != null) {
            final int lastRowItemCount = (mAdapter.getCount() % mNumColumns);
            final int emptyItemCount = ((lastRowItemCount == 0) ? 0 : mNumColumns - lastRowItemCount);
            return (getHeadersCount() * mNumColumns) + mAdapter.getCount() + emptyItemCount + (getFootersCount() * mNumColumns);
        } else {
            return (getHeadersCount() * mNumColumns) + (getFootersCount() * mNumColumns);
        }
    }

    @Override
    public boolean areAllItemsEnabled() {
        if (mAdapter != null) {
            return mAreAllFixedViewsSelectable && mAdapter.areAllItemsEnabled();
        } else {
            return true;
        }
    }

    @Override
    public boolean isEnabled(int position) {
        // Header (negative positions will throw an ArrayIndexOutOfBoundsException)
        int numHeadersAndPlaceholders = getHeadersCount() * mNumColumns;
        if (position < numHeadersAndPlaceholders) {

            return (position % mNumColumns == 0);
                   // && mHeaderViewInfos.get(position / mNumColumns).isSelectable;
        }

        // Adapter
        if (position < numHeadersAndPlaceholders + mAdapter.getCount()) {


            final int adjPosition = position - numHeadersAndPlaceholders;
            int adapterCount = 0;
            if (mAdapter != null) {
                adapterCount = mAdapter.getCount();
                if (adjPosition < adapterCount) {
                     return mAdapter.isEnabled(adjPosition);
                }
            }
        }

        // Empty item
        final int lastRowItemCount = (mAdapter.getCount() % mNumColumns);
        final int emptyItemCount = ((lastRowItemCount == 0) ? 0 : mNumColumns - lastRowItemCount);
        if (position < numHeadersAndPlaceholders + mAdapter.getCount() + emptyItemCount) {

           // return false;
            return (position % mNumColumns == 0)
                    && mFooterViewInfos.get((position - numHeadersAndPlaceholders - mAdapter.getCount() - emptyItemCount) / mNumColumns).isSelectable;
        }

        // Footer
        int numFootersAndPlaceholders = getFootersCount() * mNumColumns;
        if (position < numHeadersAndPlaceholders + mAdapter.getCount() + emptyItemCount + numFootersAndPlaceholders) {

            return (position % mNumColumns == 0)
                    && mFooterViewInfos.get((position - numHeadersAndPlaceholders - mAdapter.getCount() - emptyItemCount) / mNumColumns).isSelectable;
        }

        throw new ArrayIndexOutOfBoundsException(position);
    }

    @Override
    public Object getItem(int position) {
        // Header (negative positions will throw an ArrayIndexOutOfBoundsException)
        int numHeadersAndPlaceholders = getHeadersCount() * mNumColumns;
        if (position < numHeadersAndPlaceholders) {


            if (position % mNumColumns == 0) {

                return 0; //mHeaderViewInfos.get(position / mNumColumns).data;
            }
            return null;
        }

        // Adapter
        if (position < numHeadersAndPlaceholders + mAdapter.getCount()) {


            final int adjPosition = position - numHeadersAndPlaceholders;
            int adapterCount = 0;
            if (mAdapter != null) {
                adapterCount = mAdapter.getCount();
                if (adjPosition < adapterCount) {


                    return mAdapter.getItem(adjPosition);
                }
            }
        }

        // Empty item
        final int lastRowItemCount = (mAdapter.getCount() % mNumColumns);
        Log.e(TAG, "Lastrowitemcount:" + lastRowItemCount);
        final int emptyItemCount = ((lastRowItemCount == 0) ? 0 : mNumColumns - lastRowItemCount);
        Log.e(TAG, "emptyitemcount:" + emptyItemCount);
        if (position < numHeadersAndPlaceholders + mAdapter.getCount() + emptyItemCount) {

            /*return null;*/
            return mFooterViewInfos.get((position - numHeadersAndPlaceholders - mAdapter.getCount() - emptyItemCount) / mNumColumns).data;
        }

        // Footer
        int numFootersAndPlaceholders = getFootersCount() * mNumColumns;
        if (position < numHeadersAndPlaceholders + mAdapter.getCount() + emptyItemCount + numFootersAndPlaceholders) {


            if (position % mNumColumns == 0) {


                return mFooterViewInfos.get((position - numHeadersAndPlaceholders - mAdapter.getCount() - emptyItemCount) / mNumColumns).data;
            }
        }

        throw new ArrayIndexOutOfBoundsException(position);
    }

    @Override
    public long getItemId(int position) {
        int numHeadersAndPlaceholders = getHeadersCount() * mNumColumns;
        if (mAdapter != null) {
            if (position >= numHeadersAndPlaceholders && position < numHeadersAndPlaceholders + mAdapter.getCount()) {

                int adjPosition = position - numHeadersAndPlaceholders;
                int adapterCount = mAdapter.getCount();
                if (adjPosition < adapterCount) {

                    return mAdapter.getItemId(adjPosition);
                }
            }
        }
        return -1;
    }
    @Override
    public boolean hasStableIds() {
        if (mAdapter != null) {
            return mAdapter.hasStableIds();
        }
        return false;
    }
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        // Header (negative positions will throw an ArrayIndexOutOfBoundsException)
        int numHeadersAndPlaceholders = getHeadersCount() * mNumColumns;
        if (position < numHeadersAndPlaceholders) {
            /*View headerViewContainer = mHeaderViewInfos
                    .get(position / mNumColumns).viewContainer;*/
            if (position % mNumColumns == 0) {

                return null; //headerViewContainer;
            } else {

                convertView = new View(parent.getContext());
                // We need to do this because GridView uses the height of the last item
                // in a row to determine the height for the entire row.
                convertView.setVisibility(View.INVISIBLE);
             //   convertView.setMinimumHeight(headerViewContainer.getHeight());
                return convertView;
            }
        }
        // Adapter
      //  TODO Current implementation may not be enough in the case of 3 or more column. May need to be careful on the INVISIBLE View height.
        if (position < numHeadersAndPlaceholders + mAdapter.getCount()) {

            final int adjPosition = position - numHeadersAndPlaceholders;
            int adapterCount = 0;
            if (mAdapter != null) {
                adapterCount = mAdapter.getCount();
                if (adjPosition < adapterCount) {

                    convertView = mAdapter.getView(adjPosition, convertView, parent);
                    convertView.setVisibility(View.VISIBLE);
                    return convertView;
                }
            }
        }
        // Empty item
        final int lastRowItemCount = (mAdapter.getCount() % mNumColumns);
        Log.e(TAG, "Lastrowitemcount:" + lastRowItemCount);
        final int emptyItemCount = ((lastRowItemCount == 0) ? 0 : mNumColumns - lastRowItemCount);
        Log.e(TAG, "Emptyitemcount:" + emptyItemCount);
        if (position < numHeadersAndPlaceholders + mAdapter.getCount() + emptyItemCount) {

            // We need to do this because GridView uses the height of the last item
            // in a row to determine the height for the entire row.
            // TODO Current implementation may not be enough in the case of 3 or more column. May need to be careful on the INVISIBLE View height.
            convertView = mAdapter.getView(mAdapter.getCount() - 1, convertView, parent);
            convertView.setVisibility(View.INVISIBLE);
            return convertView;
        }
        // Footer
        int numFootersAndPlaceholders = getFootersCount() * mNumColumns;
        if (position < numHeadersAndPlaceholders + mAdapter.getCount()  + emptyItemCount + numFootersAndPlaceholders) {


            View footerViewContainer = mFooterViewInfos
                    .get((position - numHeadersAndPlaceholders - mAdapter.getCount() - emptyItemCount) / mNumColumns).viewContainer;
            if (position % mNumColumns == 0) {

                return footerViewContainer;
            } else {

                convertView = new View(parent.getContext());
                // We need to do this because GridView uses the height of the last item
                // in a row to determine the height for the entire row.
                convertView.setVisibility(View.INVISIBLE);
                convertView.setMinimumHeight(footerViewContainer.getHeight());
                return convertView;
            }
        }
        throw new ArrayIndexOutOfBoundsException(position);
    }
    @Override
    public int getItemViewType(int position) {
        int numHeadersAndPlaceholders = getHeadersCount() * mNumColumns;
        if (position < numHeadersAndPlaceholders && (position % mNumColumns != 0)) {

            // Placeholders get the last view type number
            return mAdapter != null ? mAdapter.getViewTypeCount() : 1;
        }
        if (mAdapter != null && position >= numHeadersAndPlaceholders && position < numHeadersAndPlaceholders + mAdapter.getCount() + (mNumColumns - (mAdapter.getCount() % mNumColumns))) {
            int adjPosition = position - numHeadersAndPlaceholders;
            int adapterCount = mAdapter.getCount();
            if (adjPosition < adapterCount) {
                return mAdapter.getItemViewType(adjPosition);
            } else if (adapterCount != 0 && mNumColumns != 1) {
                return mAdapter.getItemViewType(adapterCount - 1);
            }
        }
        int numFootersAndPlaceholders = getFootersCount() * mNumColumns;
        if (mAdapter != null && position < numHeadersAndPlaceholders + mAdapter.getCount() + numFootersAndPlaceholders) {

            return mAdapter != null ? mAdapter.getViewTypeCount() : 1;
        }
        return AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER;
    }
    @Override
    public int getViewTypeCount() {
        if (mAdapter != null) {
            return mAdapter.getViewTypeCount() + 1;
        }
        return 2;
    }
    @Override
    public void registerDataSetObserver(DataSetObserver observer) {
        mDataSetObservable.registerObserver(observer);
        if (mAdapter != null) {
            mAdapter.registerDataSetObserver(observer);
        }
    }
    @Override
    public void unregisterDataSetObserver(DataSetObserver observer) {
        mDataSetObservable.unregisterObserver(observer);
        if (mAdapter != null) {
            mAdapter.unregisterDataSetObserver(observer);
        }
    }
    @Override
    public Filter getFilter() {
        if (mIsFilterable) {
            return ((Filterable) mAdapter).getFilter();
        }
        return null;
    }
    @Override
    public ListAdapter getWrappedAdapter() {
        return mAdapter;
    }
    public void notifyDataSetChanged() {
        mDataSetObservable.notifyChanged();
    }
}

} }

I tried understanding his code by removing any code relating to headers and only looking at what he does with footers. 我试图通过删除任何与页眉有关的代码来理解他的代码,而只看他对页脚的处理方式。

In short: How do I add a footer to a three column gridview? 简而言之:如何在三列gridview中添加页脚? What do I need? 我需要什么?

You don't need any libraries for that. 您不需要任何库。 Just try this .... 只是尝试这个....

Create Layout like this..... 创建这样的Layout .....

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <android.support.v4.widget.NestedScrollView
        android:id="@+id/nestedScrollView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:overScrollMode="never">


        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            <TextView
                android:id="@+id/header"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:padding="20dp"
                android:text="Header"
                android:textColor="@color/white"
                android:textSize="16sp" />


            <android.support.v7.widget.RecyclerView
                android:id="@+id/recyclerView"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />

            <TextView
                android:id="@+id/footer"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:padding="20dp"
                android:text="Footer"
                android:textColor="@color/white"
                android:textSize="16sp" />

        </LinearLayout>
    </android.support.v4.widget.NestedScrollView>
</LinearLayout>

And Use this code in your Activity or Fragment ... 并在您的ActivityFragment使用此代码...

RecyclerView recyclerView = findViewById(R.id.recyclerView);
ViewCompat.setNestedScrollingEnabled(recyclerView, false);
GridLayoutManager mLayoutManager = new GridLayoutManager(activity, 3);
recyclerView.setLayoutManager(mLayoutManager);
adapter = new YourCustomAdapter(this);
recyclerView.setAdapter(adapter);

Note:- In My point of view don't depend on libraries. 注意:-在我看来,不依赖于库。 If they will remove it in future then you have to change your work again. 如果他们将来会删除它,那么您必须再次更改您的工作。 If you want to use library try to import their GitHub whole module in your project. 如果要使用库,请尝试在项目中导入其GitHub整个模块。 So you don't depend on their changes. 因此,您不必依赖于它们的更改。 There is an incident with me, where i used image compression library in my app. 我发生了一件事情,我在应用中使用了图像压缩库。 After one year they removed their library and i had to work again on that module. 一年后,他们删除了他们的图书馆,我不得不在那个模块上再次工作。 And if your are using some famous company libraries then it is fine like Facebook , Google , Square or more. 而且,如果您使用的是一些著名的公司图书馆,那也很好,例如FacebookGoogleSquare或更多。 Many big company also depend on their Library. 许多大公司也依靠他们的图书馆。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM