zoukankan      html  css  js  c++  java
  • HeaderGridView

    /*
     * 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();
            }
        }
    }
    

      https://android.googlesource.com/platform/packages/apps/Gallery2/+/idea133/src/com/android/photos/views/HeaderGridView.java

  • 相关阅读:
    网宿科技股份有限公司投资者关系活动记录表(2014.3.30)
    网宿科技投资者关系活动记录2016年10月31日
    [转载]20131206 网宿科技电话交流会纪要
    strlcpy和strlcat
    114 的 dns 的解析测试
    大批量数据读写
    ART——一个轻量级的web报表工具
    递归删除.svn文件
    SA常用命令
    淘女郎团队敏捷开发实践2011上半年回顾
  • 原文地址:https://www.cnblogs.com/pandans/p/4385655.html
Copyright © 2011-2022 走看看