简体   繁体   English

滚动列表时具有错误状态项的ListView

[英]ListView with wrong status items when scrolling list

I'm having trouble with my ListView. 我在使用ListView时遇到麻烦。

ListView 列表显示

<ListView
    android:id="@+id/lvMyList"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:divider="@android:color/transparent"
    android:dividerHeight="5dp" >
</ListView>

I have a ListView that has a number of components in your adapter. 我有一个ListView,在您的适配器中有许多组件。 By clicking on a line, LinearLayout has an animation of expansion, becomes visible or already is visible hide (collapse). 通过单击一行,LinearLayout具有展开动画,变得可见或已经可见(隐藏)。

Items ListView (adapter xml) 项目ListView(适配器xml)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/llContainer"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginBottom="5dp"
    android:layout_marginTop="5dp"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/tvLocal"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="question"
        android:textColor="@color/app_gray"
        android:textSize="12sp" >
    </TextView>

    <TextView
        android:id="@+id/tvQuestion"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="question"
        android:textColor="@color/app_gray"
        android:textSize="12sp"
        android:textStyle="bold" >
    </TextView>

    <LinearLayout
        android:id="@+id/llContainerLikeDislike"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="5dp"
        android:layout_marginTop="5dp"
        android:orientation="vertical"
        android:visibility="gone" >

        <TextView
            android:id="@+id/tvAnswer"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="5dp"
            android:layout_marginBottom="5dp"
            android:textColor="@color/app_blue"
            android:textSize="12sp" />

        <LinearLayout
            android:id="@+id/llContainerButtons"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="5dp"
            android:layout_marginTop="5dp"
            android:orientation="horizontal" >

            <LinearLayout
                android:id="@+id/llLike"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="5dp"
                android:padding="5dp"
                android:clickable="true"
                android:gravity="center_horizontal"
                android:orientation="vertical" >

                <ImageView
                    android:id="@+id/ivLike"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:contentDescription="@null"
                    android:layout_margin="5dp"
                    android:src="@drawable/background_btn_like" />

                <TextView
                    android:id="@+id/tvHelped"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="Helped"
                    android:textColor="@color/app_gray"
                    android:textSize="12sp" >
                </TextView>

                <TextView
                    android:id="@+id/tvNumLike"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:textColor="@color/app_gray"
                    android:textSize="12sp" >
                </TextView>
            </LinearLayout>

            <LinearLayout
                android:id="@+id/llDisLike"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="5dp"
                android:padding="5dp"
                android:clickable="true"
                android:gravity="center_horizontal"
                android:orientation="vertical" >

                <ImageView
                    android:id="@+id/ivDisLike"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:contentDescription="@null"
                    android:layout_margin="5dp"
                    android:src="@drawable/background_btn_dislike" />

                <TextView
                    android:id="@+id/tvNotHelp"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="Not Help"
                    android:textColor="@color/app_gray"
                    android:textSize="12sp" >
                </TextView>

                <TextView
                    android:id="@+id/tvNumDisLike"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:textColor="@color/app_gray"
                    android:textSize="12sp" >
                </TextView>
            </LinearLayout>

        </LinearLayout>

    </LinearLayout>

</LinearLayout>

The problem is that (means that random mode) by extending a line, for example the first, another line also receives the event. 问题是(通过随机扩展一条线)(例如,第一条,另一条线)也接收到该事件。

Animation 动画

    /**
         * Expand animation
         * @param v : {@link View}
         */
        public static void expand(final View v, final ListView lv, final int position) {
            v.measure(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
            final int targetHeight = v.getMeasuredHeight();

            v.getLayoutParams().height = 0;
            v.setVisibility(View.VISIBLE);
            Animation a = new Animation()
            {
                @Override
                protected void applyTransformation(float interpolatedTime, Transformation t) {
                    v.getLayoutParams().height = interpolatedTime == 1
                            ? LayoutParams.WRAP_CONTENT
                            : (int)(targetHeight * interpolatedTime);
                    v.requestLayout();

                    //Moves the listview scroll so that the expanding area is visible.
                    lv.setSelectionFromTop(position, v.getLayoutParams().height);
                }

                @Override
                public boolean willChangeBounds() {
                    return true;
                }
            };

            // 1dp/ms
            a.setDuration((int)(targetHeight / v.getContext().getResources().getDisplayMetrics().density));
            v.startAnimation(a);
        }

        /**
         * Collapse animation
         * @param v : {@link View}
         */
        public static void collapse(final View v) {
            final int initialHeight = v.getMeasuredHeight();

            Animation a = new Animation()
            {
                @Override
                protected void applyTransformation(float interpolatedTime, Transformation t) {
                    if(interpolatedTime == 1){
                        v.setVisibility(View.GONE);
                    }else{
                        v.getLayoutParams().height = initialHeight - (int)(initialHeight * interpolatedTime);
                        v.requestLayout();
                    }
                }

                @Override
                public boolean willChangeBounds() {
                    return true;
                }
            };

            // 1dp/ms
            a.setDuration((int)(initialHeight / v.getContext().getResources().getDisplayMetrics().density));
            v.startAnimation(a);
        }

Using the debugging to verify whether the method is being called more than once, this method being called only once and receives the correct position where it received the click event. But visibly other line receives the event as well.

Adapter

public class QAAdapter extends ArrayAdapter<QA> implements Filterable {

    private List<QA>filteredData;

    private ArrayList<QA> arrayQA;
    private ViewHolder holder;
    private final LayoutInflater inflater;
    private Activity activity;

    public QAAdapter(Activity activity,
            ArrayList<QA> arrayQA) {
        super(activity, 0);

        this.inflater = (LayoutInflater) activity
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        this.arrayQA = arrayQA;
        this.filteredData = arrayQA; 
        this.activity = activity;
    }

    /**
     * Stores the visual components for better performance.
     */
    static class ViewHolder {
        private TextView tvLocal, tvQuestion, tvAnswer, tvNumLike, tvNumDisLike;
        private LinearLayout llContainer, llLike, llDisLike;
    }

    /**
     * Return the size of {@code arrayQA}.
     */
    @Override
    public int getCount() {
        return filteredData.size();
    }

    /**
     * Return {@link QA}.
     * @param position
     * @return {@link QA}
     */
    public QA getItemQa(int position) {
        return filteredData.get(position);
    }

    /**
     * Insert {@link QA} in the {@code arrayQA}.
     * @param qa: {@link QA}
     */
    public void addNewQA(final QA qa) {
        activity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                filteredData.add(qa);
                notifyDataSetChanged();
            }
        });
    }

    /**
     * Return the {@code id} of the {@link QA}.
     */
    @Override
    public long getItemId(int position) {
        return filteredData.get(position).getId();
    }

    /**
     * Return line of the {@link BaseAdapter}.
     */
    @Override
    public View getView(final int position, View cv, final ViewGroup parent) {
        View convertView = cv;

        final QA qa = filteredData.get(position);

        if (convertView == null) {
            convertView = inflater.inflate(R.layout.item_qa, parent, false);
            holder = new ViewHolder();

            Typeface tfLight = Typeface.createFromAsset(activity.getAssets(),
                    "fonts/Oswald-Light.ttf");

            Typeface tfBold = Typeface.createFromAsset(activity.getAssets(),
                    "fonts/Oswald-Bold.ttf");

            holder.tvLocal = (TextView) convertView
                    .findViewById(R.id.tvLocal);
            holder.tvLocal.setTypeface(tfLight);

            holder.tvQuestion = (TextView) convertView
                    .findViewById(R.id.tvQuestion);
            holder.tvQuestion.setTypeface(tfBold);

            holder.tvAnswer = (TextView) convertView
                    .findViewById(R.id.tvAnswer);
            holder.tvAnswer.setTypeface(tfLight);

            holder.tvNumLike = (TextView) convertView
                    .findViewById(R.id.tvNumLike);
            holder.tvNumLike.setTypeface(tfLight);

            holder.tvNumDisLike = (TextView) convertView
                    .findViewById(R.id.tvNumDisLike);
            holder.tvNumDisLike.setTypeface(tfLight);

            holder.llContainer = (LinearLayout) convertView.findViewById(R.id.llContainer);
            holder.llContainer.setTag(position);
            holder.llLike = (LinearLayout) convertView.findViewById(R.id.llLike);
            holder.llDisLike = (LinearLayout) convertView.findViewById(R.id.llDisLike);

            holder.llContainer.setOnClickListener(new View.OnClickListener() {

                @Override
                public void onClick(View v) {

                    int visibility = v.findViewById(R.id.llContainerLikeDislike).getVisibility();

                    if(visibility == View.GONE){
                        final int position2 = ((ListView) parent).getPositionForView(v);
                        expand(v.findViewById(R.id.llContainerLikeDislike), ((ListView) parent), position2);
                    } else {
                        collapse(v.findViewById(R.id.llContainerLikeDislike));
                    }

                    v.findViewById(R.id.llContainerLikeDislike).requestLayout();
                    notifyDataSetChanged();
                }
            });

            holder.llLike.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {

                    int value = (int) (qa.getUp_count() + 1);
                    qa.setUp_count(value);

                    ((LinearLayout) v).setEnabled(false);
                    ((LinearLayout) ((LinearLayout) v.getParent()).findViewById(R.id.llDisLike)).setEnabled(false);
                    ((ImageView) v.findViewById(R.id.ivLike)).setSelected(true);
                    ((TextView) v.findViewById(R.id.tvAjudou)).setTextColor(activity.getResources().getColor(R.color.app_blue));
                    ((TextView) v.findViewById(R.id.tvNumLike)).setTextColor(activity.getResources().getColor(R.color.app_blue));

                    notifyDataSetChanged();

                    MyAsyncTask asyncTask = new MyAsyncTask();
                    asyncTask.execute(URL);
                }
            });

            holder.llDisLike.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {

                    int value = (int) (qa.getDown_count() + 1);
                    qa.setDown_count(value);

                    ((LinearLayout) v).setEnabled(false);
                    ((LinearLayout) ((LinearLayout) v.getParent()).findViewById(R.id.llLike)).setEnabled(false);
                    ((ImageView) v.findViewById(R.id.ivDisLike)).setSelected(true);
                    ((TextView) v.findViewById(R.id.tvNaoAjudou)).setTextColor(activity.getResources().getColor(R.color.app_red));
                    ((TextView) v.findViewById(R.id.tvNumDisLike)).setTextColor(activity.getResources().getColor(R.color.app_red));

                    notifyDataSetChanged();

                    MyAsyncTask asyncTask = new MyAsyncTask();
                    asyncTask.execute(URL);
                }
            });

            convertView.setTag(holder);

        } else {
            holder = (ViewHolder) convertView.getTag();
        }

        String name = qa.getName();
        String city = qa.getCity();
        String state = qa.getState();

        if(qa.getName().equals(null) || qa.getName().equals("null")) {
            name = " ";
        }

        if(qa.getCity().equals(null) || qa.getCity().equals("null")) {
            city = " ";
        }

        if(qa.getState().equals(null) || qa.getState().equals("null")) {
            state = " ";
        }

        holder.tvLocal.setText(activity.getString(R.string.local_item_pergunta, name, city, state));

        holder.tvQuestion.setText(qa.getQuestion());
        holder.tvAnswer.setText(qa.getAnswer());

        holder.tvNumLike.setText(String.valueOf(qa.getUp_count()));
        holder.tvNumDisLike.setText(String.valueOf(qa.getDown_count()));

        return convertView;
    }

    /**
     * Realizes filter of the {@link QA}.
     */
    public Filter getFilter() {

        Filter mFilter = new Filter() {

            @SuppressLint("DefaultLocale")
            @Override
            protected FilterResults performFiltering(CharSequence constraint) {

                String filterString = constraint.toString().toLowerCase();

                FilterResults results = new FilterResults();

                final List<QA> list = arrayQA;

                int count = list.size();
                final ArrayList<QA> nlist = new ArrayList<QA>(count);

                QA filterable;

                for (int i = 0; i < count; i++) {
                    filterable = list.get(i);
                    String questionFiltred = filterable.getQuestion();
                    String anwserFiltred = filterable.getAnswer();

                    if (questionFiltred.toLowerCase().contains(filterString) || anwserFiltred.toLowerCase().contains(filterString)) {
                        nlist.add(filterable);
                    }

                }

                results.values = nlist;
                results.count = nlist.size();

                return results;
            }

            @SuppressWarnings("unchecked")
            @Override
            protected void publishResults(CharSequence constraint,
                    final FilterResults results) {
                filteredData = (ArrayList<QA>) results.values;
                notifyDataSetChanged();
            }

        };

        return mFilter;
    }

    /**
     * {@link AsyncTask} for the send data like or dislike.
     */
    public class MyAsyncTask extends AsyncTask<String, Integer, Boolean>{...}

}

My Class QA 我的班级质量检查

/**
 * Represents entity questions and answers.
 */
public class QA {

    private int id;
    private String question, answer, answer_at, state, city, name;
    public enum state { like, dislike };
    private long up_votes_count, down_votes_count;
    /**
     * @return the question
     */
    public String getQuestion() {
        return question;
    }
    /**
     * @param question the question to set
     */
    public void setQuestion(String question) {
        this.question = question;
    }
    /**
     * @return the answer
     */
    public String getAnswer() {
        return answer;
    }
    /**
     * @param answer the answer to set
     */
    public void setAnswer(String answer) {
        this.answer = answer;
    }
    /**
     * @return the answer_at
     */
    public String getAnswer_at() {
        return answer_at;
    }
    /**
     * @param answer_at the answer_at to set
     */
    public void setAnswer_at(String answer_at) {
        this.answer_at = answer_at;
    }
    /**
     * @return the up_count
     */
    public long getUp_count() {
        return up_votes_count;
    }
    /**
     * @param up_count the up_count to set
     */
    public void setUp_count(long up_count) {
        this.up_votes_count = up_count;
    }
    /**
     * @return the down_count
     */
    public long getDown_count() {
        return down_votes_count;
    }
    /**
     * @param down_count the down_count to set
     */
    public void setDown_count(long down_count) {
        this.down_votes_count = down_count;
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    /**
     * @return the state
     */
    public String getState() {
        return state;
    }
    /**
     * @param state the state to set
     */
    public void setState(String state) {
        this.state = state;
    }
    /**
     * @return the city
     */
    public String getCity() {
        return city;
    }
    /**
     * @param city the city to set
     */
    public void setCity(String city) {
        this.city = city;
    }
    /**
     * @return the name
     */
    public String getName() {
        return name;
    }
    /**
     * @param name the name to set
     */
    public void setName(String name) {
        this.name = name;
    }


}

Using the debugging to verify whether the method is being called more than once, this method being called only once and receives the correct position where it received the click event. 使用调试来验证该方法是否被多次调用,该方法仅被调用一次,并在接收到click事件的位置接收到正确的位置。 But visibly other line receives the event as well. 但显然其他线路也接收该事件。 Where can I be missing or what should I change to fix this? 我在哪里可能会丢失,或者应该更改以解决此问题?

EDIT1: 编辑1:

Problem only occurs in the scroll of the ListView! 问题仅出现在ListView的滚动中!

The problem with your code is the listview-item-recycling which does not handle subitem-visiblity: 您的代码的问题是listview-item-recycling,它不能处理subitem-visiblity:

  public View getView(final int position, View cv, final ViewGroup parent)  {
    ...
    if (convertView == null) {
       // create new item here
       ...
    } else {
      // recycle convertView where parts of are visible or not
      // make shure that llContainer starts invisible
      ViewHolder holder = (ViewHolder) convertView.getTag();
      holder.llContainer.setVisibility(View.GONE);        
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM