拖放ListView吃其他行Android

时间:2015-04-09 14:13:32

标签: java android listview drag-and-drop

我正在尝试创建一个具有拖放功能的列表视图。我用谷歌搜索了谷歌的这个视频,向您展示了如何制作动态列表视图:https://www.youtube.com/watch?v=_BZIvjMgH-Q

我尽可能地将代码复制到我的项目中,但我发现了一个小错误。当我有一个包含2个相同单词的列表时,它会搞砸。我很好奇,并将Google代码更改为包含所有相同名称项的列表视图,它也破坏了他们的代码。以下是我在概述错误时发布的YouTube视频的链接:https://youtu.be/t7ghuUU80KY

有没有人对如何修复此错误有任何建议?这是我的代码:

item_row.xml

<?xml version="1.0" encoding="utf-8"?>

    <TextView
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="New Text"
        android:textSize="30sp"
        android:id="@+id/itemText"
        android:paddingLeft="15dp"
        android:paddingRight="15dp"
        android:singleLine="true"
        android:layout_alignParentLeft="true"/>

NoteActivity.java

public class NoteActivity extends ActionBarActivity {

    private final static String TAG = NoteActivity.class.getSimpleName();
    public final static int SLASHED = 1;
    public final static int UNSLASHED = 0;
    private static final StrikethroughSpan STRIKE_THROUGH_SPAN = new StrikethroughSpan();
    ItemsArrayAdapter mItemsArrayAdapter;
    FinishedItemsArrayAdapter mFinishedItemsArrayAdapter;
    EditText mNewItemText;
    DynamicListView mItemsListView;
    ListView mFinishedItemsListView;
    ArrayList<String> mItems;
    ArrayList<String> mFinishedItems;
    //    FloatingActionButton fab;
    private Uri noteUri;
    public ArrayList<String> slashes;

    @Override
    protected void onCreate(Bundle bundle) {
        super.onCreate(bundle);
        setContentView(R.layout.activity_note);
        slashes = new ArrayList<>();

        mFinishedItems = new ArrayList<>();
        mFinishedItemsArrayAdapter = new FinishedItemsArrayAdapter(this, mFinishedItems, true);
        mFinishedItemsListView = (ListView) findViewById(R.id.finishedItems);
        mFinishedItemsListView.setAdapter(mFinishedItemsArrayAdapter);
        mFinishedItemsListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                TextView item = (TextView) view.findViewById(R.id.itemText);
                String text = item.getText().toString();
                mFinishedItems.remove(text);
                mItems.add(text);
                mFinishedItemsArrayAdapter.notifyDataSetChanged();
                mItemsArrayAdapter.notifyDataSetChanged();
            }
        });

        mItems = new ArrayList<String>();
        mItemsArrayAdapter = new ItemsArrayAdapter(this, mItems, false);
        mItemsListView = (DynamicListView) findViewById(R.id.itemsListView);
        mItemsListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
        mItemsListView.setAdapter(mItemsArrayAdapter);
        mItemsListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                TextView item = (TextView) view.findViewById(R.id.itemText);
                String text = item.getText().toString();
                mItems.remove(text);
                mFinishedItems.add(text);
                mFinishedItemsArrayAdapter.notifyDataSetChanged();
                mItemsArrayAdapter.notifyDataSetChanged();
            }
        });

        Bundle extras = getIntent().getExtras();

        // check from the saved Instance
        noteUri = (bundle == null) ? null : (Uri) bundle
                .getParcelable(NoteContentProvider.CONTENT_ITEM_TYPE);

        // Or passed from the other activity
        if (extras != null) {
            noteUri = extras
                    .getParcelable(NoteContentProvider.CONTENT_ITEM_TYPE);

            fillData(noteUri);

        }

        mItemsListView.setCheeseList(mItems);

    }

    private void fillData(Uri uri) {

        String[] projection = {NoteTable.COLUMN_ITEMS, NoteTable.COLUMN_SLASHED};
        Cursor cursor = null;
        try {
            cursor = getContentResolver().query(uri, projection, null, null,
                    null);
        } catch (NullPointerException e) {
            Log.e(TAG, "NullPointerException caught: ", e);
        }
        if (cursor != null) {
            cursor.moveToFirst();

            String sItems = cursor.getString(cursor
                    .getColumnIndexOrThrow(NoteTable.COLUMN_ITEMS));

            String sSlashes = cursor.getString(cursor.getColumnIndexOrThrow(NoteTable.COLUMN_SLASHED));

            try {
                JSONArray jsonArray = new JSONArray(sItems);
//                for (int i = 0; i < jsonArray.length(); i++) {
//                    mItems.add((String) jsonArray.get(i));
//                }
                JSONArray slashesJsonArray = new JSONArray(sSlashes);
                for (int i = 0; i < slashesJsonArray.length(); i++) {
                    slashes.add("" + slashesJsonArray.get(i));
                    if(slashesJsonArray.get(i).equals(NoteActivity.UNSLASHED)){
                        mItems.add((String) jsonArray.get(i));
                    }
                    else{
                        mFinishedItems.add((String) jsonArray.get(i));
                    }
                }
                mFinishedItemsArrayAdapter.notifyDataSetChanged();
                mItemsArrayAdapter.notifyDataSetChanged();
            } catch (JSONException ignored) {
            }

            // always close the cursor
            cursor.close();
        }

    }

    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        saveState();
        outState.putParcelable(NoteContentProvider.CONTENT_ITEM_TYPE, noteUri);
    }

    protected void onPause() {
        super.onPause();
        saveState();
    }

    private void saveState() {
        String note = new JSONArray(mItems).toString();
        ArrayList<Integer> slashes = new ArrayList<>();

//        for (int i = 0; i < mItemsListView.getChildCount(); i++) {
//            View row = mItemsListView.getChildAt(i);
//            TextView textView = (TextView) row.findViewById(R.id.itemText);
//
//            if (17 == textView.getPaintFlags()) {
//                slashes.add(NoteActivity.SLASHED);
//            } else {
//                slashes.add(NoteActivity.UNSLASHED);
//            }
//        }

        for (int i = 0; i < mItemsListView.getChildCount(); i++) {
            slashes.add(NoteActivity.UNSLASHED);
        }
        for (int i = 0; i < mFinishedItemsListView.getChildCount(); i++) {
            slashes.add(NoteActivity.UNSLASHED);
        }

        String sSlashes = new JSONArray(slashes).toString();

        // only save if either summary or description
        // is available

        if (mItems.isEmpty()) {
            return;
        }

        ContentValues values = new ContentValues();
        values.put(NoteTable.COLUMN_ITEMS, note);
        values.put(NoteTable.COLUMN_SLASHED, sSlashes);

        if (noteUri == null) {
            noteUri = getContentResolver().insert(NoteContentProvider.CONTENT_URI, values);
        } else {
            getContentResolver().update(noteUri, values, null, null);
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds mItems to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_note, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.addItem) {
            item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
                @Override
                public boolean onMenuItemClick(MenuItem item) {
                    addItem();
                    return false;
                }
            });
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    public void addItem() {

        if (mItems.size() < 100) {
            getDialog().show();
        } else {
            AlertDialog.Builder builder = new AlertDialog.Builder(this);
            builder.setTitle("Max Items")
                    .setMessage("You have reached the maximum " +
                            "number of items (100) one note can hold.")
                    .setPositiveButton("OK", null);
            builder.show();
        }

    }

    public AlertDialog.Builder getDialog() {
        LayoutInflater li = LayoutInflater.from(this);
        LinearLayout newNoteBaseLayout = (LinearLayout) li.inflate(R.layout.new_item_dialog, null);

        mNewItemText = (EditText) newNoteBaseLayout.getChildAt(0);

        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                mItems.add(mNewItemText.getText().toString());
                mItemsArrayAdapter.notifyDataSetChanged();
            }
        });
        builder.setNegativeButton("Cancel", null)
                .setTitle("New Item");

        builder.setView(newNoteBaseLayout);
        return builder;
    }

    public void deleteItem(int position) {
        mItems.remove(position);
        slashes.remove(position);
        mItemsArrayAdapter.notifyDataSetChanged();
    }

    public void editItem(final int position) {
        AlertDialog.Builder builder = getDialog();
        mNewItemText.setText(mItems.get(position));
        builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                mItems.set(position, mNewItemText.getText().toString());
                mItemsArrayAdapter.notifyDataSetChanged();
            }
        });
        builder.show();
    }

    public void uncheckAll(View view) {
        for (int i = 0; i < mItemsListView.getChildCount(); i++) {
            View row = mItemsListView.getChildAt(i);
            TextView textView = (TextView) row.findViewById(R.id.itemText);

            textView.setPaintFlags(textView.getPaintFlags() & (~Paint.STRIKE_THRU_TEXT_FLAG));

        }

    }
}

ItemArrayAdapter.java

public class ItemsArrayAdapter extends ArrayAdapter<String> {

    public static final String TAG = ItemsArrayAdapter.class.getSimpleName();
    Context mContext;
    ArrayList<String> mArrayList;
    boolean wantsSlash;
    NoteActivity mNoteActivity;

    final int INVALID_ID = -1;

    HashMap<String, Integer> mIdMap = new HashMap<String, Integer>();

    public ItemsArrayAdapter
            (NoteActivity context, ArrayList<String> arrayList, boolean slashes){
        super(context, R.layout.item_row,arrayList);
        mContext = context;
        mArrayList = arrayList;
        mNoteActivity = context;
        wantsSlash = slashes;
        for (int i = 0; i < arrayList.size(); ++i) {
            mIdMap.put(arrayList.get(i), i);
        }
    }

    public View getView(final int position, View convertView, ViewGroup parent) {
        ViewHolder holder;

        if(convertView == null){
            convertView = LayoutInflater.from(mContext).inflate(R.layout.item_row, parent, false);
            holder = new ViewHolder();

            holder.itemName = (TextView)convertView.findViewById(R.id.itemText);

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

//            holder.delete = (ImageView)convertView.findViewById(R.id.delete_item);
//            holder.edit = (ImageView)convertView.findViewById(R.id.edit_item);
            convertView.setTag(holder);
        }
        else{
            holder = (ViewHolder) convertView.getTag();
        }

        holder.itemName.setText(mArrayList.get(position));
        if(wantsSlash){
            holder.itemName.setPaintFlags(Paint.STRIKE_THRU_TEXT_FLAG);
        }
//        holder.delete.setOnClickListener(new View.OnClickListener() {
//            @Override
//            public void onClick(View v) {
//                mNoteActivity.deleteItem(position);
//            }
//        });
//        holder.edit.setOnClickListener(new View.OnClickListener() {
//            @Override
//            public void onClick(View v) {
//                mNoteActivity.editItem(position);
//            }
//        });


        return convertView;
    }

    private static class ViewHolder {
        TextView itemName;
        ImageView edit;
        ImageView delete;
    }

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

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

}

DynamicListView.java

我达到了粘贴代码的最大字符数限制,所以如果你想看看代码是什么,这里有一个指向pastebin的链接:http://pastebin.com/x41RKfEU

我添加了我认为与问题最相关的代码,但如果有任何其他文件有助于查看,请告诉我,我可以将其添加进去。提前感谢。

1 个答案:

答案 0 :(得分:1)

DynamicListview强烈依赖于适配器的getItemId()。正如您在适配器中看到的那样,这些ID存储在mIdMap上

它在构造函数

上填充
  for (int i = 0; i < arrayList.size(); ++i) {
        mIdMap.put(arrayList.get(i), i);
    }

这是什么意思? 如果arrayList在索引1和4处包含apple。在for循环结束时。 地图将只包含一个关键字“apple”的条目:4。 这意味着getItemId(1)和getItemId(4)将返回id 4。

这是潜在的问题。如果您的列表可以包含相同的字符串,则必须更正此点。

拥有一个用户可以订购的列表却很奇怪但却无法区分某些项目。

最佳解决方案改变初始字符串列表。和数字项目。 {“apple”,“apple”}变为{“apple 1”,“apple 2”}。或者根据您的应用中的名称或任何有意义的内容对它们进行分组。

你是否希望绝对拥有奇怪的行为。 (用户无法区分但重新排序的不同项目)。您必须从模型中添加更多信息,并根据此信息创建ID