簡體   English   中英

滾動列表時具有錯誤狀態項的ListView

[英]ListView with wrong status items when scrolling list

我在使用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>{...}

}

我的班級質量檢查

/**
 * 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事件的位置接收到正確的位置。 但顯然其他線路也接收該事件。 我在哪里可能會丟失,或者應該更改以解決此問題?

編輯1:

問題僅出現在ListView的滾動中!

您的代碼的問題是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