• Android GridView增加HeaderView和FooterView的实现


    Android GridView增加HeaderView和FooterView的实现

    做的项目中遇到一个问题,需要实现一个页面

    页面的上面是一个自定义的View和GridView,当向下滚动屏幕的时候,需要确保两者一起滑动

    之前没遇到过这种情况,直接按照心中的想法实现了,发现遇到问题了

    “GridView只显示一行记录”

    网上搜索之后发现很多人遇到过,也多贴出解决的方法

    大概实现的方法有几种:

    1. 重载GridView的onMeasure()方法
    2. 使用google提供的HeaderGridView类 -- 主要实现的原理是将HeaderView当作其中一个Item来显示,同时也需要考虑高度的不同
    3. 借助开源项目,很多个,比如android-GridViewWithHeaderAndFooter

    我这里使用的是HeaderGridView类,比较简单

    //初始化HeaderView
     LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
     headerView = inflater.inflate(R.layout.activity_page_header, null);
    
     gridView = (HeaderGridView) findViewById(R.id.gridview);
     gridView.addHeaderView(headerView); // 他需要在setAdapter()之前
     gridView.setAdapter(twoAdapter);
    <?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="wrap_content"
        android:background="@color/white"
        android:orientation="vertical">
    
        <com.dudress.dress.detail.HeaderGridView
            android:id="@+id/gridview"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:horizontalSpacing="6dp"
            android:numColumns="2"
            android:background="@color/gray_dc"
            android:verticalSpacing="10dp"></com.dudress.dress.detail.HeaderGridView>
    
    </LinearLayout>

    附上HeaderGridView类的源码,复制回去直接使用

    package com.dudress.dress.detail;
    
    /**
     * Created by zhou on 16-4-6.
     */
    import android.content.Context;
    import android.database.DataSetObservable;
    import android.database.DataSetObserver;
    import android.util.AttributeSet;
    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;
    /**
     * A {@link GridView} that supports adding header rows in a
     * very similar way to {@link ListView}.
     * See {@link HeaderGridView#addHeaderView(View, Object, boolean)}
     */
    public class HeaderGridView extends GridView {
        private static final String TAG = "HeaderGridView";
        /**
         * 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 void initHeaderGridView() {
            super.setClipChildren(false);
        }
        public HeaderGridView(Context context) {
            super(context);
            initHeaderGridView();
        }
        public HeaderGridView(Context context, AttributeSet attrs) {
            super(context, attrs);
            initHeaderGridView();
        }
        public HeaderGridView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
            initHeaderGridView();
        }
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            ListAdapter adapter = getAdapter();
            if (adapter != null && adapter instanceof HeaderViewGridAdapter) {
                ((HeaderViewGridAdapter) 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 HeaderGridView 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 HeaderViewGridAdapter)) {
                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) {
                ((HeaderViewGridAdapter) adapter).notifyDataSetChanged();
            }
        }
        /**
         * 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 HeaderGridView can wrap
         * the supplied cursor with one that will also account for header views.
         *
         * @param v The view to add.
         */
        public void addHeaderView(View v) {
            addHeaderView(v, null, true);
        }
        public int getHeaderViewCount() {
            return mHeaderViewInfos.size();
        }
        /**
         * Removes a previously-added header view.
         *
         * @param v The view to remove
         * @return true if the view was removed, false if the view was not a header
         *         view
         */
        public boolean removeHeaderView(View v) {
            if (mHeaderViewInfos.size() > 0) {
                boolean result = false;
                ListAdapter adapter = getAdapter();
                if (adapter != null && ((HeaderViewGridAdapter) adapter).removeHeader(v)) {
                    result = true;
                }
                removeFixedViewInfo(v, mHeaderViewInfos);
                return result;
            }
            return 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) {
                HeaderViewGridAdapter hadapter = new HeaderViewGridAdapter(mHeaderViewInfos, 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 = HeaderGridView.this.getMeasuredWidth()
                        - HeaderGridView.this.getPaddingLeft()
                        - HeaderGridView.this.getPaddingRight();
                widthMeasureSpec = MeasureSpec.makeMeasureSpec(targetWidth,
                        MeasureSpec.getMode(widthMeasureSpec));
                super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            }
        }
        /**
         * ListAdapter used when a HeaderGridView 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 HeaderViewGridAdapter 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> mHeaderViewInfos;
            boolean mAreAllFixedViewsSelectable;
            private final boolean mIsFilterable;
            public HeaderViewGridAdapter(ArrayList<FixedViewInfo> headerViewInfos, ListAdapter adapter) {
                mAdapter = adapter;
                mIsFilterable = adapter instanceof Filterable;
                if (headerViewInfos == null) {
                    throw new IllegalArgumentException("headerViewInfos cannot be null");
                }
                mHeaderViewInfos = headerViewInfos;
                mAreAllFixedViewsSelectable = areAllListInfosSelectable(mHeaderViewInfos);
            }
            public int getHeadersCount() {
                return mHeaderViewInfos.size();
            }
            @Override
            public boolean isEmpty() {
                return (mAdapter == null || mAdapter.isEmpty()) && getHeadersCount() == 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 removeHeader(View v) {
                for (int i = 0; i < mHeaderViewInfos.size(); i++) {
                    FixedViewInfo info = mHeaderViewInfos.get(i);
                    if (info.view == v) {
                        mHeaderViewInfos.remove(i);
                        mAreAllFixedViewsSelectable = areAllListInfosSelectable(mHeaderViewInfos);
                        mDataSetObservable.notifyChanged();
                        return true;
                    }
                }
                return false;
            }
            @Override
            public int getCount() {
                if (mAdapter != null) {
                    return getHeadersCount() * mNumColumns + mAdapter.getCount();
                } else {
                    return getHeadersCount() * 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
                final int adjPosition = position - numHeadersAndPlaceholders;
                int adapterCount = 0;
                if (mAdapter != null) {
                    adapterCount = mAdapter.getCount();
                    if (adjPosition < adapterCount) {
                        return mAdapter.isEnabled(adjPosition);
                    }
                }
                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 mHeaderViewInfos.get(position / mNumColumns).data;
                    }
                    return null;
                }
                // Adapter
                final int adjPosition = position - numHeadersAndPlaceholders;
                int adapterCount = 0;
                if (mAdapter != null) {
                    adapterCount = mAdapter.getCount();
                    if (adjPosition < adapterCount) {
                        return mAdapter.getItem(adjPosition);
                    }
                }
                throw new ArrayIndexOutOfBoundsException(position);
            }
            @Override
            public long getItemId(int position) {
                int numHeadersAndPlaceholders = getHeadersCount() * mNumColumns;
                if (mAdapter != null && position >= numHeadersAndPlaceholders) {
                    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 headerViewContainer;
                    } else {
                        if (convertView == null) {
                            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
                final int adjPosition = position - numHeadersAndPlaceholders;
                int adapterCount = 0;
                if (mAdapter != null) {
                    adapterCount = mAdapter.getCount();
                    if (adjPosition < adapterCount) {
                        return mAdapter.getView(adjPosition, convertView, parent);
                    }
                }
                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) {
                    int adjPosition = position - numHeadersAndPlaceholders;
                    int adapterCount = mAdapter.getCount();
                    if (adjPosition < adapterCount) {
                        return mAdapter.getItemViewType(adjPosition);
                    }
                }
                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();
            }
        }
    }
  • 相关阅读:
    开启sentry权限控制hue
    hive_server2的权限控制
    自带的simple认证
    tableau备份
    tableau分布式添加节点
    升级tableau版本
    tableau日常管理
    mavn Nexus Repository Manager漏洞
    第3章:打造命令行工具
    基于从库+binlog方式恢复数据
  • 原文地址:https://www.cnblogs.com/zhou-guobao/p/5359690.html
走看看 - 开发者的网上家园