1

我有一个 ListView,其中包含使用特定布局创建的行。每行都有默认为 View.GONE 的 ProgressBar。单击此元素时,我需要使 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 的哪个部分当前在屏幕上,我都需要它在一行中。

4

3 回答 3

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

于 2013-10-06T04:24:54.253 回答
0

ListView,像所有适配器视图一样,使用视图回收。

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

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

该怎么办?

您应该在自定义适配器的 getView() 方法中打开进度条的可见性(可以基于BaseAdapter)。它是否打开应该取决于一些标志。

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


我需要更改进度条的可见性,当我单击元素时它是进度,而不是在我创建列表视图时。

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

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

于 2013-10-06T13:12:06.757 回答
0

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

以下是解决方法:

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

if(data.isProressVisible){
   audioItemProgressBarView.setVisibility(View.VISIBLE);
}else{
   audioItemProgressBarView.setVisibility(View.INVISIBLE);
}
于 2013-10-06T13:15:35.980 回答