通过按同一适配器内的按钮更改 ArrayAdapter 内的 TextView 的文本

Changing text of a TextView that's inside an ArrayAdapter by pressing a Button within the same adapter

这是我在 Whosebug 中的第一个问题。 如果我做错了什么,请纠正我。 所以..我们开始吧:

我正在尝试在 ArrayAdapter 中创建一个 Button 的 onClickListener,它会在同一布局中更改 TextView 的文本。但实际情况是:当我单击按钮时,它会更改多个 TextView 的文本。 是这样的:如果我按下列表的第一个按钮,它会更改 5h、9th、13th 的文本......为什么会这样?

我想要一个 onClickListener 来更改位于相同布局上的 TextView 的文本。

PS:当我说 "Button" 它实际上是 "ImageView"

适配器代码:

public class ProductAdapter extends ArrayAdapter<Produtc> {

public ProductAdapter (Context context, ArrayList<Product> products) {
    super(context, 0, products);
}



@Override
public View getView (final int position, View convertView, ViewGroup parent) {

    final ViewHolder viewHolder;
    final Product product = getItem(position);

    if (convertView == null) {
        convertView = LayoutInflater.from(getContext()).inflate(R.layout.layout_sliders, parent, false);

        viewHolder = new ViewHolder();
        viewHolder.textViewProductIndex = (TextView) convertView.findViewById(R.id.textViewIndex);
        viewHolder.textViewProductName = (TextView) convertView.findViewById(R.id.textViewProductName);
        viewHolder.textViewQuantity = (TextView) convertView.findViewById(R.id.textViewQuantity);
        viewHolder.imageViewADD = (ImageView) convertView.findViewById(R.id.buttonAdd);
        viewHolder.imageViewFILL = (ImageView) convertView.findViewById(R.id.buttonFill);
        viewHolder.imageViewCheck = (ImageView) convertView.findViewById(R.id.buttonCheck);

        convertView.setTag(viewHolder);
    } else {
        viewHolder = (ViewHolder) convertView.getTag();
    }



    if (produto != null) {

        viewHolder.textViewProductIndex.setText(product.getProductIndex());
        viewHolder.textViewProductName.setText(product.getProductName());

        viewHolder.imageViewADD.setTag(position);
        viewHolder.imageViewFILL.setTag(position);
        viewHolder.imageViewCheck.setTag(position);
        viewHolder.textViewProductIndex.setTag(position);
        viewHolder.textViewProductName.setTag(position);
        viewHolder.textViewQuantity.setTag(position);

        viewHolder.imageViewADD.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                viewHolder.textViewQuantity.setText("TESTING");
            }
        });

    }
    return convertView;
}

class ViewHolder {
    private TextView textViewProductIndex;
    private TextView textViewProductName;
    private TextView textViewQuantity;
    private ImageView imageViewADD;
    private ImageView imageViewFILL;
    private ImageView imageViewCheck;
}}

其他疑惑:

-我真正需要传递给 setTag() 的是什么?

-我应该在 ListView 的 onItemClickListener 上的 setApdapter 之后处理 clickListeners 吗?

欢迎使用 Whosebug!

发生这种情况是因为列表视图正在重用视图以提高性能。所以第 1、5、9 个视图实际上是相同的。当您执行 viewHolder = (ViewHolder) convertView.getTag(); 时,您正在重用现有视图而不是创建新视图,这对性能有好处。您还避免了 findViewById 电话。

要解决您的问题,您应该在每次调用 getView() 时设置 quantity 文本。类似于 viewHolder.textViewQuantity.setText(product.getQuantity())。这将覆盖当前文本。

至于setTag,它用于存储带有View的任意对象,以便稍后获取。这用于实现 ViewHolder 模式,但也有其他用途。您不需要在视图持有者的每个 属性 上调用 setTag,您只需要 convertView.setTag(viewHolder);.

我会这样做:

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;

public class ProductAdapter extends ArrayAdapter<Product> {

    private Context mContext;
    private ArrayList<Product> mProducts;

    public ProductAdapter(Context context, ArrayList<Product> products) {
        super(context, 0, products);
        this.mContext = context;
        this.mProducts = products;
    }


    public class ViewHolder {
        private final TextView textViewProductIndex;
        private final TextView textViewProductName;
        private final TextView textViewQuantity;
        private final ImageView imageViewADD;
        private final ImageView imageViewFILL;
        private final ImageView imageViewCheck;

        public ViewHolder(View v, final int position) {
            this.mTextViewProductIndex = (TextView) v.findViewById(R.id.textViewIndex);
            this.mTextViewProductName = (TextView) v.findViewById(R.id.textViewProductName);
            this.mTextViewQuantity = (TextView) v.findViewById(R.id.textViewQuantity);
            this.mImageViewADD = (ImageView) v.findViewById(R.id.buttonAdd);
            this.mImageViewFILL = (ImageView) v.findViewById(R.id.buttonFill);
            this.mImageViewCheck = (ImageView) v.findViewById(R.id.buttonCheck);
        }
    }

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {

        View rowView = convertView;

        if (rowView == null) {
            LayoutInflater inflater = mContext.getLayoutInflater();
            rowView = inflater.inflate(R.layout.layout_sliders, parent);
            ViewHolder viewHolder = new ViewHolder(rowView, position);
            rowView.setTag(viewHolder);
        }

        final ViewHolder holder = (ViewHolder) rowView.getTag();

        holder.textViewProductIndex.setText(mProducts.get(position).getProductIndex());
        holder.textViewProductName.setText(mProducts.get(position).getProductName());
        holder.textViewQuantity.setText(mProducts.get(position).getQuantity());

        holder.imageViewADD.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                holder.textViewQuantity.setText("TESTING");
            }
        });

        return rowView;
    }
}

您在这里提出了三个问题。让我试着这样解释一下。

A) 关于视图的可重用性。

假设您的数组中有 100 种产品。但是,在任何时间点,屏幕上只显示 5 倍的产品。所以只有 5x 布局被列表视图膨胀。它们在您滚动时被重复使用(注意我通过忽略缓存机制稍微简化了这一点)。

如果您将第一个产品的“第一个视图”的颜色设置为橙色,会发生什么情况。到第 6 个产品重新使用“第一个视图”时,它仍然是橙色的。

您需要为所有 100x 产品设置一个 属性 布尔值,这样您就可以根据该 属性 设置视图的颜色,每次它们进入视图时。

B) setTag 是可选的。但如果您看到问题 C) 的答案,它会很有用。

C) 通常有两种方法可以为您的列表视图设置onclick。 - 第一种方法是在每次出现时为每个视图设置一个 onclick。因此,如果您从第一个产品滚动到第 100 个产品,您将设置 100 次。然后,当您向上滚动时,您需要为每个视图创建一个 onclick(),因为它们会在您滚动时被覆盖。

第二种方法是创建共享答题器。您可以将其设置到每个视图中。因此实际上只创建了 1 个监听器实例

final OnClickListener listener = new OnClickListener() { 
    void onClick(View view) { 
        Product product = (Product)view.getTag();
        // do somethign
    } 
}

试试这个

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

public class ProductAdapter extends ArrayAdapter<Product> {

    private final LayoutInflater inflater;
    private Context mContext;
    private ArrayList<Product> mProducts;

    final String[] switch = new String[2] { "on", "off" };

    public ProductAdapter(Context context, ArrayList<Product> products) {
        super(context, 0, products);
        this.mContext = context;
        this.mProducts = products;

        inflater = mContext.getLayoutInflater();
    }

    public class ViewHolder {
        private final TextView textViewProductIndex;
        private final TextView textViewProductName;
        private final TextView textViewQuantity;
        private final ImageView imageViewADD;
        private final ImageView imageViewFILL;
        private final ImageView imageViewCheck;

        private byte selected = 0;

        public ViewHolder(View view) {
            this.mTextViewProductIndex = (TextView) v.findViewById(R.id.textViewIndex);
            this.mTextViewProductName = (TextView) v.findViewById(R.id.textViewProductName);
            this.mTextViewQuantity = (TextView) v.findViewById(R.id.textViewQuantity);
            this.mImageViewADD = (ImageView) v.findViewById(R.id.buttonAdd);
            this.mImageViewFILL = (ImageView) v.findViewById(R.id.buttonFill);
            this.mImageViewCheck = (ImageView) v.findViewById(R.id.buttonCheck);
            view.setTag(this);
        }
    }

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        if (convertView == null) {
            convertView = inflater.inflate(R.layout.layout_sliders, parent);
            new ViewHolder(convertView);
        }

        final ViewHolder holder = (ViewHolder) convertView.getTag();

        holder.textViewProductIndex.setText(mProducts.get(position).getProductIndex());
        holder.textViewProductName.setText(mProducts.get(position).getProductName());
        holder.imageViewADD.setOnClickListener(listener);

        holder.mTextViewQuantity(switch[holder.selected]);

        return convertView;
    }

    final OnClickListener listener = new OnClickListener() {
        void onClick(View view) {           
            final ViewHolder holder = (ViewHolder) convertView.getTag();
            holder.selected ^= 1;
            holder.mTextViewQuantity.setText(switch[holder.selected]);
        }       
    }
}

另一种方法是在列表视图的ItemClickListener 中设置。但是,与上面的第二种方式相比,灵活性较低。

希望对您有所帮助