typeof programmer
typeof programmer

Reputation: 1609

How ListView's recycling works

I have a listView in my project, I want to get background color changed when I click listItem. But when I click the one row, it changes many lines.

Here is my code for this function:

 public View getView(int pos, View view, ViewGroup parent) {
        mActivity = (Activity) this.getContext();
        ListViewHolder holder;


        if (view == null) {
            LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            view = inflater.inflate(R.layout.portfolio_row, null);

            LinearLayout textViewWrap = (LinearLayout) view.findViewById(R.id.portfolio_text_wrap);
            TextView text = (TextView) view.findViewById(R.id.portfolio_symbol);
            holder = new ListViewHolder(textViewWrap, text);

        } else
            holder = (ListViewHolder) view.getTag();





        PortfolioItem portfolioItem = getItem(pos);
}

But when I click the one row, it will change many lines.

I got the system.out.println for pos. I am supposed to get It should be 0 1 2 3 4 5 6 7 8 9 (# stands for position). What I get is a cycle now like this: 0 1 2 3 0 1 2 3 0 1

So if I click one , it will change all the same position. But if I don't click , just pull the listView down, the position are correct.Like 0----9.

Here is my code for item click:

public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        list = (ListView) root.findViewById(R.id.~~~);
        list.setAdapter(adapter);
        list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            public void onItemClick(AdapterView<?> parentAdapter, View view, int position, long id) {

                toggle(view, position);
            }
        });
}

What I want is getting the absolute position for it in listView. Please help me on this. Thanks!

UPDATES: Thanks for everyone's kindly answer. But I think you may misunderstand my question.

  1. the getView changes the position. It means when you want to change number 9 row, it cannot be changed , because I only have 0 1 2 3

  2. getView() and onCreateView() are in different class. The System.out.println("pos" + pos); in getView cannot get correct position.

    The correct way should be 1 to last item. But when I click it , the number will be a cycle. the cycle number are how many rows the screen can display.

It is just like this link How ListView's recycling mechanism works

And I want to click to get only one and correct position. Thanks a lot.

Here is layout.xml:

 <LinearLayout a:orientation="vertical"
                  a:layout_width="fill_parent"
                  a:layout_height="fill_parent">

        <LinearLayout a:orientation="horizontal" a:layout_width="fill_parent" a:layout_height="wrap_content"
                      a:background="@color/onSelected">
            <TextView a:text="@string/1" a:layout_weight="1" a:layout_width="fill_parent"
                      a:layout_height="fill_parent" a:layout_margin="10dp" a:textStyle="bold" a:id="@+id/0"/>
            <TextView a:text="@string/2" a:layout_weight="1" a:layout_width="fill_parent"
                      a:layout_height="fill_parent" a:gravity="right" a:layout_margin="10dp" a:textStyle="bold"/>
            <TextView a:text="@string/3" a:layout_weight="1" a:layout_width="fill_parent"
                      a:layout_height="fill_parent" a:gravity="right" a:layout_margin="10dp" a:textStyle="bold"/>
            <TextView a:text="@string/4" a:layout_weight="1" a:layout_width="fill_parent"
                      a:layout_height="fill_parent" a:gravity="right" a:layout_margin="10dp" a:textStyle="bold"/>
            <TextView a:text="@string/5" a:layout_weight="1" a:layout_width="fill_parent"
                      a:layout_height="fill_parent" a:gravity="right" a:layout_margin="10dp" a:textStyle="bold"/>
            <TextView a:text="@string/6" a:layout_weight="1" a:layout_width="fill_parent"
                      a:layout_height="fill_parent" a:gravity="right" a:layout_margin="10dp" a:textStyle="bold"/>
            <TextView a:text="@string/7" a:layout_weight="1" a:layout_width="fill_parent"
                      a:layout_height="fill_parent" a:gravity="right" a:layout_margin="10dp" a:textStyle="bold"/>
        </LinearLayout>
        <android.support.v4.widget.SwipeRefreshLayout a:layout_width="fill_parent"
                                                      a:layout_height="fill_parent"
                                                      a:id="@+id/portfolios">
            <ListView a:layout_width="fill_parent" a:layout_height="fill_parent" a:id="@+id/8" />
        </android.support.v4.widget.SwipeRefreshLayout>
    </LinearLayout>

UPDATES2: Here is listViewHolder:

public class ListViewHolder {
    private LinearLayout textViewWrap;
    private TextView textView;


    public ListViewHolder(LinearLayout textViewWrap, TextView textView) {
        super();
        this.textViewWrap = textViewWrap;
        this.textView = textView;
    }

    public TextView getTextView() {
        return textView;
    }

    public void setTextView(TextView textView) {
        this.textView = textView;
    }

    public LinearLayout getTextViewWrap() {
        return textViewWrap;
    }

    public void setTextViewWrap(LinearLayout textViewWrap) {
        this.textViewWrap = textViewWrap;
    }
}

Here set the fragment

class fragment{

        list = (ListView) root.findViewById(R.id.123);
        list.setAdapter(adapter);

}

In fragment class I have listItemClickListener and in the adapter I have the getView function

Upvotes: 1

Views: 243

Answers (3)

Urchin
Urchin

Reputation: 474

list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            public void onItemClick(AdapterView<?> parentAdapter, View view, int position, long id) {
                adapter.changeVisable(view, position);   


public void changeVisable(View view, int position) {
        if (mLastView != null && mLastPosition != position) {
            ListViewHolder holder = (ListViewHolder) mLastView.getTag();
            switch (holder.getTxt().getVisibility()) {
                case View.VISIBLE:
                    holder.getTxt().setVisibility(View.GONE);
                    mLastVisibility = View.GONE;
                    break;
                default:
                    break;
            }
        }
        mLastPosition = position;
        mLastView = view;
        ListViewHolder holder = (ListViewHolder) view.getTag();
        switch (holder.getTxt().getVisibility()) {
            case View.GONE:
                holder.getTxt().setVisibility(View.VISIBLE);
                mLastVisibility = View.VISIBLE;
                break;
            case View.VISIBLE:
                holder.getTxt().setVisibility(View.GONE);
                mLastVisibility = View.GONE;
                break;
        }
    }

works perfect

Upvotes: 1

Urchin
Urchin

Reputation: 474

I have an idea , whether can use

    final int firstListItemPosition = ((ListView) parent).getFirstVisiblePosition();
    final int lastListItemPosition = ((ListView) parent).getLastVisiblePosition();

two function to calculate the correct position. any one can do that?

And the Android scroll function can get the correct position information ? Anyone can explain how it works?

And this http://android.amberfog.com/?p=296 give the example how scroll work. But when click one line do addition function , does not work well.

I think another way to solve this problem use bindview to update the view use hashmap to store the ID information, if the ID exist, change other row with same ID back. If click the row again, remove the ID from the hashmap

Upvotes: 1

user3487063
user3487063

Reputation: 3692

int selected;
list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            public void onItemClick(AdapterView<?> parentAdapter, View view, int position, long id) {
selected=position;
adapter.notifyDataSetChanged();
                toggle(view, position);
            }
        });

in your getView:

public View getView(int pos, View view, ViewGroup parent) {
....
...
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            view = inflater.inflate(R.layout.portfolio_row, null);
if(pos==selected){
view.setBackgroundResource("your color");
.....


}

you need to setTag for each view, you missed that:

if (view == null) {
            LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            view = inflater.inflate(R.layout.portfolio_row, null);

            LinearLayout textViewWrap = (LinearLayout) view.findViewById(R.id.portfolio_text_wrap);
            TextView text = (TextView) view.findViewById(R.id.portfolio_symbol);
            holder = new ListViewHolder(textViewWrap, text);
view.setTag(holder);
        } 

Upvotes: 0

Related Questions