滚动列表时ListView包含错误的状态项

时间:2015-07-28 14:40:35

标签: android listview adapter

我的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>

我有一个ListView,它在你的适配器中有许多组件。通过单击一行,LinearLayout具有一个扩展动画,变为可见或已经可见隐藏(折叠)。

项目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>

问题在于(意味着随机模式)通过扩展一条线,例如第一条线,另一条线也接收该事件。

动画

    /**
         * 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>{...}

}

我的班级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;
    }


}

使用调试来验证是否多次调用该方法,此方法仅被调用一次并在接收到click事件的位置接收正确的位置。但显然其他线路也接受了这一事件。 我可以在哪里找不到或者我应该改变什么来解决这个问题?

EDIT1:

问题只出现在ListView的滚动中!

1 个答案:

答案 0 :(得分:0)

你的代码的问题是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);        
    }