Skip to content Skip to sidebar Skip to footer

How To Track The Position Of Items While Scrolling In A Long Custom Listview

The data which is displayed from the database in the form of listview (here listview with headers having disabled onClick of headers). I tried to display the description of the sel

Solution 1:

All you need to do is move the setting of OnClickListener on holder.textview.

The problem here is:

: Since you set the OnClickListener in the if (convertView == null) block, it isn't changed when convertView is not null. So, the position used in AlertDialog is the one you set when convertViewwas null.

: Solution is to set the OnClickListener every time a position is processed - we don't care if the view is recycled or not!!! We need to reset the OnClickListener to reflect the correct/current position.

: Although, we never set an OnClickListener on holder.textview when item is TYPE_SEPARATOR, its safe to remove the OnClickListener using holder.textview.setOnClickListener(null).

Try the updated code below. I hope the logic here is quite clear.

//Adapter ClassprivateclassMyCustomAdapterextendsBaseAdapter {

    ....
    ....     
    public View getView(finalint position, View convertView, ViewGroup parent) {
        ViewHolderholder=null;
        inttype= getItemViewType(position);
        System.out.println("getView " + position + " " + convertView + " type = " + type);
        if (convertView == null) {
            holder = newViewHolder();
            switch (type) {
            case TYPE_ITEM:
                convertView = mInflater.inflate(R.layout.activity_main1, null);
                holder.textView = (TextView)convertView.findViewById(R.id.text);
                break;
            case TYPE_SEPARATOR:
                convertView = mInflater.inflate(R.layout.activity_main2, null);
                holder.textView = (TextView)convertView.findViewById(R.id.textSeparator);
                break;
            }
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder)convertView.getTag();
        }
        holder.textView.setText(mData.get(position));

        // We set the OnClickListener here because it is unique to every// item. Although views can be recycled & reused, an OnClickListener cannot be.if (type == TYPE_ITEM) {
            holder.textView.setOnClickListener(newView.OnClickListener() {
                    @OverridepublicvoidonClick(View v) {
                        AlertDialog.Builderx=newAlertDialog.Builder(
                                temp);
                        Log.v("position",""+position);
                               x.setIcon(R.drawable.ic_launcher)
                                .setTitle(q.get(position-1).getAS_name())
                                .setMessage(q.get(position-1).getDesc_art())
                                .setCancelable(true)
                                .setPositiveButton("OK",
                                        newDialogInterface.OnClickListener() {
                                            @OverridepublicvoidonClick(DialogInterface arg,
                                                    int arg1) {

                                            }
                                        });
                        AlertDialoga= x.create();
                        a.show();
                    }
              });
        } else {
            holder.textview.setOnClickListener(null);
        }   

        return convertView;
    }

    ....
    ....

}

Edit:

Wrapper class (can be implemented as an inner class of MainActivity1 or independently):

publicclassContentWrapper {

    privateString mItem, mItemDescription;

    publicContentWrapper(String item, String itemDescription) {
        mItem = item;
        mItemDescription = itemDescription;
    }

    publicStringgetItem() {
        return mItem;
    }

    publicStringgetItemDescription() {
        return mItemDescription;
    }
}

Your data-setup will also change:

@Override
publicvoidonCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    DBAdapter db = DBAdapter.getDBAdapter(getApplicationContext());
    if (!db.checkDatabase()) 
    {
        db.createDatabase(getApplicationContext());
    }
    db.openDatabase();

    q = db.getData();

    mAdapter = new MyCustomAdapter();

    // mAdapter.addSeparatorItem(q.get(0).getA_name());// First separator item// No description
    mAdapter.addSeparatorItem(new ContentWrapper(q.get(0).getA_name(), null));

    // mAdapter.addItem(q.get(0).getAS_name());// First TYPE_ITEM// Pass the description
    mAdapter.addItem(new ContentWrapper(q.get(0).getAS_name(), q.get(0).getDesc_art()));


    for (int i = 1; i < 460; i++) {

        if (!(q.get(i).getA_name().trim().equals(q.get(i-1).getA_name().trim()))) {
            // mAdapter.addSeparatorItem(q.get(i).getA_name());
            mAdapter.addSeparatorItem(new ContentWrapper(q.get(i).getA_name(), null));
            c++;
        }

        // mAdapter.addItem(q.get(i).getAS_name());
        mAdapter.addItem(new ContentWrapper(q.get(i).getAS_name(), q.get(i).getDesc_art()));
    }

    setListAdapter(mAdapter);        
}

Next, we make changes to the adapter:

// private ArrayList<String> mData = new ArrayList<String>();
private ArrayList<ContentWrapper> mData = new ArrayList<ContentWrapper>();

The add* methods

publicvoidaddItem(ContentWrapper value) {
    mData.add(value);
    notifyDataSetChanged();
}

publicvoidaddSeparatorItem(ContentWrapper value) {
    mData.add(value);
    // save separator position
    mSeparatorsSet.add(mData.size() - 1);
    notifyDataSetChanged();
}

public ContentWrapper getItem(int position) {
    return mData.get(position);
}

The getView(...) method:

@Overridepublic View getView(finalint position, View convertView, ViewGroup parent) {
    ....
    ....

    holder.textView.setText(mData.get(position).getItem());

    if (type == TYPE_ITEM) {
        holder.textView.setOnClickListener(newView.OnClickListener() {
            @OverridepublicvoidonClick(View v) {
                AlertDialog.Builderx=newAlertDialog.Builder(temp);
                Log.v("position",""+position);
                       x.setIcon(R.drawable.ic_launcher)

                        // .setTitle(q.get(position-count).getAS_name())
                        .setTitle(mData.get(position).getItem())

                        // .setMessage(q.get(position-count).getDesc_art())
                        .setMessage(mData.get(position).getItemDescription())

                        .setCancelable(true)
                        .setPositiveButton("OK",
                                newDialogInterface.OnClickListener() {
                                    @OverridepublicvoidonClick(DialogInterface arg,
                                            int arg1) {
                                    }
                                });
                 AlertDialoga= x.create();
                 a.show();
             }
         });
    } else {
        holder.textView.setOnClickListener(null);
    }
}

And that's about it.

[I] think we should implement notifyDataSetChanged or onScroll, onScrollStateChanged methods.

notifyDataSetChanged() is used to tell the adapter that the underlying data has changed and thus a refresh is required. For example, if description for an item changes, you would update that item in mData and call notifyDataSetChanged(). But in your case (and from what your code tells me), your data is initialized before you set the adapter using - setListAdapter(mAdapter). So, calls to notifyDataSetChanged() inside the add* methods are not even required. Calling notifyDataSetChanged() before attaching an adapter to a listview does nothing.

onScroll and onScrollChanged are meant for a different purpose. For example, say that you show a Go To Top of the List button when the user scroll past the 50th item - and hide it when they scroll up the 50th position. In your case, the problem was that you were trying to get data from two different sources(mData, q) and there were issues with synchronization. Nothing else.

Solution 2:

You can detect the scroll position easily and smooth by putting onScrollListener to your ListvView in your Acvivity. That contains two basic methods: onScroll and onScrollStateChanged.

EDIT

OnScrollListener has wide range of usage. This is OnScrollListener, which detects end of scroll and loads more data. Popular load-more feature.

mListView.setOnScrollListener(newOnScrollListener() {

                    @OverridepublicvoidonScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
                            int totalItemCount) {
                        if(mListView.getRefreshableView().getCount()!=0&&mListView.getRefreshableView().getCount()>0&&mAdapter.getCount()!=0){
                        if (mListView.getRefreshableView().getLastVisiblePosition() == mListView.getRefreshableView().getAdapter().getCount() - 1
                                && mListView.getRefreshableView()
                                .getChildAt(mListView.getRefreshableView().getChildCount() - 1)
                                .getBottom() <= mListView.getRefreshableView().getHeight()) {


                            if(SplashScreen.countie  == mAdapter.getCount()){
                                if(footie.isShown()) {
                                mListView.getRefreshableView().removeFooterView(footie);    
                                }
                            }

                            else{
                                if(loading!=true&&dontupdate==false){



                                    updateMoreData();
                                    }

                                    else{}
                            }
                        }
                    }

                    }
                    @OverridepublicvoidonScrollStateChanged(AbsListView view,
                            int scrollState) {
                        //the int scrollState is what are you looking for                           if (SCROLL_STATE_TOUCH_SCROLL == scrollState) {
                            ViewcurrentFocus= getActivity().getCurrentFocus();
                            if(currentFocus != null) {
                                currentFocus.clearFocus();
                            }
                        }



                    }

                });

If you want to get the scroll position use onScrollStateChanged method. The int scrollState in code below is actually what you want. You can do whatever you want with it.

BTW This was just a example of usage of OnScrollListener but what you have to do is just set it without inner setting (in my case load more feature) but just use onScrollStateChanged and its int.

hope it helps!

Post a Comment for "How To Track The Position Of Items While Scrolling In A Long Custom Listview"