ListView中的progressBar在滚动时更改父级

时间:2013-10-06 01:32:24

标签: android listview android-listview listviewitem

我有一个ListView,其中包含使用特定布局创建的行。每行都有ProgressBar默认为View.GONE。单击此元素时,我需要在ListView项中显示ProgressBar。问题是,当我单击元素时,ProgressBars不仅在我单击的行中变得可见,而且在其他随机行中也变得可见。这是代码:

创建ListView并设置OnItemClickListener:

private void buildTracklist(ArrayList<Audio> differences, ArrayList<Audio> vkAudioList) {
        ArrayList<Map<String, Object>> data = new ArrayList<Map<String, Object>>(vkAudioList.size());
        Map<String, Object> m;
        int i;
        for (i=0;i<vkAudioList.size();i++) {
            m = new HashMap<String, Object>();
            m.put(AUDIO_ARTIST, vkAudioList.get(i).artist);
            m.put(AUDIO_TITLE, vkAudioList.get(i).title);
            if (arrayListContainsAudio(differences, vkAudioList.get(i))) {
                m.put(AUDIO_DOWNLOADED, R.drawable.image_blank);
            } else {
                m.put(AUDIO_DOWNLOADED, R.drawable.image_downloaded);
            }
            data.add(m);
        }
        String[] from = {AUDIO_TITLE,AUDIO_ARTIST,AUDIO_DOWNLOADED};
        int[] to = {R.id.audioTitleTextView,R.id.audioArtistTextView,R.id.isDownloadedImageView};
        sAdapter = new SimpleAdapter(this, data, R.layout.tracklist_item, from, to);
        audioListView = (ListView) findViewById(R.id.audioListView);
        audioListView.setAdapter(sAdapter);

        audioListView.setOnItemClickListener(new OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Log.i(TAG,"position="+position+" id="+id);

                view.findViewById(R.id.audioItemProgressBar).setVisibility(View.VISIBLE);
                //Here I'm passing progressBar further
            }
        });
    }

tracklistItem布局:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >

        <TextView
            android:id="@+id/audioTitleTextView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="5dp"
            android:layout_marginTop="2dp"
            android:gravity="top|left"
            android:text="Title"
            android:textSize="24dp" />

        <TextView
            android:id="@+id/audioArtistTextView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/audioTitleTextView"
            android:layout_marginLeft="5dp"
            android:layout_marginTop="2dp"
            android:text="Artist"
            android:textSize="16sp" />

        <ProgressBar
            android:id="@+id/audioItemProgressBar"
            style="?android:attr/progressBarStyleHorizontal"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_below="@+id/audioArtistTextView"
            android:visibility="gone" />

    </RelativeLayout>

    <ImageView
        android:id="@+id/isDownloadedImageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|right"
        android:src="@drawable/downloaded_backgroundv10"
        android:visibility="visible" />

</FrameLayout>

我尝试使用getView()的getChildAt()获取listview项目视图,但发生了同样的问题。感谢您的帮助,抱歉我的英语不好。

更新:我发现progressBar我在滚动ListView时使用更改父项但我需要它在一行中,无论ListView当前在屏幕上的哪个部分。

3 个答案:

答案 0 :(得分:0)

你的代码看起来很不错,但我想你应该使用 baseAdapter 而不是 SimpleAdapter 。如果要在每一行上显示或隐藏视图,建议您使用baseAdapter。

这是baseAdapter的示例。首先,创建一个名为MyBaseAdapter的新类。

public class MyBaseAdapter  extends BaseAdapter{

    private Activity mContext;
    private ArrayList<Map<String, Object>> mList;

    MyBaseAdapter(Activity context, ArrayList<Map<String, Object>> list){
        this.mContext = context;    
        mList = list;
    }

    @Override
    public int getCount() {
        return mList.size();        
    }

    @Override
    public Map<String, Object> getItem(int position) {      
        return mList.get(position);
    }

    @Override
    public long getItemId(int position) {       
        return position;
    }


    private static class ViewHolder {
        public final TextView audioTitleTextView, autioArtistTextView;
        public final ImageView isDownloadedImageView;
        public final FrameLayout fl;


        public ViewHolder(TextView audioArtist, TextView audioTitle,ImageView isDownloaded, FrameLayout fl){
            this.autioArtistTextView = audioArtist;
            this.audioTitleTextView = audioTitle;
            this.isDownloadedImageView = isDownloaded;
            this.fl = fl;
        }
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent){


        TextView audioTitleTextView,autioArtistTextView;
        FrameLayout fl;

        ImageView isDownloadedImageView;
        /*
         * If convertView is not null, tried reuse it
         * else create LayoutInflater to pack up the row view
         */
        if(convertView == null){            
            convertView = LayoutInflater.from(mContext).inflate(R.layout.tracklistItem , parent,false);
            audioTitleTextView = (TextView)convertView.findViewById(R.id.audioTitleTextView);
            autioArtistTextView = (TextView)convertView.findViewById(R.id.audioArtistTextView);     
            isDownloadedImageView = (ImageView)convertView.findViewById(R.id.isDownloadedImageView);
            fl = (FrameLayout)convertView.findViewById(R.id.parentFrameLayout);
            convertView.setTag(new ViewHolder(autioArtistTextView,audioTitleTextView,isDownloadedImageView));


        } else{
            ViewHolder holder = (ViewHolder)convertView.getTag();
            audioTitleTextView = holder.audioTitleTextView;
            autioArtistTextView = holder.autioArtistTextView;
            isDownloadedImageView = holder.isDownloadedImageView;
            fl = holder.fl;
        }


        @SuppressWarnings("unchecked")
        Map<String, Object> rowItem = getItem(position);


        audioTitleTextView.setText(rowItem.get(AUDIO_TITLE));   
        autioArtistTextView.setText(rowItem.get(AUDIO_ARTIST));

        // Change setImageResource to your own image resources
        isDownloadedImageView.setImageResource(rowItem.get(AUDIO_DOWNLOADED));

        fl.setOnClickListener( new View.OnClickListener(){
             @Override
             public void onClick(View view){
                  // hide your progress bar here
             }
        });

        return convertView;
    }   

然后,将SimpleAdapter更改为以下

MyBaseAdapter sAdapter = new MyBaseAdapter(this, data);
audioListView = (ListView) findViewById(R.id.audioListView);
audioListView.setAdapter(sAdapter);

编辑:将FrameLayout添加到viewHolder并设置FrameLayout OnClickListener

答案 1 :(得分:0)

与所有适配器视图一样,

ListView使用视图回收。

  

问题在于,当我点击元素时,ProgressBars不仅在我点击的行中变得可见,而且在其他随机行中也变得可见。

我敢打赌当你滚动视图时会发生这种情况。它的工作方式如下:显示进度条,然后滚动列表。带有进度条的项目滚动到屏幕的可见区域之外。 这是视图被回收的时刻。系统将其与列表视图分离,并再次附加以显示列表的另一行。这就是你再次看到进度条的原因。

怎么办?

您应该在自定义适配器的getView()方法中转换进度条的可见性(可以基于BaseAdapter)。它是否开启应取决于某些旗帜。

阅读this以了解有关适配器视图中的回收视图的更多信息。


  

我需要更改进度条的可见性及其进度   点击元素,而不是在我创建listview时。

只需在适配器中定义一个方法,该方法将更改标志的值。然后你可以调用notifyDataSetChanged。

在处理适配器视图时要记住的重要一点是,您更改了基础数据,而不是视图,因为您的列表中可能有几千个项目,但只有少数视图可以处理可见行。

答案 2 :(得分:0)

要了解为什么会出现此问题,您必须先了解ListView的工作原理。互联网上有很多可用的内容,所以我会在这里简要介绍一下。如果您的适配器中有50个项目,那么这并不意味着ListView将为您创建50行。相反,它将创建5可能是10可能更多取决于您的屏幕的大小,但不是50!然后当你滚动ListView时,就会发生这种情况。滚动出屏幕的行将被重用。 getView()将被调用,您必须再次设置每个属性,否则将重新使用旧属性。在您的情况下,重新使用该行的可见性值。

以下是解决方法:

将可见性数据存储在数据ArrayList中并覆盖适配器的getView()方法,然后处理这两种情况:

if(data.isProressVisible){
   audioItemProgressBarView.setVisibility(View.VISIBLE);
}else{
   audioItemProgressBarView.setVisibility(View.INVISIBLE);
}