2014-07-22 79 views
2

我正在创建一个ArrayAdapter为我的GridView考虑页眉和页脚视图。Android - 非常奇怪的行为与GridView

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> 

的问题是,当我滚动到顶部或网格标题的底部/底部的观点得到了网格项目,并在任何项目上点击时,它可以追溯到原始位置(如果需要,我会放置屏幕截图)

这是我的GridView适配器(params按顺序:上下文,网格项目的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; 
    } 
} 

前SCROLLING: enter image description here 后滚动: enter image description here

正如你所看到的,目标是增加一个头,以避免第一项是状态栏

+0

如果有问题的快照,最好.... –

+0

@ i.n.e.f好的,完成 – BamsBamx

+0

你正在用你的适配器做一些非常错误的事情。为了帮助我解释一下,首先你有什么打算使用页脚和页眉?此外,这些屏幕截图中的页眉/页脚视图是什么? –

回答

2

手动位置玩弄背后数字是一件危险的事情,尽管如果做得正确的话也是可能的这里的问题在于,您试图绕过getView()方法的运行方式。 getView()将维护它自己对返回视图的引用并回收或相应地销毁它。它已经得到了极大的优化,能够提供出色的性能,并且为了达到最终目标,您希望与之合作......不会违背。

最终,您希望GridView中第一行(页眉)和最后一行(页脚)行的间距避免与半透明状态/导航栏重叠。我会给你一个更高级的需要发生的概况。

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()。但是,这需要您创建一个可以表示实际数据的类对象(例如字符串)和一个表示它是页眉,页脚和数据的标志。

+0

试过这个,但唯一让它工作的方法是在getView方法内扩展头部,如果convertView == null ...为什么不能将它作为参数传递? – BamsBamx

+0

因为在内部,对于适配器,Android将确定视图何时被销毁......或者被循环使用以用于不同的位置编号。当您滚动并且视图熄灭屏幕时,会发生这种情况。 –

+0

好的,谢谢你的回应。您让我了解了有关适配器的更多信息 – BamsBamx