java - 拖放 ListView 吃其他行 Android

标签 java android listview drag-and-drop

我正在尝试创建一个具有拖放功能的 ListView 。我在谷歌上搜索了一下,发现谷歌的这段视频向您展示了如何制作 DynamicListView:https://www.youtube.com/watch?v=_BZIvjMgH-Q

我尽我所能将代码复制到我的项目中,但我发现了一个小错误。当我有一个包含 2 个相同单词的列表时,它会变得一团糟。我很好奇并更改了 Google 代码以具有包含所有相同名称项目的 ListView ,这也破坏了他们的代码。这是我制作的概述错误的 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

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

最佳答案

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

在构造函数上填充

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

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

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

有一个用户可以订购但不能区分某些项目的列表是很奇怪的。

最佳解决方案是更改初始字符串列表。和编号项目。 {"apple", "apple"} 变成 {"apple 1", "apple 2"}。或者按名称或在您的应用中有意义的任何内容对它们进行分组。

你绝对想拥有奇怪的行为吗? (用户无法区分但重新订购的不同项目)。您将必须从您的模型中添加更多信息并根据这些信息创建 ID

关于java - 拖放 ListView 吃其他行 Android,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29540989/

相关文章:

android - 尽管有 ViewHolder、LazyLoader 和简单的布局,Listview 仍然卡顿

c# - 自动滚动到 WinRT 应用程序中的 ListView 底部

java - 是否存在扩展不允许空元素的 List 的 native JAVA 集合类?

java - 从Oracle触发器调用Java程序

android - android 中的 YoutubeService 类错误

android - Android 的 EventBus 与 RxJava

java - Files.walk.filter 和 Files.find 有什么区别?

java - 想要隐藏/删除屏幕菜单栏

android - 具有折叠工具栏和 ImageView 的视差 TabLayout

android - 从数据库中删除后刷新 ListView