android - Getview 参数 "convertview"在新的 "position"参数上不为空

标签 android listview android-arrayadapter convertview

我将 ArrayAdapter 用于我自己的对象类型列表(只有一种类型),我为用户提供了创建更多项目的选项(从而为这些项目创建了更多 View )。在某些时候,getView 发送了一个新的“position”索引和一个非空的“convertView”。然后它在最后一个位置显示第一个 View 。在那之后,当 ScrollView 时,所有的 View 都会混淆。我假设这意味着我以不应该的方式操纵了 View ,但我只是看不到在哪里。这是一些代码:

    @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);
}

如果您认为我应该上传更多方法以使事情更清楚,请告诉我。

最佳答案

一个 friend 向我解释了这个问题,现在它似乎起作用了。基本上ListView只持有少量 View ,一直循环使用。在我的例子中,我有一个 Nexus 4,所以它似乎总共有 7 个 View ,因为第 8 个总是开始引起麻烦的那个。我在 getView() 中缺少的是一个条件,用于检查 ArrayAdapter 中当前项目的位置和 ID 之间的相关性。现在它的工作原理如下:

@Override
public View getView(int position, @Nullable 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;
}

关于android - Getview 参数 "convertview"在新的 "position"参数上不为空,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18323803/

相关文章:

c# - 所选 ListView 项目的数量?

android - 需要在 android 中自定义 ListView 示例

Android 像 Chrome 一样创建编辑文本动画

java - ByteArray 到intentService 中的byte[]?

android - Proguard 和 Dalvik 错误代码 1

php - 如何在android中将动态数据从一个 Activity 发送到另一个 Activity

android - 如何确保特定 xml 中的每个字符串都被翻译成 Android 中的另一个 xml?有什么好的做法吗?

android - section indexer get section for position 返回 0

android - 带有奇怪文本的微调下拉菜单

Android - ListView 中的 ListView 不会展开以显示所有项目