listview中複用seekbar bug產生及解決方案

前言

1.之前沒怎麼在ListView的Item條目中嵌套Seekbar, 突然有朋友遇到這樣的情況,於是花點時間解決下

網上找的一些blog基本沒什麼用,可能是我的手法不對,本篇實測有效


解決問題

seekbar在listview的item中時,點擊定時加載進度時,滑動listview,seekbar複用的部分也會被定時器控制進行進度加載


解決後的效果



分析

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的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

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="100dp"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <TextView
        android:text="播放"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        android:id="@+id/tv_play"
        android:gravity="center_vertical"
        android:layout_width="wrap_content"
        android:layout_height="100dp" />

    <SeekBar
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toRightOf="@id/tv_play"
        android:id="@+id/tv_seekbar"
        app:layout_constraintRight_toRightOf="parent"
        android:layout_width="0dp"
        android:gravity="center_vertical"
        android:layout_height="100dp" />
</android.support.constraint.ConstraintLayout>

靠這篇文章解決問題的,幫忙點個贊!  打字不易





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章