listview中复用seekbar bug产生及解决方案

前言

1.之前没怎么在ListView的Item条目中嵌套Seekbar, 突然有朋友遇到这样的情况,于是花点时间解决下

网上找的一些blog基本没什么用,可能是我的手法不对,本篇实测有效


解决问题

seekbar在listview的item中时,点击定时加载进度时,滑动listview,seekbar复用的部分也会被定时器控制进行进度加载


解决后的效果

listview中复用seekbar bug产生及解决方案_第1张图片


分析

listview的常规用法,  

设置适配器 

适配器中四个方法  最重要的getView 

convertView复用Item条目

自定义ViewHolder保存控件 避免频繁查找控件

这里贴一下getView的代码



    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        final ViewHolder holder;
        if (convertView == null) {
            holder = new ViewHolder();
            convertView = View.inflate(mContext, R.layout.item_seekbar, null);
            holder.mTextView = convertView.findViewById(R.id.tv_play);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }
        holder.mTextView.setText("播放" + position);
   
        return convertView;
    }

    class ViewHolder {
        private TextView mTextView;
    }

}

listview中复用seekbar bug产生及解决方案_第2张图片

上面是 listview的convertView复用流程

比如说一个界面最多需要 6个条目覆盖慢,如果使用了convertView复用,那么在下滑时第7个条目刚刚出现,但第一个条目完全消失时,getView 会获取第一个的ItemView 作为convertView , 我们又convertView带了当前也就是第7个条目展示的Item

所以第7个的View就是第1个

listview中每个条目的区别不在于控件  而在于数据  数据通过position进行区分,我们只要将position绑定到convertView 实际上就可以了 ,看了几篇网文,可能是拷错了

每次getView 表示初始化一个ItemView 我们都需要对其绑定position,可以绑定到某个控件 view.setTag

也可以绑定到ViewHolder

但需要注意的是 不管是否复用View 都需要对于position进行绑定

我这里会在下面初始化的定时器的回调中对于当前 view中获取的position和 点击播放的position进行比较,来判断当前的条目是否为复用条目,而不是原本点击的条目

还是贴出关键代码 getView

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        final ViewHolder holder;
        if (convertView == null) {
            holder = new ViewHolder();
            convertView = View.inflate(mContext, R.layout.item_seekbar, null);
            holder.mTextView = convertView.findViewById(R.id.tv_play);
            holder.mSeekBar = convertView.findViewById(R.id.tv_seekbar);
            holder.mTextView.setTag(position);
            holder.mSeekBar.setTag(position);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
            holder.mTextView.setTag(position);
            holder.mSeekBar.setTag(position);
        }
        holder.mTextView.setText("播放" + position);
        holder.mSeekBar.setMax(100);
        holder.mSeekBar.setProgress(0);
        holder.mTextView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                choosePosition =position;
                timer = new Timer();
                final Handler handler = new Handler();
                timer.schedule(new TimerTask() {
                    @Override
                    public void run() {
                        handler.post(new Runnable() {
                            @Override
                            public void run() {
                                currentPlayProgress++;


                                if ((int)holder.mTextView.getTag() == choosePosition) {
                                    if (currentPlayProgress > 100) {
                                        currentPlayProgress = 0;
                                        holder.mSeekBar.setProgress(currentPlayProgress);
                                        timer.cancel();
                                    } else {
                                        holder.mSeekBar.setProgress(currentPlayProgress);
                                    }
                                }
                            }
                        });
                    }
                }, 100, 1000);

            }
        });

        return convertView;
    }

    class ViewHolder {
        private SeekBar mSeekBar;
        private TextView mTextView;
    }

实际上 上面的gif图还有一点点小问题,就是 从下往上滑动时,第一个条目重新出现 一开始显示进度0 

这个在getView 初始化数据时做一点小变动,判断当前是否为进行进度加载中的条目,做进度更新就可以了

    holder.mSeekBar.setMax(100);
        if (choosePosition == position) {
            holder.mSeekBar.setProgress(currentPlayProgress);
        } else {
            holder.mSeekBar.setProgress(0);
        }



下面贴一下全部代码

adapter

package com.example.caixingcun.seekbarlistcontroldemo;

import android.content.Context;
import android.os.Handler;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.SeekBar;
import android.widget.TextView;

import java.util.Timer;
import java.util.TimerTask;


/**
 * Created by cxc on 2018/3/22.
 */

public class SeekBarAdapter extends BaseAdapter {
    private Context mContext;
    private Timer timer;
    private int currentPlayProgress = 0;
    private int choosePosition = -1;


    public SeekBarAdapter(Context context) {
        mContext = context;

    }

    @Override
    public int getCount() {
        return 30;
    }

    @Override
    public Object getItem(int position) {
        return position;
    }

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

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        final ViewHolder holder;
        if (convertView == null) {
            holder = new ViewHolder();
            convertView = View.inflate(mContext, R.layout.item_seekbar, null);
            holder.mTextView = convertView.findViewById(R.id.tv_play);
            holder.mSeekBar = convertView.findViewById(R.id.tv_seekbar);
            holder.mTextView.setTag(position);
            holder.mSeekBar.setTag(position);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
            holder.mTextView.setTag(position);
            holder.mSeekBar.setTag(position);
        }
        holder.mTextView.setText("播放" + position);
        holder.mSeekBar.setMax(100);
        if (choosePosition == position) {
            holder.mSeekBar.setProgress(currentPlayProgress);
        } else {
            holder.mSeekBar.setProgress(0);
        }
        holder.mTextView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                choosePosition = position;
                timer = new Timer();
                final Handler handler = new Handler();
                timer.schedule(new TimerTask() {
                    @Override
                    public void run() {
                        handler.post(new Runnable() {
                            @Override
                            public void run() {
                                currentPlayProgress++;


                                if ((int) holder.mTextView.getTag() == choosePosition) {
                                    if (currentPlayProgress > 100) {
                                        currentPlayProgress = 0;
                                        holder.mSeekBar.setProgress(currentPlayProgress);
                                        timer.cancel();
                                    } else {
                                        holder.mSeekBar.setProgress(currentPlayProgress);
                                    }
                                }
                            }
                        });
                    }
                }, 100, 1000);

            }
        });

        return convertView;
    }

    class ViewHolder {
        private SeekBar mSeekBar;
        private TextView mTextView;
    }

}

MainActivity

       setContentView(R.layout.activity_main);
        mListView = findViewById(R.id.lv);
        mListView.setAdapter(new SeekBarAdapter(this));

item_seekbar.xml



    

    

靠这篇文章解决问题的,帮忙点个赞!  打字不易





你可能感兴趣的:(android)