Android - 使用GridView非常奇怪的行为

时间:2014-07-22 14:08:24

标签: android android-arrayadapter android-gridview

我正在为gridView创建一个ArrayAdapter,考虑页眉和页脚视图。

activity_main.xml中:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <GridView
        android:id="@+id/activity_main_gridview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:numColumns="4" />

</RelativeLayout>

问题在于,当我滚动到网格标题/底部视图的顶部或底部时,会覆盖网格项目,当点击任何项目时,它会返回到原始位置(如果需要,我会放置屏幕截图)< / p>

这是我的GridView适配器(按顺序排列:上下文,网格项的arraylist(没有页眉/页脚),所有第一行的页眉视图,所有最后一行的页脚视图,gridview列编号):

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mGridView = (GridView) findViewById(R.id.activity_main_gridview);

    List<String> list = new ArrayList<String>();
    for (int i = 0; i < 500; i++) {
        list.add("item " + i);
    }
    View headerView = new View(this);
    headerView.setMinimumHeight(70);
    headerView.setBackgroundColor(Color.argb(255, 63, 81, 181));

    GridHeaderFooterAdapter adapter =
            new GridHeaderFooterAdapter(this, list, headerView, headerView, 4);
    mGridView.setAdapter(adapter);
}

private final class GridHeaderFooterAdapter extends ArrayAdapter<String> {

    private int mNumColumns;
    private int mListSize;

    private List<String> mList;
    private View mHeaderView;
    private View mFooterView;

    private LayoutInflater mInflater;

    public GridHeaderFooterAdapter(ActivityMain context, List<String> list, View headerView, View footerView, int numColumns) {
        super(context, 0);
        this.mNumColumns = numColumns;
        this.mListSize = list.size();
        this.mList = list;
        this.mHeaderView = headerView;
        this.mFooterView = footerView;

        mInflater = context.getLayoutInflater();
    }

    @Override
    public int getCount() {
        int count = 0;
        //headers
        count += mNumColumns;
        //list items
        count += mListSize;
        //footers
        count += mNumColumns + (mNumColumns - mList.size() % mNumColumns);
        Log.w("ActivityMain", "getCount() = " + count);
        return count;
    }

    @Override
    public String getItem(int position) {
        //discard header items
        return mList.get(position - mNumColumns);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        //headers
        if (position < mNumColumns){
            Log.w("ActivityMain", "headers: position = " + position);
            return mHeaderView;
        }
        //listitems
        if (position >= mNumColumns && position < mNumColumns + mListSize) {
            Log.w("ActivityMain", "listitems: position = " + position);
            LinearLayout ll = (LinearLayout) mInflater.inflate(R.layout.listitem_main, null);
            TextView tv = (TextView) ll.findViewById(R.id.textView);
            tv.setText(getItem(position));
            return ll;
        }
        //footers
        if (position >= mNumColumns + mListSize){
            Log.w("ActivityMain", "footers: position = " + position);
/*TODO: some footers might be in the same row as listitem, which is wrong because Gridview uses last item of the row to determine row height... */
            return mFooterView;
        }

        return null;
    }
}

在滚动之前: enter image description here 滚动后: enter image description here

如您所见,目标是添加标题以避免第一项位于状态栏

之后

1 个答案:

答案 0 :(得分:2)

手动玩位置编号是一件危险的事情,尽管如果做得恰到好处,这很有可能。这里的问题是您试图绕过getView()方法的运作方式。 getView()将保留它自己对返回的视图的引用,并相应地回收或销毁它。它已经进行了大量优化以提供卓越的性能,并且为了实现您的最终目标,您希望使用它...而不是反对。

最终,您希望GridView中第1行(页眉)和最后(页脚)行的间距避免与半透明状态/导航栏重叠。我将更全面地了解需要发生的事情。

getCount()需要返回:

mListSize + (mNumColumns * 2)

为什么呢?因为您需要每列的标题视图以及每列的页脚视图。

getItem()需要为所有可能的位置返回一些内容。这意味着getCount()返回的任何值都需要能够返回某些内容......即使它是一个空字符串。如下所示:

// if a header position or a footer position
if (position < mNumColumns || position > mListSize + mNumColumns) {
    return ""
} else {
    return mList.get(position - mNumColumns);
}

请注意,考虑到数量不是零,但位置是......,这可能会稍微偏离......但它显示了您需要的基本要点。

getView()需要正常呈现视图。区别在于,如果位置编号指示页眉/页脚位置,则返回空白视图。例如:

ViewHolder vh = null;
if (convertView == null) {
    //inflate your view
    convertView.setTag(vh);
} else {
    vh = (ViewHolder) convertView;
}

//If position is indicative of a header/footer. Alternatively you could see if getItem() returns an empty string...assuming your data can never contain an empty string.
 if (position < mNumColumns || position > mListSize + mNumColumns) {
    //Don't fill the view with any data. Make any visible elements INVISIBLE
 } else {
    //populate convertView with data
 }

摆脱传递视图以供适配器使用的整个概念。那会破坏一切。如果表现非常令人担忧,那么使用getItemViewType()getViewTypeCount()就是一个更好的选择(而且正确的选择......比我发布的更多)。但是,这将要求您创建一个可以表示实际数据的类对象(例如字符串)和一个表示它是页眉,页脚和数据的标志。