2016-09-28 7 views
0

У меня возникли проблемы с выполнением множественного удаления в ListView в android.Удалить элементы из пользовательского адаптера android

1) Я создал CustomAdapter настроить каждую строку с помощью нескольких кнопок и текстов (я помещу здесь только то, что я думаю, что его самое важное):

public class PlayableCustomAdapter extends ArrayAdapter<String> { 
private final boolean[] checkedItems; 
private final LayoutInflater mInflater; 
private final ActivityCallback activityCallback; 

public PlayableCustomAdapter(Context context, ActivityCallback activityCallback, 
          List<String> files) { 
    super(context, NO_SELECTION); 

    this.activityCallback = activityCallback; 
    this.mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
    this.checkedItems = new boolean[files.size()]; 

    addAll(files); 
} 

@Override 
public View getView(final int position, View convertView, ViewGroup parent) { 
    View row = convertView; 
    Holder holder; 

    if (row == null) { 
     row = mInflater.inflate(R.layout.list_view_row_song, null); 

     holder = new Holder(); 
     holder.text = (TextView) row.findViewById(R.id.tvFileName); 
     holder.configs = (TextView) row.findViewById(R.id.tvFileConfiguration); 
     holder.checkBox = (CheckBox) row.findViewById(R.id.cbDelete); 
     holder.playButton = (ImageButton) row.findViewById(R.id.btnPlay); 
     holder.settingsButton = (ImageButton) row.findViewById(R.id.btnSettings); 
     holder.text.setText(getItem(position)); 
     holder.configs.setText(getLyricConfiguration(getItem(position))); 
     row.setTag(holder); 

    } else { 
     holder = (Holder) convertView.getTag(); 
    } 

    holder.playButton.setOnClickListener(new View.OnClickListener() { 
     @Override 
     public void onClick(View view) { 
      startPrompter(position); 
     } 
    }); 

    holder.settingsButton.setOnClickListener(new View.OnClickListener() { 
     @Override 
     public void onClick(View view) { 
      startSettings(position); 
     } 
    }); 

    holder.text.setOnClickListener(new View.OnClickListener() { 
     @Override 
     public void onClick(View view) { 
      startEditFile(position); 
     } 
    }); 
    holder.checkBox.setChecked(checkedItems[position]); 
    holder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { 

     @Override 
     public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 
      if (isChecked) { 
       checkedItems[position] = true; 
       activityCallback.showContent(); 
      } else { 
       verifySelectedItems(position); 
      } 
     } 
    }); 

    return row; 
} 

private void verifySelectedItems(int position) { 
    checkedItems[position] = false; 
    for (boolean checked : checkedItems) { 
     if (checked) 
      return; 
    } 
    activityCallback.hideContent(); 
} 

public boolean isChecked(int position) { 
    return checkedItems[position]; 
} 

@Override 
public void remove(String s) { 
    verifySelectedItems(getPosition(s)); 
    super.remove(s); 
    notifyDataSetChanged(); 
} 

static class Holder { 
    TextView text; 
    TextView configs; 
    ImageButton playButton; 
    CheckBox checkBox; 
    ImageButton settingsButton; 
} 

2) Я использовал этот адаптер в Activity и все работает как шарм, за исключением множественного удаления. Только когда я очищаю все элементы адаптера, список просматривается правильно. Когда я удаляю один или несколько элементов, адаптер кажется прекрасным. Все позиции переданы правильно. Но я не знаю, как, только элементы в конце списка удаляются из представления.

3) Как вы можете видеть, я использую notifyDataSetChanged(); после удаления, и проблема все еще происходит. Единственным (и УЖАСНЫМ) решением, которое я мог бы заставить его работать, было восстановление активности после удаления (recreate();). Экран мигает, его ужасно, но он полностью функциональный. И теперь, когда у меня есть свободное время, я спрашиваю вас, ребята, за помощью.

Вот код от деятельности, которая использует адаптер:

private void deleteFilesFromDisk(List<Integer> positionsToDelete, ArrayAdapter adapter) { 
    File[] files = getAppFiles(); 
    for (int position : positionsToDelete) { 
     if (files[position].delete()) { 
      adapter.remove(fileNames.get(position));     
     } else 
      showMessage(R.string.delete_file_error, fileNames.get(position)); 
    } 
    recreate(); // Horrible workaround, but it works! 
} 

Пожалуйста, помните, что этот метод является лишь примером. Особенно последняя строка. Без команды отдыха только элементы в конце списка удаляются (по крайней мере, визуально, из пользовательского интерфейса).

Любые санкции?

+0

adapter.notifydatasetchanged()? когда вы вызываете адаптер.remove (fileNames.get (position)) вместо унаследованного метода – BIW

+0

Вам не нужно удалять элемент из адаптера, удалять элемент из списка и уведомлять адаптер о том, что набор данных изменился –

ответ

0

Ваша проблема может быть здесь

@Override 
public void remove(String s) { 
    verifySelectedItems(getPosition(s)); 
    super.remove(s); 
    notifyDataSetChanged(); 
} 

Вы удалите элемент из адаптера, но не индекс от checkedItems Если бы я тебя, вместо того, чтобы булево массив следить проверяемых элементов, я будет использовать ArrayList<Integer> и сохранить все зарегистрированные позиции в списке.

Вы могли бы изменить этот метод, чтобы выглядеть примерно так

@Override 
public void remove(String s) { 
    int pos = getPosition(s); 
    verifySelectedItems(pos); 
    remove(s); 
    checkedItems.remove(Integer.valueOf(pos)); 
    notifyDataSetChanged(); 
} 

А потом это ...

private void verifySelectedItems(int position) { 
    checkedItems[position] = false; 
    for (boolean checked : checkedItems) { 
     if (checked) 
      return; 
    } 
    activityCallback.hideContent(); 
} 

вместо этого может быть этот

private void verifySelectedItems(int position) { 
    if(!checkedItems.contains(position)) { 
     activityCallback.hideContent(); 
    } 
} 

EDIT:

Извините Я не читал этот вопрос правильно, я думаю, что это ваша проблема

if (row == null) { 
     row = mInflater.inflate(R.layout.list_view_row_song, null); 

     holder = new Holder(); 
     holder.text = (TextView) row.findViewById(R.id.tvFileName); 
     holder.configs = (TextView) row.findViewById(R.id.tvFileConfiguration); 
     holder.checkBox = (CheckBox) row.findViewById(R.id.cbDelete); 
     holder.playButton = (ImageButton) row.findViewById(R.id.btnPlay); 
     holder.settingsButton = (ImageButton) row.findViewById(R.id.btnSettings); 
     holder.text.setText(getItem(position)); 
     holder.configs.setText(getLyricConfiguration(getItem(position))); 
     row.setTag(holder); 

    } else { 
     holder = (Holder) convertView.getTag(); 
    } 

Вы удаляете правильные элементы, но это предотвращает взгляды от обновления после notifydatasetchanged, может быть, попробовать что-то вроде этого

if(convertView == null) { 
    convertView = mInflater.inflate(R.layout.list_view_row_song, null); 
} 

Holder holder = new Holder(); 
holder.text = (TextView) convertView.findViewById(R.id.tvFileName); 
holder.configs = (TextView) convertView.findViewById(R.id.tvFileConfiguration); 
holder.checkBox = (CheckBox) convertView.findViewById(R.id.cbDelete); 
holder.playButton = (ImageButton) convertView.findViewById(R.id.btnPlay); 
holder.settingsButton = (ImageButton) convertView.findViewById(R.id.btnSettings); 

holder.text.setText(getItem(position)); 
holder.configs.setText(getLyricConfiguration(getItem(position))); 
+0

Спасибо человек!! Ты спасатель жизни :) –