通过按同一适配器内的按钮更改 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 中设置。但是,与上面的第二种方式相比,灵活性较低。
希望对您有所帮助
这是我在 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 中设置。但是,与上面的第二种方式相比,灵活性较低。
希望对您有所帮助