ListView 在与交互之前不会呈现所有项目

Posted

技术标签:

【中文标题】ListView 在与交互之前不会呈现所有项目【英文标题】:ListView does not render all items until interacted with 【发布时间】:2012-07-13 03:17:18 【问题描述】:

我在使用 ListView 时遇到了一个非常奇怪的问题。

我的适配器项目只有一部分呈现在屏幕上的列表视图中,但是当我与列表视图交互(即尝试滚动它)时,所有项目都正确呈现。

只有当我的项目比屏幕显示的少时才会出现这种情况。看看下面的这些屏幕截图。

互动前:

互动后:

添加物品的activity源代码:

String[] jRests = getResources().getStringArray(R.array.j_restaurants);
        String[] lRests = getResources().getStringArray(R.array.l_restaurants);

        items = new ArrayList<Object>();
        items.add(getString(R.string.campus_j));
        for(String item : jRests)
            String[] val = item.split(",,,");
            items.add(new FoodSectionListItem(new Restaurant(val[0], val[1], val[2], "")));
           
        items.add(getString(R.string.campus_l));
        for(String item : lRests)
            String[] val = item.split(",,,");
            items.add(new FoodSectionListItem(new Restaurant(val[0], val[1], val[2], "")));
           

        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        adapter = new BaseSectionAdapter(this, R.layout.list_item_fragment_header);
        if(!isTabletView())
            adapter.setSelectedItem(-1);
        
        adapter.setItems(items);

适配器代码:

public class BaseSectionAdapter extends AmazingAdapter 

    private LayoutInflater inflater;
    private int selectedItem = 0;
    private List<Object> items;
    private List<SectionItem> sections = new ArrayList<SectionItem>(10);
    private List<Class> itemTypes = new ArrayList<Class>();
    private List<Integer> sectionPositions = new ArrayList<Integer>();
    private int listHeaderLayoutId;
    private View headerView;

    public static interface ISectionListItem 
        public void setProps(View convertView, int position, int selectedItem);
        public View getLayout(LayoutInflater inflater);
    

    private class SectionItem implements Serializable 
        private static final long serialVersionUID = -8930010937740160935L;
        String text;
        int position;

        public SectionItem(String text, int position) 
            this.text = text;
            this.position = position;
        
    

    public BaseSectionAdapter(Context context, int listHeaderLayoutId) 
        this.listHeaderLayoutId = listHeaderLayoutId;
        init(context);
    

    public BaseSectionAdapter(Context context, int listHeaderLayoutId, List<Object> listItems) 
        this.listHeaderLayoutId = listHeaderLayoutId;
        init(context);
        initListItems(listItems);
    

    private void init(Context context) 
        inflater = (LayoutInflater) context
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    

    public void setSelectedItem(int position) 
        selectedItem = position;
    

//  public List<ListItem> getItems() 
//      return items;
//  

    private void initListItems(List<Object> itemList) 
        int curSection = -1;
        //int curPosition = 0;
        //curSection = 0;

        this.items = itemList;
        itemTypes.clear();
        sections.clear();
        sectionPositions.clear();



        int listSize = itemList.size();
        for(int i = 0; i < listSize; i++)
            Object currentItem = items.get(i);
            if(currentItem instanceof String)
                sections.add(new SectionItem((String) currentItem,i));
                curSection++;
            
            if(!itemTypes.contains(currentItem.getClass()))
                itemTypes.add(currentItem.getClass());
            


            sectionPositions.add(curSection);
        

        Log.d("test", "No of items = "+items.size());
        Log.d("test", "No of itemtypes = "+itemTypes.size());
        Log.d("test", "View type count = "+getViewTypeCount());
    

    public void setItems(List<Object> itemList) 
        initListItems(itemList);
    

    public int getCount() 
        return items==null?0:items.size();
    

    @Override
    public int getViewTypeCount()
        return (itemTypes.size() == 0)?1:itemTypes.size();
    

    @Override
    public int getItemViewType(int position)
        return itemTypes.indexOf(items.get(position).getClass());
    

    @Override
    public boolean isEnabled(int position)
        return !(items.get(position) instanceof String || items.get(position) instanceof EmptySectionListItem);
    

    @Override
    public Object getItem(int position) 
        return items.get(position);
    

    public long getItemId(int position) 
        return position;
    

    @Override
    protected void onNextPageRequested(int page) 
        // TODO Auto-generated method stub

    

    @Override
    protected void bindSectionHeader(View view, int position,
            boolean displaySectionHeader) 
//      TextView lSectionTitle = (TextView) view
//              .findViewById(R.id.txt_list_header);
//      if (displaySectionHeader) 
//          lSectionTitle.setVisibility(View.VISIBLE);
//          lSectionTitle
//                  .setText(getSections()[getSectionForPosition(position)]);
//       else 
//          lSectionTitle.setVisibility(View.GONE);
//      
    

    @Override
    public View getAmazingView(int position, View convertView, ViewGroup parent) 
        Object curItemObject = items.get(position);
        boolean isHeader = (curItemObject instanceof String);

        if(convertView == null)
            if(isHeader && headerView != null)
                convertView = headerView;
            else if(isHeader)
                convertView = inflater.inflate(listHeaderLayoutId, null);
                headerView = convertView;
            else
                convertView = ((ISectionListItem) curItemObject).getLayout(inflater);
            
           
        if(isHeader)
            TextView header = ((TextView)convertView.findViewById(R.id.txt_list_header));
            header.setText((String)curItemObject);
        else
            ((ISectionListItem)curItemObject).setProps(convertView, position, selectedItem);
        
        return convertView;
    

    @Override
    public void configurePinnedHeader(View header, int position, int alpha) 

        TextView textView = ((TextView)header.findViewById(R.id.txt_list_header));
        textView.setText(getSections()[getSectionForPosition(position)]);
    

    @Override
    public int getPositionForSection(int section) 
        if(section >= sections.size())
            return 0;
        

        return sections.get(section).position;
    

    @Override
    public int getSectionForPosition(int position) 
        return sectionPositions.get(position);
    

    @Override
    public String[] getSections() 
        String[] res = new String[sections.size()];
        for (int i = 0; i < res.length; i++) 
            res[i] = sections.get(i).text;

        
        return res;
    

布局代码:

LinearLayout layout = new LinearLayout(this);
            layout.setOrientation(LinearLayout.HORIZONTAL);

            FrameLayout listLayout = new FrameLayout(this);
            LinearLayout.LayoutParams listParams = new LinearLayout.LayoutParams(0, FrameLayout.LayoutParams.MATCH_PARENT);
            listParams.weight = 1;
            listLayout.setId(LIST_FRAGMENT_VIEW_ID);

            FrameLayout detailLayout = new FrameLayout(this);
            LinearLayout.LayoutParams detailParams = new LinearLayout.LayoutParams(0, FrameLayout.LayoutParams.MATCH_PARENT);
            detailParams.weight = 2;
            detailLayout.setId(DETAIL_FRAGMENT_VIEW_ID);

            layout.addView(listLayout, listParams);
            layout.addView(detailLayout, detailParams);

            if(savedInstanceState == null)

            FragmentTransaction ft = getSupportFragmentManager().beginTransaction();

            ft.add(listLayout.getId(), (Fragment) listFragment, TWO_PANEL_LIST_FRAGMENT_TAG);
            ft.add(detailLayout.getId(), detailFragment);
            ft.commit();

            
            setContentView(layout);

【问题讨论】:

你能添加一些适配器的代码吗..? 将要添加项目的源代码添加到列表视图的后备数据源,并创建适配器 也显示您的 ListView 的布局源。 :) 添加了你要求的所有东西,虽然结构相当复杂:) 你能分享一下你做了什么改变吗?我也面临同样的问题 【参考方案1】:

尝试在 runOnUIThread() 方法中调用 notifyDataSetChanged(),如下所示,它会像魅力一样工作。 :)

                runOnUiThread(new Runnable() 
                    @Override
                    public void run() 
                        messageAdapter.notifyDataSetChanged();
                    
                );

【讨论】:

显然不是原始问题的解决方案,但这为我解决了同样的问题。从另一个线程调用 notifyDataSetChanged() 不可靠。【参考方案2】:

我不知道是什么导致了这个问题,但如果你没有找到一个合乎逻辑的解决方案,你可以尝试这样的事情:

无论何时启动ListView,都会以编程方式触发onTouchEvent()。 ListView 启动后立即以编程方式向下滚动和备份。

等等。

【讨论】:

【参考方案3】:

将 ListView 小部件添加到 layout.xml 并将列表内容添加到其中。不要使用 FrameLayout,因为它可能是问题的原因。它在触摸后更新内容,因此它所在的布局没有像 ListView 小部件那样实现正确的 onCreate() 设置。

【讨论】:

你的意思是它没有实现正确的onCreate?我以编程方式创建布局,然后将我的片段添加到其中。试过把两个FrameLayout改成LinearLayout,没区别:/ @Richard 你在哪里添加 ListView?根据您的代码,您没有实现 ListView。 ft.add(listLayout.getId(), (Fragment) listFragment, TWO_PANEL_LIST_FRAGMENT_TAG); 我正在添加一个列表片段【参考方案4】:

添加新项目后,您是否在适配器上调用方法 notifyDataSetChanged()?这会导致列表视图在基础数据集更改时刷新其视图。

如果还是不行,试试 notifyDataSetInvalidated(),它会导致 listview 完全重绘。

【讨论】:

试过这个。没有效果。开始认为 listfragment 可能是这里的问题。我正在添加【参考方案5】:

解决了!!!

问题在于适配器试图重用相同的部分项目。不好!!!

将其更改为每次我们点击一​​个部分时都会膨胀部分项目!

【讨论】:

你能帮帮我吗,我也有同样的问题,你能解释一下你是怎么解决的吗?我必须点击屏幕才能加载列表视图 正确的答案应该详细说明如何解决问题,而不仅仅是提示。特别是如果您回答自己的问题...

以上是关于ListView 在与交互之前不会呈现所有项目的主要内容,如果未能解决你的问题,请参考以下文章

未调用列表视图中的 xamarin 项目单击

具有网络数据的 UICollectionView 在与交互之前不显示单元格

自定义 UIControl(滑块)在与交互之前不遵守约束

React Native ListView 不会通过单击重新呈现状态更改

android 自己定义ViewGroup实现可记载并呈现选择的ListView

如何在与 JGit 合并之前获得冲突?