You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Android ScrollView中通过代码添加可点击自定义项

解决动态添加ScrollView商品项及点击事件的问题

核心解决思路:

  • 用数据类绑定每个商品的信息,避免依赖视图ID
  • 动态创建商品项视图时直接为其设置点击监听器
  • 将ScrollView内部改为垂直LinearLayout作为容器,统一管理所有商品项

1. 优化布局文件

主页面布局(activity_main.xml)

将ScrollView内的示例项替换为垂直LinearLayout容器,用于承载所有动态添加的商品项:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <Button
            android:id="@+id/popUpAddItem"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Add Your Item"
            tools:ignore="MissingConstraints" />

        <ScrollView
            android:id="@+id/scrollViewItems"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <!-- 商品项容器 -->
            <LinearLayout
                android:id="@+id/itemContainer"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical" />

        </ScrollView>
    </LinearLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

商品项布局(item_goods.xml)

抽离单独的商品项布局,保证样式统一且可复用:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:clickable="true"
    android:orientation="horizontal"
    android:padding="8dp"
    android:background="?attr/selectableItemBackground">

    <TextView
        android:id="@+id/tvItemName"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:textSize="16sp" />

    <TextView
        android:id="@+id/tvItemQuantity"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:textSize="16sp"
        android:gravity="center" />

    <TextView
        android:id="@+id/tvItemPrice"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:textSize="16sp"
        android:gravity="end" />

</LinearLayout>

2. 创建商品数据类(Item.java)

用实体类存储商品信息,实现数据与视图的解耦:

package com.example.myapplication;

public class Item {
    private String name;
    private int quantity;
    private float price;

    public Item(String name, int quantity, float price) {
        this.name = name;
        this.quantity = quantity;
        this.price = price;
    }

    // Getter & Setter
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public int getQuantity() { return quantity; }
    public void setQuantity(int quantity) { this.quantity = quantity; }
    public float getPrice() { return price; }
    public void setPrice(float price) { this.price = price; }
}

3. 修改弹窗类(CreateCustomPopUp.java)

新增重载构造方法,支持新增/修改两种场景:

package com.example.myapplication;

import android.app.Activity;
import android.app.Dialog;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

public class CreateCustomPopUp extends Dialog {
    private EditText etName, etQuantity, etPrice;
    private Button btnValidation;
    private Item currentItem;

    // 修改商品场景
    public CreateCustomPopUp(Activity activity, Item item) {
        this(activity);
        this.currentItem = item;
        // 填充现有数据
        etName.setText(item.getName());
        etQuantity.setText(String.valueOf(item.getQuantity()));
        etPrice.setText(String.valueOf(item.getPrice()));
    }

    // 新增商品场景
    public CreateCustomPopUp(Activity activity) {
        super(activity, androidx.appcompat.R.style.Theme_AppCompat_Dialog);
        setContentView(R.layout.dialog_popup);

        etName = findViewById(R.id.itemName);
        etQuantity = findViewById(R.id.itemQuantity);
        etPrice = findViewById(R.id.itemPrice);
        btnValidation = findViewById(R.id.validationButton);

        btnValidation.setOnClickListener(v -> {
            try {
                String name = etName.getText().toString().trim();
                int quantity = Integer.parseInt(etQuantity.getText().toString().trim());
                float price = Float.parseFloat(etPrice.getText().toString().trim());

                if (currentItem != null) {
                    // 更新现有商品数据
                    currentItem.setName(name);
                    currentItem.setQuantity(quantity);
                    currentItem.setPrice(price);
                } else {
                    // 创建新商品
                    currentItem = new Item(name, quantity, price);
                }
                dismiss();
            } catch (NumberFormatException e) {
                e.printStackTrace();
                // 可在此添加输入格式错误提示
            }
        });
    }

    public void build() { show(); }
    public Item getCurrentItem() { return currentItem; }
}

4. 修改主活动代码(MainActivity.java)

实现动态添加、点击修改的完整逻辑:

package com.example.myapplication;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {
    private LinearLayout itemContainer;
    private List<Item> itemList = new ArrayList<>();
    private LayoutInflater inflater;

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

        inflater = LayoutInflater.from(this);
        itemContainer = findViewById(R.id.itemContainer);
        Button addItemBtn = findViewById(R.id.popUpAddItem);

        // 添加商品按钮事件
        addItemBtn.setOnClickListener(v -> showAddItemDialog());

        // 添加测试商品
        addItemToContainer(new Item("Item1", 1, 10.0f));
    }

    // 显示新增商品弹窗
    private void showAddItemDialog() {
        CreateCustomPopUp popUp = new CreateCustomPopUp(this);
        popUp.build();
        popUp.setOnDismissListener(dialog -> {
            Item newItem = popUp.getCurrentItem();
            if (newItem != null) {
                itemList.add(newItem);
                addItemToContainer(newItem);
            }
        });
    }

    // 显示修改商品弹窗
    private void showEditItemDialog(Item item, View itemView) {
        CreateCustomPopUp popUp = new CreateCustomPopUp(this, item);
        popUp.build();
        popUp.setOnDismissListener(dialog -> {
            // 更新视图显示
            TextView tvName = itemView.findViewById(R.id.tvItemName);
            TextView tvQt = itemView.findViewById(R.id.tvItemQuantity);
            TextView tvPrice = itemView.findViewById(R.id.tvItemPrice);

            tvName.setText(item.getName());
            tvQt.setText(String.valueOf(item.getQuantity()));
            tvPrice.setText(String.valueOf(item.getPrice()));
        });
    }

    // 将商品添加到容器
    private void addItemToContainer(Item item) {
        View itemView = inflater.inflate(R.layout.item_goods, itemContainer, false);

        // 设置商品数据
        TextView tvName = itemView.findViewById(R.id.tvItemName);
        TextView tvQt = itemView.findViewById(R.id.tvItemQuantity);
        TextView tvPrice = itemView.findViewById(R.id.tvItemPrice);

        tvName.setText(item.getName());
        tvQt.setText(String.valueOf(item.getQuantity()));
        tvPrice.setText(String.valueOf(item.getPrice()));

        // 设置点击修改事件
        itemView.setOnClickListener(v -> showEditItemDialog(item, itemView));

        itemContainer.addView(itemView);
    }
}

关键说明

  1. 无需动态设置ID:通过绑定Item对象与视图,点击时直接操作对应数据,完全规避动态ID的问题。
  2. 数据驱动视图:所有视图显示由Item数据决定,修改数据后直接更新视图即可,逻辑清晰。
  3. 点击事件即时绑定:创建商品项视图时直接设置OnClickListener,点击触发修改弹窗并传入对应数据与视图,实现实时更新。

内容的提问来源于stack exchange,提问作者Nehril Is'O'ruz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 00:15:42