|
@@ -1,813 +0,0 @@
|
|
|
-
|
|
|
-/*
|
|
|
- * 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 third_parties.in.srain.cube;
|
|
|
-
|
|
|
-
|
|
|
-import android.annotation.TargetApi;
|
|
|
-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.lang.reflect.Field;
|
|
|
-import java.util.ArrayList;
|
|
|
-
|
|
|
-/**
|
|
|
- * A {@link android.widget.GridView} that supports adding header rows in a
|
|
|
- * very similar way to {@link android.widget.ListView}.
|
|
|
- * See {@link GridViewWithHeaderAndFooter#addHeaderView(View, Object, boolean)}
|
|
|
- * See {@link GridViewWithHeaderAndFooter#addFooterView(View, Object, boolean)}
|
|
|
- */
|
|
|
-public class GridViewWithHeaderAndFooter extends GridView {
|
|
|
-
|
|
|
- public static final boolean DEBUG = false;
|
|
|
-
|
|
|
- private int mNumColumns = AUTO_FIT;
|
|
|
- private View mViewForMeasureRowHeight = null;
|
|
|
- private int mRowHeight = -1;
|
|
|
- private static final String LOG_TAG = "GridViewWHeaderNFooter";
|
|
|
-
|
|
|
- private ArrayList<FixedViewInfo> mHeaderViewInfos = new ArrayList<>();
|
|
|
- private ArrayList<FixedViewInfo> mFooterViewInfos = new ArrayList<>();
|
|
|
-
|
|
|
- /**
|
|
|
- * 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 android.widget.ListAdapter#getItem(int)}.
|
|
|
- */
|
|
|
- public Object data;
|
|
|
- /**
|
|
|
- * <code>true</code> if the fixed view should be selectable in the grid
|
|
|
- */
|
|
|
- public boolean isSelectable;
|
|
|
- }
|
|
|
-
|
|
|
- private void initHeaderGridView() {
|
|
|
- }
|
|
|
-
|
|
|
- public GridViewWithHeaderAndFooter(Context context) {
|
|
|
- super(context);
|
|
|
- initHeaderGridView();
|
|
|
- }
|
|
|
-
|
|
|
- public GridViewWithHeaderAndFooter(Context context, AttributeSet attrs) {
|
|
|
- super(context, attrs);
|
|
|
- initHeaderGridView();
|
|
|
- }
|
|
|
-
|
|
|
- public GridViewWithHeaderAndFooter(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 instanceof HeaderViewGridAdapter) {
|
|
|
- ((HeaderViewGridAdapter) adapter).setNumColumns(super.getNumColumns());
|
|
|
- invalidateRowHeight();
|
|
|
- ((HeaderViewGridAdapter) adapter).setRowHeight(getRowHeight());
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public void setClipChildren(boolean clipChildren) {
|
|
|
- // Ignore, since the header rows depend on not being clipped
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Do not call this method unless you know how it works.
|
|
|
- *
|
|
|
- * @param clipChildren
|
|
|
- */
|
|
|
- public void setClipChildrenSupper(boolean clipChildren) {
|
|
|
- super.setClipChildren(false);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 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);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 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.");
|
|
|
- }
|
|
|
-
|
|
|
- ViewGroup.LayoutParams lyp = v.getLayoutParams();
|
|
|
-
|
|
|
- FixedViewInfo info = new FixedViewInfo();
|
|
|
- FrameLayout fl = new FullWidthFixedViewLayout(getContext());
|
|
|
-
|
|
|
- if (lyp != null) {
|
|
|
- v.setLayoutParams(new FrameLayout.LayoutParams(lyp.width, lyp.height));
|
|
|
- fl.setLayoutParams(new LayoutParams(lyp.width, lyp.height));
|
|
|
- }
|
|
|
- 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();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- public void addFooterView(View v) {
|
|
|
- addFooterView(v, null, true);
|
|
|
- }
|
|
|
-
|
|
|
- public void addFooterView(View v, Object data, boolean isSelectable) {
|
|
|
- ListAdapter mAdapter = getAdapter();
|
|
|
- if (mAdapter != null && !(mAdapter instanceof HeaderViewGridAdapter)) {
|
|
|
- throw new IllegalStateException(
|
|
|
- "Cannot add header view to grid -- setAdapter has already been called.");
|
|
|
- }
|
|
|
-
|
|
|
- ViewGroup.LayoutParams lyp = v.getLayoutParams();
|
|
|
-
|
|
|
- FixedViewInfo info = new FixedViewInfo();
|
|
|
- FrameLayout fl = new FullWidthFixedViewLayout(getContext());
|
|
|
-
|
|
|
- if (lyp != null) {
|
|
|
- v.setLayoutParams(new FrameLayout.LayoutParams(lyp.width, lyp.height));
|
|
|
- fl.setLayoutParams(new LayoutParams(lyp.width, lyp.height));
|
|
|
- }
|
|
|
- fl.addView(v);
|
|
|
- info.view = v;
|
|
|
- info.viewContainer = fl;
|
|
|
- info.data = data;
|
|
|
- info.isSelectable = isSelectable;
|
|
|
- mFooterViewInfos.add(info);
|
|
|
-
|
|
|
- if (mAdapter != null) {
|
|
|
- ((HeaderViewGridAdapter) mAdapter).notifyDataSetChanged();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- public int getHeaderViewCount() {
|
|
|
- return mHeaderViewInfos.size();
|
|
|
- }
|
|
|
-
|
|
|
- public int getFooterViewCount() {
|
|
|
- return mFooterViewInfos.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;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Removes a previously-added footer 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 removeFooterView(View v) {
|
|
|
- if (mFooterViewInfos.size() > 0) {
|
|
|
- boolean result = false;
|
|
|
- ListAdapter adapter = getAdapter();
|
|
|
- if (adapter != null && ((HeaderViewGridAdapter) adapter).removeFooter(v)) {
|
|
|
- result = true;
|
|
|
- }
|
|
|
- removeFixedViewInfo(v, mFooterViewInfos);
|
|
|
- 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;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- @TargetApi(16)
|
|
|
- private int getColumnWidthCompatible() {
|
|
|
- if (Build.VERSION.SDK_INT >= 16) {
|
|
|
- return super.getColumnWidth();
|
|
|
- } else {
|
|
|
- try {
|
|
|
- Field numColumns = getClass().getSuperclass().getDeclaredField("mColumnWidth");
|
|
|
- numColumns.setAccessible(true);
|
|
|
- return numColumns.getInt(this);
|
|
|
- } catch (NoSuchFieldException e) {
|
|
|
- throw new RuntimeException(e);
|
|
|
- } catch (IllegalAccessException e) {
|
|
|
- throw new RuntimeException(e);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- protected void onDetachedFromWindow() {
|
|
|
- super.onDetachedFromWindow();
|
|
|
- mViewForMeasureRowHeight = null;
|
|
|
- }
|
|
|
-
|
|
|
- public void invalidateRowHeight() {
|
|
|
- mRowHeight = -1;
|
|
|
- }
|
|
|
-
|
|
|
- public int getRowHeight() {
|
|
|
- if (mRowHeight > 0) {
|
|
|
- return mRowHeight;
|
|
|
- }
|
|
|
- ListAdapter adapter = getAdapter();
|
|
|
- int numColumns = super.getNumColumns();
|
|
|
-
|
|
|
- // adapter has not been set or has no views in it;
|
|
|
- if (adapter == null || adapter.getCount() <= numColumns * (mHeaderViewInfos.size() + mFooterViewInfos.size())) {
|
|
|
- return -1;
|
|
|
- }
|
|
|
- int mColumnWidth = getColumnWidthCompatible();
|
|
|
- View view = getAdapter().getView(numColumns * mHeaderViewInfos.size(), mViewForMeasureRowHeight, this);
|
|
|
- LayoutParams p = (LayoutParams) view.getLayoutParams();
|
|
|
- if (p == null) {
|
|
|
- p = new LayoutParams(-1, -2, 0);
|
|
|
- view.setLayoutParams(p);
|
|
|
- }
|
|
|
- int childHeightSpec = getChildMeasureSpec(
|
|
|
- MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), 0, p.height);
|
|
|
- int childWidthSpec = getChildMeasureSpec(
|
|
|
- MeasureSpec.makeMeasureSpec(mColumnWidth, MeasureSpec.EXACTLY), 0, p.width);
|
|
|
- view.measure(childWidthSpec, childHeightSpec);
|
|
|
- mViewForMeasureRowHeight = view;
|
|
|
- mRowHeight = view.getMeasuredHeight();
|
|
|
- return mRowHeight;
|
|
|
- }
|
|
|
-
|
|
|
- public void tryToScrollToBottomSmoothly() {
|
|
|
- int lastPos = getAdapter().getCount() - 1;
|
|
|
- smoothScrollToPositionFromTop(lastPos, 0);
|
|
|
- }
|
|
|
-
|
|
|
- public void tryToScrollToBottomSmoothly(int duration) {
|
|
|
- int lastPos = getAdapter().getCount() - 1;
|
|
|
- smoothScrollToPositionFromTop(lastPos, 0, duration);
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public void setAdapter(ListAdapter adapter) {
|
|
|
- if (mHeaderViewInfos.size() > 0 || mFooterViewInfos.size() > 0) {
|
|
|
- HeaderViewGridAdapter headerViewGridAdapter = new HeaderViewGridAdapter(mHeaderViewInfos, mFooterViewInfos, adapter);
|
|
|
- int numColumns = super.getNumColumns();
|
|
|
- if (numColumns > 1) {
|
|
|
- headerViewGridAdapter.setNumColumns(numColumns);
|
|
|
- }
|
|
|
- headerViewGridAdapter.setRowHeight(getRowHeight());
|
|
|
- super.setAdapter(headerViewGridAdapter);
|
|
|
- } else {
|
|
|
- super.setAdapter(adapter);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * full width
|
|
|
- */
|
|
|
- private class FullWidthFixedViewLayout extends FrameLayout {
|
|
|
-
|
|
|
- public FullWidthFixedViewLayout(Context context) {
|
|
|
- super(context);
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
|
|
- int realLeft = GridViewWithHeaderAndFooter.this.getPaddingLeft() + getPaddingLeft();
|
|
|
- // Try to make where it should be, from left, full width
|
|
|
- if (realLeft != left) {
|
|
|
- offsetLeftAndRight(realLeft - left);
|
|
|
- }
|
|
|
- super.onLayout(changed, left, top, right, bottom);
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
|
|
- int targetWidth = GridViewWithHeaderAndFooter.this.getMeasuredWidth()
|
|
|
- - GridViewWithHeaderAndFooter.this.getPaddingLeft()
|
|
|
- - GridViewWithHeaderAndFooter.this.getPaddingRight();
|
|
|
- widthMeasureSpec = MeasureSpec.makeMeasureSpec(targetWidth,
|
|
|
- MeasureSpec.getMode(widthMeasureSpec));
|
|
|
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public void setNumColumns(int numColumns) {
|
|
|
- super.setNumColumns(numColumns);
|
|
|
- mNumColumns = numColumns;
|
|
|
- ListAdapter adapter = getAdapter();
|
|
|
- if (adapter instanceof HeaderViewGridAdapter) {
|
|
|
- ((HeaderViewGridAdapter) adapter).setNumColumns(numColumns);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- public boolean isCorrectAdapter(){
|
|
|
- return getAdapter() == null || getAdapter() instanceof HeaderViewGridAdapter;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 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;
|
|
|
- static final ArrayList<FixedViewInfo> EMPTY_INFO_LIST =
|
|
|
- new ArrayList<FixedViewInfo>();
|
|
|
-
|
|
|
- // This ArrayList is assumed to NOT be null.
|
|
|
- ArrayList<FixedViewInfo> mHeaderViewInfos;
|
|
|
- ArrayList<FixedViewInfo> mFooterViewInfos;
|
|
|
- private int mNumColumns = 1;
|
|
|
- private int mRowHeight = -1;
|
|
|
- boolean mAreAllFixedViewsSelectable;
|
|
|
- private final boolean mIsFilterable;
|
|
|
- private boolean mCachePlaceHoldView = true;
|
|
|
- // From Recycle Bin or calling getView, this a question...
|
|
|
- private boolean mCacheFirstHeaderView = false;
|
|
|
-
|
|
|
- public HeaderViewGridAdapter(ArrayList<FixedViewInfo> headerViewInfos, ArrayList<FixedViewInfo> footViewInfos, ListAdapter adapter) {
|
|
|
- mAdapter = adapter;
|
|
|
- mIsFilterable = adapter instanceof Filterable;
|
|
|
- if (headerViewInfos == null) {
|
|
|
- mHeaderViewInfos = EMPTY_INFO_LIST;
|
|
|
- } else {
|
|
|
- mHeaderViewInfos = headerViewInfos;
|
|
|
- }
|
|
|
-
|
|
|
- if (footViewInfos == null) {
|
|
|
- mFooterViewInfos = EMPTY_INFO_LIST;
|
|
|
- } else {
|
|
|
- mFooterViewInfos = footViewInfos;
|
|
|
- }
|
|
|
- mAreAllFixedViewsSelectable = areAllListInfosSelectable(mHeaderViewInfos)
|
|
|
- && areAllListInfosSelectable(mFooterViewInfos);
|
|
|
- }
|
|
|
-
|
|
|
- public void setNumColumns(int numColumns) {
|
|
|
- if (numColumns < 1) {
|
|
|
- return;
|
|
|
- }
|
|
|
- if (mNumColumns != numColumns) {
|
|
|
- mNumColumns = numColumns;
|
|
|
- notifyDataSetChanged();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- public void setRowHeight(int height) {
|
|
|
- mRowHeight = height;
|
|
|
- }
|
|
|
-
|
|
|
- public int getHeadersCount() {
|
|
|
- return mHeaderViewInfos.size();
|
|
|
- }
|
|
|
-
|
|
|
- public int getFootersCount() {
|
|
|
- return mFooterViewInfos.size();
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public boolean isEmpty() {
|
|
|
- return (mAdapter == null || mAdapter.isEmpty()) && getHeadersCount() == 0 && getFootersCount() == 0;
|
|
|
- }
|
|
|
-
|
|
|
- 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) && areAllListInfosSelectable(mFooterViewInfos);
|
|
|
- mDataSetObservable.notifyChanged();
|
|
|
- return true;
|
|
|
- }
|
|
|
- }
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- 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(mHeaderViewInfos) && areAllListInfosSelectable(mFooterViewInfos);
|
|
|
- mDataSetObservable.notifyChanged();
|
|
|
- return true;
|
|
|
- }
|
|
|
- }
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public int getCount() {
|
|
|
- if (mAdapter != null) {
|
|
|
- return (getFootersCount() + getHeadersCount()) * mNumColumns + getAdapterAndPlaceHolderCount();
|
|
|
- } else {
|
|
|
- return (getFootersCount() + getHeadersCount()) * mNumColumns;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public boolean areAllItemsEnabled() {
|
|
|
- if (mAdapter != null) {
|
|
|
- return mAreAllFixedViewsSelectable && mAdapter.areAllItemsEnabled();
|
|
|
- } else {
|
|
|
- return true;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private int getAdapterAndPlaceHolderCount() {
|
|
|
- return (int) (Math.ceil(1f * mAdapter.getCount() / mNumColumns) * mNumColumns);
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public boolean isEnabled(int position) {
|
|
|
- // Header (negative positions will throw an IndexOutOfBoundsException)
|
|
|
- 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 = getAdapterAndPlaceHolderCount();
|
|
|
- if (adjPosition < adapterCount) {
|
|
|
- return adjPosition < mAdapter.getCount() && mAdapter.isEnabled(adjPosition);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // Footer (off-limits positions will throw an IndexOutOfBoundsException)
|
|
|
- final int footerPosition = adjPosition - adapterCount;
|
|
|
- return footerPosition % mNumColumns == 0
|
|
|
- && mFooterViewInfos.get(footerPosition / mNumColumns).isSelectable;
|
|
|
- }
|
|
|
-
|
|
|
- @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 = getAdapterAndPlaceHolderCount();
|
|
|
- if (adjPosition < adapterCount) {
|
|
|
- if (adjPosition < mAdapter.getCount()) {
|
|
|
- return mAdapter.getItem(adjPosition);
|
|
|
- } else {
|
|
|
- return null;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // Footer (off-limits positions will throw an IndexOutOfBoundsException)
|
|
|
- final int footerPosition = adjPosition - adapterCount;
|
|
|
- if (footerPosition % mNumColumns == 0) {
|
|
|
- return mFooterViewInfos.get(footerPosition).data;
|
|
|
- } else {
|
|
|
- return null;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- @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) {
|
|
|
- if (DEBUG) {
|
|
|
- Log.d(LOG_TAG, String.format("getView: %s, reused: %s", position, convertView == null));
|
|
|
- }
|
|
|
- // 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 = getAdapterAndPlaceHolderCount();
|
|
|
- if (adjPosition < adapterCount) {
|
|
|
- if (adjPosition < mAdapter.getCount()) {
|
|
|
- return mAdapter.getView(adjPosition, convertView, parent);
|
|
|
- } else {
|
|
|
- if (convertView == null) {
|
|
|
- convertView = new View(parent.getContext());
|
|
|
- }
|
|
|
- convertView.setVisibility(View.INVISIBLE);
|
|
|
- convertView.setMinimumHeight(mRowHeight);
|
|
|
- return convertView;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- // Footer
|
|
|
- final int footerPosition = adjPosition - adapterCount;
|
|
|
- if (footerPosition < getCount()) {
|
|
|
- View footViewContainer = mFooterViewInfos
|
|
|
- .get(footerPosition / mNumColumns).viewContainer;
|
|
|
- if (position % mNumColumns == 0) {
|
|
|
- return footViewContainer;
|
|
|
- } 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(footViewContainer.getHeight());
|
|
|
- return convertView;
|
|
|
- }
|
|
|
- }
|
|
|
- throw new ArrayIndexOutOfBoundsException(position);
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public int getItemViewType(int position) {
|
|
|
-
|
|
|
- final int numHeadersAndPlaceholders = getHeadersCount() * mNumColumns;
|
|
|
- final int adapterViewTypeStart = mAdapter == null ? 0 : mAdapter.getViewTypeCount() - 1;
|
|
|
- int type = AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER;
|
|
|
- if (mCachePlaceHoldView
|
|
|
- && position < numHeadersAndPlaceholders) {
|
|
|
- // Header
|
|
|
- if (position == 0 && mCacheFirstHeaderView) {
|
|
|
- type = adapterViewTypeStart + mHeaderViewInfos.size() + mFooterViewInfos.size() + 1 + 1;
|
|
|
- }
|
|
|
- if (position % mNumColumns != 0) {
|
|
|
- type = adapterViewTypeStart + (position / mNumColumns + 1);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // Adapter
|
|
|
- final int adjPosition = position - numHeadersAndPlaceholders;
|
|
|
- int adapterCount = 0;
|
|
|
- if (mAdapter != null) {
|
|
|
- adapterCount = getAdapterAndPlaceHolderCount();
|
|
|
- if (adjPosition >= 0 && adjPosition < adapterCount) {
|
|
|
- if (adjPosition < mAdapter.getCount()) {
|
|
|
- type = mAdapter.getItemViewType(adjPosition);
|
|
|
- } else {
|
|
|
- if (mCachePlaceHoldView) {
|
|
|
- type = adapterViewTypeStart + mHeaderViewInfos.size() + 1;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (mCachePlaceHoldView) {
|
|
|
- // Footer
|
|
|
- final int footerPosition = adjPosition - adapterCount;
|
|
|
- if (footerPosition >= 0 && footerPosition < getCount() && (footerPosition % mNumColumns) != 0) {
|
|
|
- type = adapterViewTypeStart + mHeaderViewInfos.size() + 1 + (footerPosition / mNumColumns + 1);
|
|
|
- }
|
|
|
- }
|
|
|
- if (DEBUG) {
|
|
|
- Log.d(LOG_TAG, String.format("getItemViewType: pos: %s, result: %s", position, type, mCachePlaceHoldView, mCacheFirstHeaderView));
|
|
|
- }
|
|
|
- return type;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * content view, content view holder, header[0], header and footer placeholder(s)
|
|
|
- *
|
|
|
- * @return
|
|
|
- */
|
|
|
- @Override
|
|
|
- public int getViewTypeCount() {
|
|
|
- int count = mAdapter == null ? 1 : mAdapter.getViewTypeCount();
|
|
|
- if (mCachePlaceHoldView) {
|
|
|
- int offset = mHeaderViewInfos.size() + 1 + mFooterViewInfos.size();
|
|
|
- if (mCacheFirstHeaderView) {
|
|
|
- offset += 1;
|
|
|
- }
|
|
|
- count += offset;
|
|
|
- }
|
|
|
- if (DEBUG) {
|
|
|
- Log.d(LOG_TAG, String.format("getViewTypeCount: %s", count));
|
|
|
- }
|
|
|
- return count;
|
|
|
- }
|
|
|
-
|
|
|
- @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();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- /**
|
|
|
- * Sets the selected item and positions the selection y pixels from the top edge of the ListView.
|
|
|
- * (If in touch mode, the item will not be selected but it will still be positioned appropriately.)
|
|
|
- *
|
|
|
- * @param position Index (starting at 0) of the data item to be selected.
|
|
|
- * @param y The distance from the top edge of the ListView (plus padding)
|
|
|
- * that the item will be positioned.
|
|
|
- *
|
|
|
- * @see <a href="http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.4_r1/android/widget/ListView.java#ListView.setSelectionFromTop%28int%2Cint%29">Original code</a>
|
|
|
- */
|
|
|
- public void setSelectionFromTop(int position, int y) {
|
|
|
- if (getAdapter() == null) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- setSelection(position);
|
|
|
- //setSelectionInt(position);
|
|
|
-
|
|
|
- /*if (!isInTouchMode()) {
|
|
|
- position = super.lookForSelectablePosition(position, true);
|
|
|
- if (position >= 0) {
|
|
|
- setNextSelectedPositionInt(position);
|
|
|
- }
|
|
|
- } else {
|
|
|
- mResurrectToPosition = position;
|
|
|
- }*/
|
|
|
-
|
|
|
- /*
|
|
|
- if (position >= 0) {
|
|
|
- mLayoutMode = LAYOUT_SPECIFIC;
|
|
|
- mSpecificTop = mListPadding.top + y;
|
|
|
-
|
|
|
- if (mNeedSync) {
|
|
|
- mSyncPosition = position;
|
|
|
- mSyncRowId = getAdapter().getItemId(position);
|
|
|
- }
|
|
|
-
|
|
|
- if (mPositionScroller != null) {
|
|
|
- mPositionScroller.stop();
|
|
|
- }
|
|
|
-
|
|
|
- requestLayout();
|
|
|
- }
|
|
|
- */
|
|
|
- }
|
|
|
-
|
|
|
-}
|