我正在使用ArrayAdapter获取我自己的对象类型列表(只有一种类型),并且我为用户提供了创建更多项目的选项(从而为这些项目创建更多视图)。在某些时候,getView发送了一个带有非null“convertView”的新“位置”索引。然后它显示最后一个位置的第一个视图。之后,当滚动视图时,所有内容都会混淆。我假设这意味着我以不应该的方式操纵视图,但我只是看不到。这是一些代码:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View v;
PreviewItemHolder holder = null;
// Initialize view if convertview is null
if (convertView == null) {
v = newView(parent, position);
}
// Populate from previously saved holder
else {
// Use previous item if not null
v = convertView;
}
// Populate if the holder is null (newly inflated view) OR
// if current view's holder's flag is true and requires populating
if ((holder == null) || (holder.readPopulateFlag())) {
bindView(position, v);
}
return v;
}
private View newView(ViewGroup parent, int position) {
// Getting view somehow...
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View inflatedView = inflater.inflate(R.layout.preview_element_set, parent, false);
PreviewItemHolder holder = new PreviewItemHolder();
holder.set = (Set) mSets.get(position);
holder.previewElementHolders = new ArrayList<PreviewElementHolder>();
holder.expandArea = (View) inflatedView.findViewById(R.id.expandArea);
holder.repetitionsLabel = (TextView) inflatedView.findViewById(R.id.previewRepetitionsInput);
holder.endlessInput = (CheckBox) inflatedView.findViewById(R.id.previewSetEndlessInput);
holder.nameLabel = (TextView) inflatedView.findViewById(R.id.previewSetNameLabel);
holder.commentInput = (EditText) inflatedView.findViewById(R.id.previewSetCommentInput);
holder.soundInput = (EditText) inflatedView.findViewById(R.id.previewSetSoundInput);
holder.addElementButton = (Button) inflatedView.findViewById(R.id.previewSetAddElements);
holder.expand = (View) inflatedView.findViewById(R.id.infoArea);
holder.collapse = (View) inflatedView.findViewById(R.id.collapse);
final int setsLength = holder.set.getElements().size();
for (int i = 0; i < setsLength; i++) {
AElement currElement = holder.set.getElements().get(i);
// Creating new element holder according to the type
if (currElement instanceof Rest) {
holder.previewElementHolders.add(new PreviewRestHolder());
}
else if (currElement instanceof TimeExercise) {
holder.previewElementHolders.add(new PreviewTimeExerciseHolder());
}
else if (currElement instanceof RepetitionExercise) {
holder.previewElementHolders.add(new PreviewRepetitionExerciseHolder());
}
View currLayout = inflateElement(currElement, inflater, i, holder.previewElementHolders.get(i));
// Add the child before the hairline, collapse image and the add
// button
// (3 last children of the expandArea view
((ViewGroup) holder.expandArea).addView(currLayout, ((ViewGroup) holder.expandArea).getChildCount() - CHILDREN_INDEX_AFTER_PHASES_LABEL);
}
inflatedView.setTag(holder);
return inflatedView;
}
private void bindView(int position, View inflatedView) {
final PreviewItemHolder holder = (PreviewItemHolder) inflatedView.getTag();
holder.set.setId(position);
holder.endlessInput.setChecked(holder.set.getEndless());
holder.soundInput.setText(holder.set.getSound());
holder.nameLabel.setText(holder.set.getName());
holder.commentInput.setText(holder.set.getComment());
// Make sure there is a name. If none, put default
if (holder.nameLabel.getText().equals("")) {
holder.nameLabel.setText(R.string.default_set_name);
}
// Set repetitions value according to the endless flag
if (holder.set.getEndless()) {
holder.repetitionsLabel.setText(R.string.infinity);
}
else {
holder.repetitionsLabel.setText(String.valueOf(holder.set.getRepetitions()));
}
// Set click listeners
holder.endlessInput.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
// Save endless flag
holder.set.setEndless(isChecked);
// If an endless set - Dropset
if (isChecked) {
holder.repetitionsLabel.setText(R.string.infinity);
}
else {
// Regular set
holder.repetitionsLabel.setText(String.valueOf(holder.set.getRepetitions()));
}
hideShowRepsWeights(holder);
}
});
holder.repetitionsLabel.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
NumericDialog instance = NumericDialog.newInstance(holder, holder.set, NumericDialog.INTEGER_MODE, Consts.SET_REPETITIONS_METHOD_NAME);
instance.show(((Activity) getContext()).getFragmentManager(), null);
}
});
holder.nameLabel.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// Setting flag to true to allow populating this view
holder.rePopulateFlag = true;
SetNameDialog instance = SetNameDialog.newInstance(holder.set);
instance.show(((Activity) getContext()).getFragmentManager(), null);
}
});
holder.commentInput.setOnFocusChangeListener(new OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (!hasFocus) {
// After focus is lost, save the text into the set
holder.set.setComment(holder.commentInput.getText().toString());
}
}
});
// TODO Change that into a dialog that allows selection of sounds
holder.soundInput.setOnFocusChangeListener(new OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (!hasFocus) {
// After focus is lost, save the text into the set
holder.set.setSound(holder.soundInput.getText().toString());
}
}
});
holder.expand.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// Change visibility - Show expandArea and its data
holder.expandArea.setVisibility(View.VISIBLE);
holder.expand.setVisibility(View.GONE);
holder.collapse.setVisibility(View.VISIBLE);
}
});
holder.collapse.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// Change visibility - Hide expandArea and its data
holder.expandArea.setVisibility(View.GONE);
holder.collapse.setVisibility(View.GONE);
holder.expand.setVisibility(View.VISIBLE);
}
});
holder.addElementButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
AddElementDialog instance = AddElementDialog.newInstance(holder);
instance.show(((Activity) getContext()).getFragmentManager(), null);
}
});
// Populate elements
for (PreviewElementHolder elementHolder : holder.previewElementHolders) {
populateElement(elementHolder, holder);
}
// Finally hide/show if needed - Should this be put somewere else?
hideShowRepsWeights(holder);
}
如果您认为我应该上传更多方法以使事情更清楚,请告诉我。
答案 0 :(得分:15)
一位朋友向我解释了这个问题,现在似乎有效。基本上ListView只保存少量视图并一直循环使用它们。在我的情况下,我有一个Nexus 4,所以它似乎总共有7个视图,因为第8个总是那个开始造成麻烦的人。我在getView()中缺少的是检查ArrayAdapter中当前项的位置和ID之间的相关性的条件。以下是它的工作原理:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View v;
PreviewItemHolder holder = null;
// Initialize view if convertview is null
if (convertView == null) {
v = newView(parent, position);
}
// Populate from previously saved holder
else {
// If position and id of set do not match, this view needs to be re-created, not recycled
if (((PreviewItemHolder) convertView.getTag()).set.getId() != position) {
v = newView(parent, position);
}
else {
// Use previous item if not null
v = convertView;
// Get holder
holder = (PreviewItemHolder) v.getTag();
}
}
// Populate if the holder is null (newly inflated view) OR
// if current view's holder's flag is true and requires populating
if ((holder == null) || (holder.readPopulateFlag())) {
bindView(position, v);
}
return v;
}
答案 1 :(得分:1)
您需要致电bindView()
始终。想法或重用如下。如果convertView
为null,则创建并初始化新视图。如果convertView
不为空,则您可以使用此视图并将转换为新视图,这意味着您使用bindView()
实例调用convertView
。
结帐this Javadoc了解详情。
答案 2 :(得分:0)
当你有几种类型的应该回收的视图时,你必须通过实现方法告诉列表视图你有多少种类型
SELECT *
, CAST(NULL as NVARCHAR(100)) as NewColumn1
, CAST(NULL as INT) as NewColumn2
INTO B
FROM A
WHERE 1=0