【问题标题】:How to remove items (randomly) from a list and maintaining the ListView如何从列表中(随机)删除项目并维护 ListView
【发布时间】:2019-08-12 09:12:15
【问题描述】:

有一个 ListView 显示 Arraylist 的项目,这些项目由用户动态添加(通过 EditText 和确认按钮)。在 Listview 的每个 item 中,都有一个 remove ImageView,它从 List 中删除相应的 item(因此也从 ListView 中删除)。

目标是让 ListView 上的移除按钮(ImageView)正常工作。

目前,当将每个项目添加到列表时,我正在为每个项目添加一个 onClickListener。 onClickListener 执行一个方法,该方法使用 list.remove(int i) 函数,然后 notifyDataSetChanged() 来更新 ListView。

[[主要活动]]

public class MainActivity extends AppCompatActivity {

    // setting up member variables
    ArrayList<String> list = new ArrayList<>();
    ArrayAdapter<String> arrayAdapter;
    TextInputLayout textInputLayout;
    ListView listView;
    Button addNewListItem;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initialize();

    }

    private void initialize() {
        // binding listView, arrayadapter & button to the ones from the layout, setting up the array adapter

        // Listview & adapted
        listView = findViewById(R.id.listView_Items);
        arrayAdapter = new ArrayAdapter<>(this, R.layout.listview_item, R.id.listView_item_text, list);
        listView.setAdapter(arrayAdapter);

        // buttons
        addNewListItem = findViewById(R.id.button_addItem);

        // setting up the onclick listener for addItem, de/increasePeople, calculate
        addNewListItem.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                addItem();
            }
        });

        // setting up the onclick listener for the ok button in the soft keyboard for the
        // edit text field when adding new items
        textInputLayout = findViewById(R.id.TextInputLayout_itemToAdd);
        textInputLayout.getEditText().setOnEditorActionListener(new TextView.OnEditorActionListener() {
            @Override
            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
                if (actionId == EditorInfo.IME_ACTION_DONE) {
                    addItem();
                    return true;
                }
                return false;
            }
        });
    }

    private void addItem() {
        textInputLayout = findViewById(R.id.TextInputLayout_itemToAdd);
        String inputItem = textInputLayout.getEditText().getText().toString().trim();

        // checking, if text was entered in the edit text and then adding it to the list
        if (inputItem.isEmpty()) {
            textInputLayout.setError("Can't be empty");
        } else {
            textInputLayout.setError(null);
            list.add(inputItem);

            // Adding an onClickListener to an item of the listview requires the listView to
            // finish redrawing. OnLayoutChangeListener fires as soon as the listview has finished
            // redrawing the listview.
            // The layoutchangelistener is immediately removed and the onclicklistener is added.

            listView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
                @Override
                public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
                    listView.removeOnLayoutChangeListener(this);

                    // getting the child count of the listview to get the index of the item, that
                    // just has been added
                    int addedItemId = listView.getChildCount();
                    Toast.makeText(MainActivity.this,"addedItemid: " + addedItemId,Toast.LENGTH_SHORT).show();
                    View addedItemChildView = listView.getChildAt(addedItemId-1);

                    // initializing the imageview to which the onclicklistener has to be added
                    ImageView removeImage = addedItemChildView.findViewById(R.id.ImageView_removeItem);

                    // onclicklistener is an anonymous class and therefore requires
                    // the index to be final. initializing a final int with the index
                    final int itemId = addedItemId-1;
                    removeImage.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            Log.d("Logging","itemId: " + itemId);
                            removeListItem(itemId);
                        }
                    });
                }
            });
            arrayAdapter.notifyDataSetChanged();
        }
    }

    private void removeListItem(int listItemId) {
        list.remove(listItemId);
        arrayAdapter.notifyDataSetChanged();
    }
}

[[ACTIVITY_MAIN]]

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    android:id="@+id/linearLayout_mainLayout"
    android:layout_height="match_parent"
    android:layout_width="match_parent"
    android:orientation="vertical"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <android.support.design.widget.TextInputLayout
        android:id="@+id/TextInputLayout_itemToAdd"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:errorEnabled="true">

        <android.support.design.widget.TextInputEditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="@string/hint_enterItem"
            android:inputType="text" />
    </android.support.design.widget.TextInputLayout>

    <Button
        android:id="@+id/button_addItem"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/button_addItem" />

    <ListView
        android:id="@+id/listView_Items"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />


</LinearLayout>

[[LISTVIEW_ITEM]]

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="horizontal"
    android:layout_marginTop="8dp"
    android:layout_marginBottom="8dp"
    android:layout_marginStart="8dp"
    android:layout_marginLeft="8dp"
    android:layout_marginEnd="8dp"
    android:layout_marginRight="8dp">


    <ImageView
        android:id="@+id/ImageView_removeItem"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="4"
        android:clickable="true"

        app:srcCompat="@android:drawable/ic_menu_delete" />

    <TextView
        android:id="@+id/listView_item_text"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginStart="16dp"
        android:layout_marginLeft="16dp"
        android:layout_marginEnd="8dp"
        android:layout_marginRight="8dp"
        android:layout_weight="2"
        android:gravity="center_vertical"
        tools:text="test" />

    <android.support.design.widget.TextInputLayout
        android:id="@+id/listView_item_edit"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginStart="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginEnd="16dp"
        android:layout_marginRight="16dp"
        android:layout_weight="3"
        android:gravity="center"
        app:errorEnabled="false">

        <android.support.design.widget.TextInputEditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="Enter Value"
            android:inputType="numberDecimal" />
    </android.support.design.widget.TextInputLayout>



</LinearLayout>

如您所见,当将 onClickListener 添加到 ImageView 时,itemid 将根据列表中当前的项目数量(减 1)添加。 如果我们有 3 个项目:“i0”、“i1”和“i2”,“i1”将被删除,“i2”上具有删除方法的 onClickListener 具有旧索引。 "i2" 的索引在 ArrayList 中已自动减少,但 remove-function 参数保持不变。

如何解决这个问题?

谢谢你:)

(我希望我没有删除任何必要的代码,因为我试图只留下重要的部分)

【问题讨论】:

    标签: android list listview onclicklistener dynamically-generated


    【解决方案1】:

    可以通过覆盖标准适配器的 getView() 来访问 ListView 项内的视图。试试这个[使用 setTag() 和 getTag()]:

        arrayAdapter = new ArrayAdapter(this, R.layout.listview_item, R.id.listView_item_text, list){
            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                View itemView = super.getView(position, convertView, parent);
                ImageView removeImage = itemView.findViewById(R.id.ImageView_removeItem);
    
                removeImage.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        int pos = (int)v.getTag();
                        Log.d("Logging","itemId: " + pos);
                        remove(pos);
                        notifyDataSetChanged();
                    }
                });
    
                removeImage.setTag(position);
                return itemView;
            }
        };
    

    希望有帮助!

    另一个答案[使用final]:

        arrayAdapter = new ArrayAdapter(this, R.layout.listview_item, R.id.listView_item_text, list){
        @Override
        public View getView(final int position, View convertView, ViewGroup parent) {
            View itemView = super.getView(position, convertView, parent);
            ImageView removeImage = itemView.findViewById(R.id.ImageView_removeItem);
    
            removeImage.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    //int pos = (int)v.getTag();
                    Log.d("Logging","itemId: " + position);
                    remove(position);
                    notifyDataSetChanged();
                }
            });
    
            //removeImage.setTag(position);
            return itemView;
        }
    };
    

    【讨论】:

    • 哇,非常感谢!它完全按预期工作。如果您不介意回答以下问题,只是为了确保我正确理解了所有内容: (1) int pos 被描述为适配器数据集中项目的位置。换句话说,它正是列表中的位置,我们已经为 arrayadapter 提供了? (2) 添加或删除项目时,被覆盖的方法 getView() 被多次调用(我放入 log.d())。这是为什么呢?
    • (1) 我总是使用 setTag() 和 getTag() 将位置传递给适配器内的侦听器,这是为了避免将 position 作为最终结果 [尽管它适用于您的案子]。我对这篇文章的回答:stackoverflow.com/questions/56875819/…
    • (2) getView() 是适配器用于填充其项目视图的方法,因此在必须显示项目/数据时调用它。它被调用的次数几乎与屏幕上的项目相同。如果您的 ListView 比屏幕长,当您滚动时,还会调用 getView() 来填充新显示的项目。您可以搜索可能有帮助的自定义适配器教程!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-14
    • 1970-01-01
    • 1970-01-01
    • 2011-06-16
    • 2016-12-12
    相关资源
    最近更新 更多