我正在尝试创建一个具有拖放功能的列表视图。我用谷歌搜索了谷歌的这个视频,向您展示了如何制作动态列表视图: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
我添加了我认为与问题最相关的代码,但如果有任何其他文件有助于查看,请告诉我,我可以将其添加进去。提前感谢。
答案 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