带header的GridView(HeaderGridView)

来源:互联网 发布:云镜安卓限制安装软件 编辑:程序博客网 时间:2024/05/01 04:43
扣自goolge android.photos

/* * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *      http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package com.android.photos.views;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();        }    }}


用法:
mHeaderView = LayoutInflater.from(getActivity())        .inflate(R.layout.album_header, getGridView(), false);((HeaderGridView) getGridView()).addHeaderView(mHeaderView, null, false);
0 0
原创粉丝点击