使用自定义适配器更新筛选的列表视图



我正在创建一个音乐播放器。除其他事项外,此类还假设将新歌曲添加到播放列表中。 弹出一个新窗口,其中包含可用的歌曲,并添加了选中的歌曲。可以过滤歌曲,选中复选框时,所选行将更改颜色。过滤工作,一切都按照它应该的方式添加,但是......

问题是,当我检查一首歌曲/一些歌曲,然后单击搜索过滤器,软键盘弹出所选行的颜色更改为默认颜色时,(歌曲仍然被选中并且可以添加到播放列表中)。当检查歌曲并隐藏键盘时,也会发生同样的事情。

另一个问题是,当列表被过滤时,先前选择的行的颜色也会消失,当搜索框被清除时,歌曲仍然处于选中状态。

我不明白如何以及为什么会发生这种情况,因此如何解决这个问题。 请问有人有什么想法吗?

我想我不明白过滤后更新是如何工作的,以及 notifyDataSetChanged() 到底做了什么。

这是适配器代码:

public class MyTrackAdapter extends ArrayAdapter<File> 
{
private final Activity context;   
private ArrayList<File> album, temp;   
private ArrayList<File> piosenki;
public MyTrackAdapter(Activity context, ArrayList<File> album) 
{   
super(context, R.layout.adapter_traki, album);   
this.context = context;   
this.temp = new ArrayList<File>(album);
this.album = album;   
this.piosenki=new ArrayList<File>();        
} 
public View getView(int position, View view, ViewGroup parent) 
{   
LayoutInflater inflater = context.getLayoutInflater();   
final View rowView = inflater.inflate(R.layout.adapter_traki, null,true);   
final CheckBox cb_plus = (CheckBox) rowView.findViewById(R.id.add);
final int position1=position;
final TextView txt = (TextView) rowView.findViewById(R.id.list_text);   
if(position1 %2 == 1) rowView.setBackgroundResource(R.color.bbcolor);
else rowView.setBackgroundResource(R.color.bpcolor);
txt.setText(album.get(position1).getName().toString().replace(".mp3",""));   
cb_plus.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener()
{
@Override 
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
{
if (cb_plus.isChecked())
{
cb_plus.setBackgroundResource(R.drawable.x2);       
txt.setTextColor(context.getResources().getColor(R.color.bdcolor));
rowView.setBackgroundResource(R.color.acolor);
piosenki.add(album.get(position1));
}
else 
{
cb_plus.setBackgroundResource(R.drawable.plus);
txt.setTextColor(context.getResources().getColor(R.color.gcolor));
if(position1 %2 == 1) rowView.setBackgroundResource(R.color.bbcolor);
else rowView.setBackgroundResource(R.color.bpcolor);
piosenki.remove(album.get(position1));
}
}
}); 
return rowView;        
} 
public void showTost(String s)
{
Toast.makeText(context, s, Toast.LENGTH_SHORT).show();
}
public ArrayList<File> getpiosenki()
{   
return piosenki;
}
public Filter getFilter()
{           
return filtr;
}
private Filter filtr = new Filter()
{   
protected FilterResults performFiltering(CharSequence s)
{   
FilterResults r = new FilterResults();
ArrayList<File> f = new ArrayList<File>();
if(s==null || s.length()==0) f.addAll(temp);                            
else
{   
String ss=s.toString().toLowerCase().trim();
for(File ff : temp) if(ff.getName().replace(".mp3", "").toLowerCase().contains(ss)) f.add(ff);                                  
}
r.values=f;
r.count=f.size();
return r;           
} 
protected void publishResults(CharSequence s, FilterResults r)
{   
album.clear();
album.addAll((ArrayList)r.values);
notifyDataSetChanged(); 
} 
};
}   

和播放列表类:

public class Playlist extends Activity implements TextWatcher
{
int where;
long pos;
String pllist;
ArrayList<String> lstp, lsts;
ArrayList<Long> lsti;
ArrayList<Integer> lstx;
DBHandler db;
private TextView txt1, txt2;
ImageView pic;
private ListView lv_traki;
ListView lv_traki2add;
PopupWindow pw;
View popupv;
TextView etext;
MyTrackAdapter tadapter;
ImageView add2list;
ArrayList <File> piosenki, toadd;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.playlist);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
db = new DBHandler(getApplicationContext());    
Intent tnt = getIntent();
Bundle bn = tnt.getExtras();
lstp = (ArrayList) bn.getParcelableArrayList("path");
lsts = (ArrayList) bn.getParcelableArrayList("song"); 
lsti = (ArrayList) bn.getParcelableArrayList("indx");
lstx = (ArrayList) bn.getParcelableArrayList("pause"); 
pos = bn.getLong("pos", 0);
where = bn.getInt("skad", 0);
pllist = bn.getString("album");
piosenki = (ArrayList) bn.getParcelableArrayList("full"); 
setData(0, lstp.size());    
songlist(); 
lv_traki.setOnItemClickListener(new AdapterView.OnItemClickListener()
{
@Override
public void onItemClick(AdapterView<?> adapterView, View v, int i, long l)
{
Intent it;          
lstp.clear();
lsti.clear();
lsts.clear();
lstx.clear();
db.gett1path(pos, lstp);
db.gett1song(pos, lsts);
db.gett1pause(pos, lstx);
db.gett1id(pos, lsti); 
it=new Intent(getApplicationContext(), Player.class);       
it.putExtra("path", lstp).putExtra("nazwa", lsts).putExtra("pause", lstx).putExtra("pos",i).putExtra("skad",4);
startActivity(it);
}                       
});
if(where==5) lv_traki.performItemClick(lv_traki.getAdapter().getView(0, null, null), 0, lv_traki.getAdapter().getItemId(0));
add2list = (ImageView) findViewById(R.id.btn_addtoplay);
toadd = new ArrayList<File>();
add2list.setOnClickListener(new View.OnClickListener() 
{
public void onClick(View view) 
{           
popupv = ((LayoutInflater) getApplicationContext().getSystemService("layout_inflater")).inflate(R.layout.popup_addtolist, null);
ImageView btn01 = (ImageView) popupv.findViewById(R.id.btn_addtoplay);
FrameLayout fl = (FrameLayout) findViewById(R.id.frameLayout1);
etext = (EditText) popupv.findViewById(R.id.etext);
etext.addTextChangedListener(Playlist.this); 
lv_traki2add = (ListView) popupv.findViewById(R.id.lst_traki2add);
tadapter = new MyTrackAdapter(Playlist.this, piosenki);
lv_traki2add.setAdapter(tadapter);
toadd=tadapter.getpiosenki();
btn01.setOnClickListener(new View.OnClickListener() 
{
public void onClick(View view) 
{
if(toadd.size()>0)  
{   
for (File addt1 : toadd) 
{
db.addt1(pos, addt1);                               
}
lstp.clear();
lsts.clear();
lstx.clear();
lsti.clear();
db.gett1path(pos, lstp);
db.gett1song(pos, lsts);
db.gett1pause(pos, lstx);
db.gett1id(pos, lsti);
lv_traki.setAdapter(null);
setData(0, lstp.size());    
MyPlaylistAdapter adapter=new MyPlaylistAdapter(Playlist.this, lsts, lstp, lsti, lstx, pos, pllist, lv_traki, txt2);   
lv_traki.setAdapter(adapter);   
for(int x=0; x<lv_traki2add.getChildCount(); x++)
{                           
CheckBox cb = lv_traki2add.getChildAt(x).findViewById(R.id.add);                                                
cb.setChecked(false);                                    
}
pw.dismiss();
showTost("Songs Added");
}               
else pw.dismiss();                                                                                     
}
});
pw = new PopupWindow(popupv, -1, -1, true);
pw.showAtLocation(fl, 17, 0, 0);
}
});
} 
private void songlist()
{
lv_traki = (ListView) findViewById(R.id.lst_traki);
MyPlaylistAdapter adapter=new MyPlaylistAdapter(this, lsts, lstp, lsti, lstx, pos, pllist, lv_traki, txt2);   
lv_traki.setAdapter(adapter);   
}
public void setData(int z, int size)
{
MediaMetadataRetriever mmr = new MediaMetadataRetriever(); 
MediaMetadataRetriever tmp = new MediaMetadataRetriever(); 
mmr.setDataSource(lstp.get(z));
txt1 = (TextView) findViewById(R.id.txt1);
txt2 = (TextView) findViewById(R.id.txt2);
pic = (ImageView) findViewById(R.id.img_bg);
int tmax = 0;
for(int i=0;i<size;i++) 
{
tmp.setDataSource(lstp.get(i));
tmax+=Integer.parseInt(tmp.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)); 
tmax+=lstx.get(i)*1000;
}
txt1.setText(pllist);
if (size>1) txt2.setText(size+" songs;   "+mili_t(tmax)); 
else txt2.setText("1 song;   "+mili_t(tmax)); 
Bitmap bm; 
Drawable d;
byte [] img = mmr.getEmbeddedPicture();
if(img!=null)
{
bm = BitmapFactory.decodeByteArray(img, 0, img.length); 
d = new BitmapDrawable(getResources(), bm); 
pic.setBackground(d);
}
else
{
pic.setBackgroundResource(R.drawable.no_image);
pic.getLayoutParams().height = 400;
pic.getLayoutParams().width = 400;
pic.setScaleType(ScaleType.CENTER_INSIDE);   
}
}

public String mili_t(int t)
{
int s = (int) (t / 1000) % 60 ;
int m = (int) ((t / (1000*60)) % 60);
int h = (int) ((t / (1000*60*60)) % 24);
String dt="", dh, ds, dm;
if(h>0)
{
dh=Integer.toString(h);
if(h<10) dh="0"+dh;
dt=dt+dh+":";
}
if(m>=0)
{
dm=Integer.toString(m);
if(m<10) dm="0"+dm;
dt=dt+dm+":";
}
if(s>=0)
{
ds=Integer.toString(s);
if(s<10) ds="0"+ds;
dt=dt+ds;
}
return dt;
}
public void showTost(String s) 
{ 
Toast.makeText(getApplicationContext(), s, Toast.LENGTH_SHORT).show(); 
} 
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) 
{
tadapter.getFilter().filter(s);                               
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
@Override
public void afterTextChanged(Editable s) {}
}

和 xml :

<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/popupwrap"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:background="@color/bdcolor">
<RelativeLayout
android:id="@+id/popup"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/bdcolor">
<EditText
android:id="@+id/etext"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textColorHint="@color/bbcolor"
android:hint="SEARCH FILTER"
android:background="@drawable/etext"
android:textSize="24sp"
android:textCursorDrawable="@drawable/cursor"
android:textColor="@color/gcolor"
android:inputType="text"
android:layout_marginLeft="10dp"
android:layout_marginRight="80dp"
android:layout_marginTop="10dp" 
android:layout_marginBottom="10dp"  
android:layout_centerVertical="true"
android:layout_alignParentLeft="true"/>
<ImageView
android:id="@+id/btn_addtoplay"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginBottom="10dp"
android:layout_marginRight="10dp"
android:src="@drawable/check1"
android:clickable="true"
android:layout_alignParentRight="true" 
android:layout_marginTop="10dp" 
android:layout_centerVertical="true"/>
</RelativeLayout>   
<ListView
android:layout_width="fill_parent"
android:layout_height="wrap_content"    
android:id="@+id/lst_traki2add">
</ListView>

</LinearLayout>

问题是您依赖于每行中的Checkbox视图来维护该行的选择状态。如果您有很长的歌曲列表,您还会看到奇怪的行为,选择一些,然后滚动。这两个问题都是因为ListView将回收用于呈现当前显示的歌曲的视图,而不是为每一行创建一组新的视图。

要解决此问题,您需要自己维护选择状态。您可以使用bool[]List<Boolean>来执行此操作,该为当前数据中的每首歌曲存储一个标志。使用此选项可以设置背景颜色和复选框状态,而不是依赖复选框状态来设置背景颜色。

原因很简单 - 你有OnCheckedChangeListener,它在每次(取消)检查后触发并且正在更改背景。每次调用时notifyDataSetChanged()整个列表都会被重新绘制,因此背景颜色将再次设置为if(position1 %2 == 1)getView方法中的条件,但侦听器不会再次触发。使用手动侦听器调用查看他的代码

CompoundButton.OnCheckedChangeListener listener = new CompoundButton.OnCheckedChangeListener()
{
@Override 
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
{
if (cb_plus.isChecked())
{
cb_plus.setBackgroundResource(R.drawable.x2);       
txt.setTextColor(context.getResources().getColor(R.color.bdcolor));
rowView.setBackgroundResource(R.color.acolor);
if(piosenki.get(album.get(position1)) != null) // won't duplicate
piosenki.add(album.get(position1));
}
else 
{
cb_plus.setBackgroundResource(R.drawable.plus);
txt.setTextColor(context.getResources().getColor(R.color.gcolor));
if(position1 %2 == 1) rowView.setBackgroundResource(R.color.bbcolor);
else rowView.setBackgroundResource(R.color.bpcolor);
piosenki.remove(album.get(position1));
}
}
}
boolean isAdded = ...;
cb_plus.setChecked(isAdded);
cb_plus.setOnCheckedChangeListener(listener); // set listener after setting (un)checked
listener.onCheckedChanged(cb_plus, isAdded); // manual call

isAdded是你是否CheckBox检查的条件,可能是piosenki.contains(album.get(position1));piosenki.get(album.get(position1)) != null;。 您还可以从方法中删除getView一些重复的行,例如具有背景或文本颜色设置的行 - 这些将在手动侦听器调用中调用

PS. 还将piosenki更改为songs;)

最新更新