如何滚动时在相当长的自定义列表视图跟踪项目的位置自定义、视图、位置、项目

2023-09-05 23:26:29 作者:Fedad 悲痛

这是从数据库列表视图(这里的ListView具有头残疾人的onClick头)的形式显示的数据。

The data which is displayed from the database in the form of listview (here listview with headers having disabled onClick of headers).

我试图从位置 getView显示所选项目的说明()。这份名单是非常大的,因此动态分配的观点,同时滚动和放大器;滚动后的位置给出错误的值

I tried to display the description of the selected item from position of getView(). The list is very large so it dynamically allocates the view while scrolling & the position gives wrong values after scrolling

我看着谷歌I / O 2010 - ListView的视频和放大器的世界; 它指出这些东西的。

I watched Google I/O 2010 - The world of ListView video & it states these things.

所以,我认为我需要实现 notifyDataSetChanged() onScroll() onScrollStateChanged()的方法。

So I think I need to implement notifyDataSetChanged() or onScroll() , onScrollStateChanged() methods.

但如何?

code:

public class MainActivity1 extends ListActivity implements OnTouchListener{

private MyCustomAdapter mAdapter;
Activity temp = this;
String []s = new String[500];
ArrayList<GS> q = new ArrayList<GS>();
CustomAdapter adapter;
ListView lv;
int c=1;

@Override
public void onCreate(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());
    mAdapter.addItem(q.get(0).getAS_name());
    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());
            c++;
        }
        mAdapter.addItem(q.get(i).getAS_name());

    }

    setListAdapter(mAdapter);        

}
 //Adapter Class
 private class MyCustomAdapter extends BaseAdapter {

    private static final int TYPE_ITEM = 0;
    private static final int TYPE_SEPARATOR = 1;
    private static final int TYPE_MAX_COUNT = TYPE_SEPARATOR + 1;

    private ArrayList<String> mData = new ArrayList<String>();
    private LayoutInflater mInflater;

    private TreeSet<Integer> mSeparatorsSet = new TreeSet<Integer>();

    public MyCustomAdapter() {
        mInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

    public void addItem(final String item) {
        mData.add(item);
        notifyDataSetChanged();
    }

    public void addSeparatorItem(final String item) {
        mData.add(item);
        // save separator position
        mSeparatorsSet.add(mData.size() - 1);
        notifyDataSetChanged();
    }

    @Override
    public int getItemViewType(int position) {
        return mSeparatorsSet.contains(position) ? TYPE_SEPARATOR : TYPE_ITEM;
    }

    @Override
    public int getViewTypeCount() {
        return TYPE_MAX_COUNT;
    }

    public int getCount() {
        return mData.size();
    }

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

    public long getItemId(int position) {
        Log.v("getItemId Position", ""+position);
        return position;

    }

            public View getView(final int position, View convertView, ViewGroup parent) {
        ViewHolder holder = null;
        int type = getItemViewType(position);
     //   System.out.println("getView " + position + " " + convertView + " type = " + type);
        if (convertView == null) {
            holder = new ViewHolder();
            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);
                count++;
                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(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        AlertDialog.Builder x = new AlertDialog.Builder(
                                temp);
                        Log.v("position",""+position);
                               x.setIcon(R.drawable.ic_launcher)
                                .setTitle(q.get(position-count).getAS_name())
                                .setMessage(q.get(position-count).getDesc_art())
                                .setCancelable(true)
                                .setPositiveButton("OK",
                                        new DialogInterface.OnClickListener() {
                                            @Override
                                            public void onClick(DialogInterface arg,
                                                    int arg1) {
                                            }
                                        });
                               AlertDialog a = x.create();
                        a.show();
                    }
                });
           } else {
            holder.textView.setOnClickListener(null);
            count++;
        }   

        return convertView;
    }
}

public static class ViewHolder {
    public TextView textView;
}

  public boolean onTouch(View v, MotionEvent event) {
 // TODO Auto-generated method stub
  return false;
 }
}

所以,我想显示Alertdialog所选项目的说明时 TYPE_ITEM 是每个TYPE_ITEM的clicked.The描述存储在连续的数据库。因此,我需要保持跟踪的位置(指索引)TYPE_ITEM的从数据库中获取数据。我希望能跟现在明白我的问题!

So,I am trying to display the description of the selected item in Alertdialog when TYPE_ITEM is clicked.The description of each TYPE_ITEM is stored in the database sequentially. Hence, I need to keep track the position(means indexing) of TYPE_ITEM for getting data from database. I hope u now understand my problem !

BTW我试图使用计数变量getView()这一点,但在那,如果我们再次向上滚动(在这种情况下,计数应减少)。我希望u现在和放明白的问题;我认为,我们应该实施notifyDataSetChanged或onScroll,onScrollStateChanged方法。

BTW I tried using a count variable in getView() that but in that what if we again scroll up(in that case the count should decrement). i hope u understand the problem now & i think we should implement notifyDataSetChanged or onScroll, onScrollStateChanged methods.

如果这个问题不明确则u可以问我的意见

If the problem is not clear then u can ask me in the comments

请帮助!

推荐答案

所有你需要做的是移动 OnClickListener 的设置上持有人。的TextView

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

这里的问题是:

:既然你在如果(convertView == NULL)块设置OnClickListener,它不会改变      当 convertView不是null 。因此,位置 AlertDialog 用的是你设置一个      当 convertView 的是的空。

: 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 convertView was null.

:解决方法是每一个位置被处理时设置OnClickListener - 我们不关心的话      该视图回收或不!我们需要重新设置OnClickListener反映      正确的/当前的位置。

: 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.

:虽然,我们从来没有在holder.textview设置OnClickListener当产品 TYPE_SEPARATOR ,其      安全地删除使用OnClickListener holder.textview.setOnClickListener(空)

: 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).

尝试下面的更新code。我希望这里的逻辑是很清楚的。

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

//Adapter Class
private class MyCustomAdapter extends BaseAdapter {

    ....
    ....     
    public View getView(final int position, View convertView, ViewGroup parent) {
        ViewHolder holder = null;
        int type = getItemViewType(position);
        System.out.println("getView " + position + " " + convertView + " type = " + type);
        if (convertView == null) {
            holder = new ViewHolder();
            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(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        AlertDialog.Builder x = new AlertDialog.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",
                                        new DialogInterface.OnClickListener() {
                                            @Override
                                            public void onClick(DialogInterface arg,
                                                    int arg1) {

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

        return convertView;
    }

    ....
    ....

}

编辑:

包装类(可实现为一个内部类的 MainActivity1 或独立):

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

public class ContentWrapper {

    private String mItem, mItemDescription;

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

    public String getItem() {
        return mItem;
    }

    public String getItemDescription() {
        return mItemDescription;
    }
}

您的数据设置也将发生变化:

Your data-setup will also change:

@Override
public void onCreate(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>();

添加* 方法

public void addItem(ContentWrapper value) {
    mData.add(value);
    notifyDataSetChanged();
}

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

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

getView(...)方法:

@Override
public View getView(final int position, View convertView, ViewGroup parent) {
    ....
    ....

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

    if (type == TYPE_ITEM) {
        holder.textView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                AlertDialog.Builder x = new AlertDialog.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",
                                new DialogInterface.OnClickListener() {
                                    @Override
                                    public void onClick(DialogInterface arg,
                                            int arg1) {
                                    }
                                });
                 AlertDialog a = x.create();
                 a.show();
             }
         });
    } else {
        holder.textView.setOnClickListener(null);
    }
}

和仅此而已。

[I]认为,我们应该实施notifyDataSetChanged或onScroll,   onScrollStateChanged的方法。

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

notifyDataSetChanged()被用来告诉的基础数据发生改变,因此需要刷新适配器。例如,如果描述一个项目的变化,你会更新 MDATA 该项目,并调用 notifyDataSetChanged()。但是,在你的情况(和你的code告诉我),你的数据,然后再设置使用适配器初始化 - setListAdapter(mAdapter)。因此,调用 notifyDataSetChanged()添加*内部方法,甚至没有要求。呼叫 notifyDataSetChanged()前连接适配器到ListView什么都不做。

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 onScrollChanged 都是为了不同的目的。例如,说你表现出返回首页列表的按钮,当用户滚动过去的第50项 - 和隐藏,当他们向上滚动的第50位。你的情况,问题是,你试图从两个不同的来源(MDATA,Q)的数据,并有与同步问题。仅此而已。

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.