拖动动态列表中的DynamicListView项目消失降

时间:2015-07-09 03:48:05

标签: android android-listview drag-and-drop

我按照这个谷歌教程并实现了一个动态ListView进行拖放 https://www.youtube.com/watch?v=_BZIvjMgH-Q

listView = (DynamicListView) findViewById(R.id.listview);
adapter = new StableArrayAdapter(this, R.layout.text_view, arraylist);
listView.setAdapter(adapter);
listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);

// added the items later and called notifyDataSetChanged();
    arraylist.add("item 1");
    arraylist.add("item 2");
    arraylist.add("item 3");
    arraylist.add("item 4");

adapter.notifyDataSetChanged();

它会显示列表视图中的所有项目,但是当我拖放元素时它们会消失。

如果我在设置适配器listView.setAdapter(adapter);之前添加元素,它可以正常工作。

图书馆源代码http://developer.android.com/shareables/devbytes/ListViewDraggingAnimation.zip

我该如何解决这个问题?

更新

StableArrayAdapter.java

package com.example.android.navigationdrawerexample;

import android.content.Context;
import android.widget.ArrayAdapter;

import java.util.HashMap;
import java.util.List;

public class StableArrayAdapter extends ArrayAdapter<String> {

    final int INVALID_ID = -1;

    int mRowLayout;
    List<String[]> mStrings;
    HashMap<String, Integer> mIdMap = new HashMap<String, Integer>();

    // constructor
    public StableArrayAdapter(Context context, int rowLayout, List<String> objects) {
        super(context, rowLayout, objects);
        for (int i = 0; i < objects.size(); ++i) {
            mIdMap.put(objects.get(i), i);
        }
    }

    @Override
    public long getItemId(int position) {
        if (position < 0 || position >= mIdMap.size()) {
            return INVALID_ID;
        }
        String item = getItem(position);
        return mIdMap.get(item);
    }

    @Override
    public boolean hasStableIds() {
        return true;
    }
}

更新2 我按照建议在这里将项目添加到对象,它现在可以正常工作,但是在设置适配器之前是否与添加MainActivity中的项目相同?

public StableArrayAdapter(Context context, int rowLayout, List<String> objects) {
    super(context, rowLayout, objects);

    objects.add("item 1");
    objects.add("item 2");
    objects.add("item 3");
    objects.add("item 4");
    objects.add("item 5");

    for (int i = 0; i < objects.size(); ++i) {
        mIdMap.put(objects.get(i), i);
    }
}

更新3 对象的大小仅在构造函数中是已知的 和 mIdMap.put(&#34; item 6&#34;,objects.size());在代码中没有效果。

 // constructor
    public StableArrayAdapter(Context context, int rowLayout, List<String> objects) {
        super(context, rowLayout, objects);

        this.objects = objects;

        objects.add("item 1");
        objects.add("item 2");
        objects.add("item 3");
        objects.add("item 4");
        objects.add("item 5");

        for (int i = 0; i < objects.size(); ++i) {
            mIdMap.put(objects.get(i), i);
        }

        mIdMap.put("item 6", objects.size());    // has no effect

    }

    public void addItem(String item) {
        int index = objects.size();
        mIdMap.put(item, index);
    }

3 个答案:

答案 0 :(得分:1)

我通常会将项目添加到ArrayList中或修改适配器代码中的对象(在您的情况下为StableArrayAdapter),而不是像您所做的那样在适配器外部。但只要ArrayAdapter 之外的对象与StableArrayAdapter 中的列表共享相同的地址,这可能就没问题了。我怀疑它不是。

在您的情况下,请确保像arraylist.add("item 1")这样的代码将字符串添加到StableArrayAdapter中的ArrayList对象中。我再次怀疑它不是。

为了加快速度,请发布StableArrayAdapter的代码。如果读者必须下载代码,读者就不方便提供帮助。

新建议代码:

StableArrayAdapter 中,添加一个公共方法,如:

// This method is opposite of getItemId().
public void addItem(String item) {
    // Add the string into the objects
    objects.add(item);

    // size of objects should be added by one after add() above
    int index = objects.size();
    mIdMap.put(item, index);
}

在StableArrayAdapter之外:

listView.setAdapter(adapter);
listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);

// added the item and called notifyDataSetChanged();
adapter.addItem("item 1");
adapter.addItem("item 2");

adapter.notifyDataSetChanged();

注意:不要在arraylist上添加项目,而是调用StableArrayAdapter,对象适配器的方法。

更新1 :问题是 DynamicListView 类中的方法setCheeseList()和swapElements()不适用于添加项目动态。此外, StableArrayAdapter 中的addItem()也会更改。 我已经在我的项目中修复了这个问题,但这并不容易解释。所以我会尝试。

代码建议:

第1部分,FROM:

private void handleCellSwitch() {
...
   swapElements(mCheeseList, originalItem, getPositionForView(switchView));
   ((BaseAdapter) getAdapter()).notifyDataSetChanged();
...

TO:

private void handleCellSwitch() {
...
   // Swap the 2 items with animation for the dragNdrop feature
   final SwappableListAdapter adapter = (SwappableListAdapter) getAdapter();
   adapter.swap(originalItem, getPositionForView(switchView));
...

注意:

  • 我没有调用本地方法swapElements()来交换mCheeseList之间的值,而是调用swap类中实现的接口SwappableListAdapter的方法StableArrayAdapter()。
  • 基本上,我们的想法取决于在StableArrayAdapter
  • 中获取正确的数据

第2部分 接口代码SwappableListAdapter

public interface SwappableListAdapter {
        /**
         * Swaps between 2 items in the adapter, one is the mobile item, another is the selected item.
         * Method notifyDataSetChanged is called in the swap() when finished.
         * @param index1 The selected row view, dragged and to be moved.
         * @param index2 The row which moved due to the dragged row item.
         */
    public void swap(int index1, int index2);
}

注意:

  • 这是在DynamicListView类中创建的接口,因为这是将进行实际调用的类。
  • 这将修复编译器错误问题。

第3部分swap类中实现StableArrayAdapter()方法的代码。

public class StableArrayAdapter extends ArrayAdapter<String> implements DynamicListView.SwappableListAdapter {
   ...
   @Override
   public void swap(int indexOne, int indexTwo) {
      // Swap mIdMap object related to indexOne and indexTwo
      String item = getItem(indexOne);

      notifyDataSetChanged();
}

注意:

  • swap()需要工作。我的项目不使用 HashMap 进行交换,我不喜欢HashMap的当前实现(来自Google工程师)。我可能有时间修理它。也许你可以修复这个方法。希望你现在有了这个想法。
  • StableArrayAdapter类现在实现了接口SwappableListAdapter,并且有权覆盖swap()。
  • 接口的想法是适配器现在是存储数据的中心点!当前实现将数据存储在Adapter和DynamicListView中,而不应该是。

答案 1 :(得分:1)

Thanx一吨到@The Original Android

动态添加项目时所做的更改摘要。

StableArrayAdapter.java

添加了addItem方法

public void addItem(String item) {
    // Add the string into the objects
    objects.add(item);

    // size of objects should be added by one after add() above
    int index = objects.size();
    mIdMap.put(item, index);
}

<强> MainActivity.java

listView.setCheeseList(al);
listView.setAdapter(adapter);
listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);

// called addItem method inside MainActivity
adapter.addItem("item 1");
adapter.addItem("item 2");
adapter.addItem("item 3");
adapter.addItem("item 4");

adapter.notifyDataSetChanged();

<强> DynamicListView.java

更改
    private void handleCellSwitch() {
     ...   
       swapElements(mCheeseList, originalItem, getPositionForView(switchView));
       ((BaseAdapter) getAdapter()).notifyDataSetChanged();
     ...
    }

   private void handleCellSwitch() { 
    ...      
      final SwappableListAdapter adapter = (SwappableListAdapter) getAdapter();
      adapter.swap(mCheeseList,originalItem, getPositionForView(switchView)); // I still had to pass the arraylist   
    ...
    }

在DynamicListView.java中创建了一个接口

public interface SwappableListAdapter {    
    public void swap(int index1, int index2);
}

StableArrayAdapter.java实现SwappableListAdapter接口并覆盖交换方法

public class StableArrayAdapter extends ArrayAdapter<String> implements DynamicListView.SwappableListAdapter {

    @Override
    public void swap(ArrayList a,int index1, int index2) {

        Object temp = a.get(index1);
        a.set(index1, a.get(index2));
        a.set(index2, temp);

        notifyDataSetChanged();
    }
}

答案 2 :(得分:1)

这可能不是完全相同的问题,但它很相似,而且谷歌带领我来到这里。我的列表视图主要是有效的,但是有一系列动作可以使某些项目消失。之后单击它们会导致NullPointerException。

以下是重现错误的步骤:

  1. 将项目拖到顶部。
  2. 向上或向下拖动另一个项目。
  3. 顶部的项目将消失。
  4. 向上或向下拖动另一个项目。
  5. 顶部项目将重新出现。
  6. 如果您转到第2步,行为将继续
  7. 调试后,我发现我的StableArrayAdapter.getView()方法被调用了两次,仅用于列表顶部的空白项。这让我想到了这个问题Adapter getView is called multiple times with position 0 提到了一个动态的全高度&#34;。

    为了解决这个问题,我将DynamicListView的layout_height设置为&#34; wrap_content&#34;。